pdf-parser.cpp revision 35636e0c762d50c37515a072b12bdc0197afd24c
842ae4bd224140319ae7feec1872b93dfd491143fielding /*
842ae4bd224140319ae7feec1872b93dfd491143fielding * PDF parsing using libpoppler.
842ae4bd224140319ae7feec1872b93dfd491143fielding *
842ae4bd224140319ae7feec1872b93dfd491143fielding * Derived from poppler's Gfx.cc
842ae4bd224140319ae7feec1872b93dfd491143fielding *
842ae4bd224140319ae7feec1872b93dfd491143fielding * Authors:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Jon A. Cruz <jon@joncruz.org>
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd *
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Copyright 2012 authors
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Copyright 1996-2003 Glyph & Cog, LLC
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd *
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd */
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd#ifdef HAVE_CONFIG_H
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding# include <config.h>
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef HAVE_POPPLER
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef USE_GCC_PRAGMAS
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#pragma implementation
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingextern "C" {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include <stdlib.h>
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include <stdio.h>
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include <stddef.h>
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include <string.h>
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include <math.h>
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include "svg-builder.h"
f7376afc33a9e035921be9114c0e246820d7c8besf#include "Gfx.h"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "pdf-parser.h"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "util/units.h"
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include "goo/gmem.h"
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include "goo/GooTimer.h"
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include "goo/GooHash.h"
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include "GlobalParams.h"
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include "CharTypes.h"
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include "Object.h"
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include "Array.h"
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#include "Dict.h"
e8f95a682820a599fe41b22977010636be5c2717jim#include "Stream.h"
f7376afc33a9e035921be9114c0e246820d7c8besf#include "Lexer.h"
f7376afc33a9e035921be9114c0e246820d7c8besf#include "Parser.h"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "GfxFont.h"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "GfxState.h"
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe#include "OutputDev.h"
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe#include "Page.h"
694e8dc146faadc46b2455f3bd0998121fc76c5drbb#include "Annot.h"
c7d0205ec1649076e7742d72a25ac53779768312stoddard#include "Error.h"
c7d0205ec1649076e7742d72a25ac53779768312stoddard
29c30db45f6a469017e16b606611e460cc1a1f2caaron// the MSVC math.h doesn't define this
032b8a34c3911bbc5ad5385ca40af65af273bff9wrowe#ifndef M_PI
e33b627b40578d0166fdb79ce0487f9e46586befgstein#define M_PI 3.14159265358979323846
cd9f429ff62d134cdf6ec903c33430c5ebae12f0trawick#endif
cd9f429ff62d134cdf6ec903c33430c5ebae12f0trawick
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding//------------------------------------------------------------------------
e33b627b40578d0166fdb79ce0487f9e46586befgstein// constants
e33b627b40578d0166fdb79ce0487f9e46586befgstein//------------------------------------------------------------------------
e33b627b40578d0166fdb79ce0487f9e46586befgstein
e33b627b40578d0166fdb79ce0487f9e46586befgstein// Default max delta allowed in any color component for a shading fill.
e33b627b40578d0166fdb79ce0487f9e46586befgstein#define defaultShadingColorDelta (dblToCol( 1 / 2.0 ))
e33b627b40578d0166fdb79ce0487f9e46586befgstein
e33b627b40578d0166fdb79ce0487f9e46586befgstein// Default max recursive depth for a shading fill.
864c5615d55b8ebbde24e72043f6325741335a74fielding#define defaultShadingMaxDepth 6
e33b627b40578d0166fdb79ce0487f9e46586befgstein
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick// Max number of operators kept in the history list.
26dfa083a1662d57ba7cc410eec4e0696b9be469wrowe#define maxOperatorHistoryDepth 16
26dfa083a1662d57ba7cc410eec4e0696b9be469wrowe
e9f8410b788ef1e6f1baed6c706ffdf3da395a16jerenkrantz//------------------------------------------------------------------------
e33b627b40578d0166fdb79ce0487f9e46586befgstein// Operator table
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz//------------------------------------------------------------------------
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz
97d20d37d21b8d427a920e211858172f0a82427epoirier#ifdef WIN32 // this works around a bug in the VC7 compiler
97d20d37d21b8d427a920e211858172f0a82427epoirier# pragma optimize("",off)
97d20d37d21b8d427a920e211858172f0a82427epoirier#endif
8ec8f1c8f0f37ca3f5ebb0e0b491dd07481dccbfronald
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingPdfOperator PdfParser::opTab[] = {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"\"", 3, {tchkNum, tchkNum, tchkString},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opMoveSetShowText},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"'", 1, {tchkString},
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz &PdfParser::opMoveShowText},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"B", 0, {tchkNone},
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf &PdfParser::opFillStroke},
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe {"B*", 0, {tchkNone},
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm &PdfParser::opEOFillStroke},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"BDC", 2, {tchkName, tchkProps},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opBeginMarkedContent},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"BI", 0, {tchkNone},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opBeginImage},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"BMC", 1, {tchkName},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opBeginMarkedContent},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"BT", 0, {tchkNone},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron &PdfParser::opBeginText},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"BX", 0, {tchkNone},
e0fe4de2016336428729a620ac0034cd1198ad7awrowe &PdfParser::opBeginIgnoreUndef},
e0fe4de2016336428729a620ac0034cd1198ad7awrowe {"CS", 1, {tchkName},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetStrokeColorSpace},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"DP", 2, {tchkName, tchkProps},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron &PdfParser::opMarkPoint},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron {"Do", 1, {tchkName},
ec486beb201583aafddf7c7ee9009727a3ade0aafielding &PdfParser::opXObject},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"EI", 0, {tchkNone},
c7de1955eb0eaeabf7042902476397692672d549sf &PdfParser::opEndImage},
8ea968d7e798635ab742673e5d5eef35798259c9sf {"EMC", 0, {tchkNone},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opEndMarkedContent},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"ET", 0, {tchkNone},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opEndText},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"EX", 0, {tchkNone},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opEndIgnoreUndef},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron {"F", 0, {tchkNone},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron &PdfParser::opFill},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron {"G", 1, {tchkNum},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron &PdfParser::opSetStrokeGray},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"ID", 0, {tchkNone},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opImageData},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"J", 1, {tchkInt},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald &PdfParser::opSetLineCap},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetStrokeCMYKColor},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"M", 1, {tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetMiterLimit},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"MP", 1, {tchkName},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opMarkPoint},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"Q", 0, {tchkNone},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opRestore},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"RG", 3, {tchkNum, tchkNum, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetStrokeRGBColor},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"S", 0, {tchkNone},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opStroke},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetStrokeColor},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"SCN", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkSCN, tchkSCN, tchkSCN, tchkSCN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkSCN, tchkSCN, tchkSCN, tchkSCN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkSCN, tchkSCN, tchkSCN, tchkSCN,
7ddfd45e4d3d13de264931df8eb27ee7619fdb0ejerenkrantz tchkSCN, tchkSCN, tchkSCN, tchkSCN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkSCN, tchkSCN, tchkSCN, tchkSCN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkSCN, tchkSCN, tchkSCN, tchkSCN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkSCN, tchkSCN, tchkSCN, tchkSCN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkSCN},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetStrokeColorN},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"T*", 0, {tchkNone},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opTextNextLine},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"TD", 2, {tchkNum, tchkNum},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald &PdfParser::opTextMoveSet},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron {"TJ", 1, {tchkArray},
78b8e4dd910f03af0a602bc4b63ad7bc69868ee3sf &PdfParser::opShowSpaceText},
78b8e4dd910f03af0a602bc4b63ad7bc69868ee3sf {"TL", 1, {tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetTextLeading},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"Tc", 1, {tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetCharSpacing},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"Td", 2, {tchkNum, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opTextMove},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"Tf", 2, {tchkName, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetFont},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"Tj", 1, {tchkString},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron &PdfParser::opShowText},
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkNum, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetTextMatrix},
c7de1955eb0eaeabf7042902476397692672d549sf {"Tr", 1, {tchkInt},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetTextRender},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald {"Ts", 1, {tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetTextRise},
26dfa083a1662d57ba7cc410eec4e0696b9be469wrowe {"Tw", 1, {tchkNum},
26dfa083a1662d57ba7cc410eec4e0696b9be469wrowe &PdfParser::opSetWordSpacing},
26dfa083a1662d57ba7cc410eec4e0696b9be469wrowe {"Tz", 1, {tchkNum},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron &PdfParser::opSetHorizScaling},
29c30db45f6a469017e16b606611e460cc1a1f2caaron {"W", 0, {tchkNone},
29c30db45f6a469017e16b606611e460cc1a1f2caaron &PdfParser::opClip},
43997561b2302d13dee973998e77743a3ddd2374trawick {"W*", 0, {tchkNone},
43997561b2302d13dee973998e77743a3ddd2374trawick &PdfParser::opEOClip},
97d20d37d21b8d427a920e211858172f0a82427epoirier {"b", 0, {tchkNone},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald &PdfParser::opCloseFillStroke},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron {"b*", 0, {tchkNone},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron &PdfParser::opCloseEOFillStroke},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkNum, tchkNum},
4c25fdfa5f370d29e55aea846eb9fe6c1d51ede3wrowe &PdfParser::opCurveTo},
4c25fdfa5f370d29e55aea846eb9fe6c1d51ede3wrowe {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkNum, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opConcat},
138c8f7cb8254e035c6f45288e3909cd9c21be5cmartin {"cs", 1, {tchkName},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetFillColorSpace},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"d", 2, {tchkArray, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetDash},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"d0", 2, {tchkNum, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetCharWidth},
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkNum, tchkNum},
185aa71728867671e105178b4c66fbc22b65ae26sf &PdfParser::opSetCacheDevice},
678a15e91d6a44569c956445442731bb64a98a63sf {"f", 0, {tchkNone},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opFill},
97d20d37d21b8d427a920e211858172f0a82427epoirier {"f*", 0, {tchkNone},
97d20d37d21b8d427a920e211858172f0a82427epoirier &PdfParser::opEOFill},
97d20d37d21b8d427a920e211858172f0a82427epoirier {"g", 1, {tchkNum},
97d20d37d21b8d427a920e211858172f0a82427epoirier &PdfParser::opSetFillGray},
97d20d37d21b8d427a920e211858172f0a82427epoirier {"gs", 1, {tchkName},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald &PdfParser::opSetExtGState},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron {"h", 0, {tchkNone},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron &PdfParser::opClosePath},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"i", 1, {tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetFlat},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald {"j", 1, {tchkInt},
29c30db45f6a469017e16b606611e460cc1a1f2caaron &PdfParser::opSetLineJoin},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetFillCMYKColor},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"l", 2, {tchkNum, tchkNum},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald &PdfParser::opLineTo},
29c30db45f6a469017e16b606611e460cc1a1f2caaron {"m", 2, {tchkNum, tchkNum},
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron &PdfParser::opMoveTo},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"n", 0, {tchkNone},
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald &PdfParser::opEndPath},
92108a6c4fd7ca6e9acc94d2485920436763e491sf {"q", 0, {tchkNone},
92108a6c4fd7ca6e9acc94d2485920436763e491sf &PdfParser::opSave},
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opRectangle},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"rg", 3, {tchkNum, tchkNum, tchkNum},
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm &PdfParser::opSetFillRGBColor},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald {"ri", 1, {tchkName},
185aa71728867671e105178b4c66fbc22b65ae26sf &PdfParser::opSetRenderingIntent},
58c74a790988c0c63b08d15f9af6908b36f3efd8jailletc {"s", 0, {tchkNone},
f7376afc33a9e035921be9114c0e246820d7c8besf &PdfParser::opCloseStroke},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald &PdfParser::opSetFillColor},
dc80439e9fba60c753cd145cb6799409ffea9b71ronald {"scn", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
dc80439e9fba60c753cd145cb6799409ffea9b71ronald tchkSCN, tchkSCN, tchkSCN, tchkSCN,
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein tchkSCN, tchkSCN, tchkSCN, tchkSCN,
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein tchkSCN, tchkSCN, tchkSCN, tchkSCN,
97d20d37d21b8d427a920e211858172f0a82427epoirier tchkSCN, tchkSCN, tchkSCN, tchkSCN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkSCN, tchkSCN, tchkSCN, tchkSCN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkSCN, tchkSCN, tchkSCN, tchkSCN,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm tchkSCN, tchkSCN, tchkSCN, tchkSCN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tchkSCN},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &PdfParser::opSetFillColorN},
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {"sh", 1, {tchkName},
97d20d37d21b8d427a920e211858172f0a82427epoirier &PdfParser::opShFill},
97d20d37d21b8d427a920e211858172f0a82427epoirier {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim &PdfParser::opCurveTo1},
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim {"w", 1, {tchkNum},
97d20d37d21b8d427a920e211858172f0a82427epoirier &PdfParser::opSetLineWidth},
97d20d37d21b8d427a920e211858172f0a82427epoirier {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
1124a56faf0228410656abbe08451d7330d906e8trawick &PdfParser::opCurveTo2}
1124a56faf0228410656abbe08451d7330d906e8trawick};
97d20d37d21b8d427a920e211858172f0a82427epoirier
97d20d37d21b8d427a920e211858172f0a82427epoirier#ifdef WIN32 // this works around a bug in the VC7 compiler
97d20d37d21b8d427a920e211858172f0a82427epoirier# pragma optimize("",on)
97d20d37d21b8d427a920e211858172f0a82427epoirier#endif
97d20d37d21b8d427a920e211858172f0a82427epoirier
185aa71728867671e105178b4c66fbc22b65ae26sf#define numOps (sizeof(opTab) / sizeof(PdfOperator))
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim
97d20d37d21b8d427a920e211858172f0a82427epoirier//------------------------------------------------------------------------
97d20d37d21b8d427a920e211858172f0a82427epoirier// PdfParser
97d20d37d21b8d427a920e211858172f0a82427epoirier//------------------------------------------------------------------------
97d20d37d21b8d427a920e211858172f0a82427epoirier
97d20d37d21b8d427a920e211858172f0a82427epoirierPdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA,
97d20d37d21b8d427a920e211858172f0a82427epoirier int /*pageNum*/, int rotate, Dict *resDict,
97d20d37d21b8d427a920e211858172f0a82427epoirier PDFRectangle *box, PDFRectangle *cropBox)
97d20d37d21b8d427a920e211858172f0a82427epoirier{
97d20d37d21b8d427a920e211858172f0a82427epoirier xref = xrefA;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald subPage = gFalse;
97d20d37d21b8d427a920e211858172f0a82427epoirier printCommands = false;
97d20d37d21b8d427a920e211858172f0a82427epoirier
dc80439e9fba60c753cd145cb6799409ffea9b71ronald // start the resource stack
dc80439e9fba60c753cd145cb6799409ffea9b71ronald res = new GfxResources(xref, resDict, NULL);
97d20d37d21b8d427a920e211858172f0a82427epoirier
97d20d37d21b8d427a920e211858172f0a82427epoirier // initialize
dc80439e9fba60c753cd145cb6799409ffea9b71ronald state = new GfxState(72.0, 72.0, box, rotate, gTrue);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron clipHistory = new ClipHistoryEntry();
97d20d37d21b8d427a920e211858172f0a82427epoirier setDefaultApproximationPrecision();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding fontChanged = gFalse;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding clip = clipNone;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron ignoreUndef = 0;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron operatorHistory = NULL;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder = builderA;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald builder->setDocumentSize(Inkscape::Util::Quantity::convert(state->getPageWidth(), "pt", "px"),
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding Inkscape::Util::Quantity::convert(state->getPageHeight(), "pt", "px"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
024e70e05386a6367eb45d0d1cc406764520ff4cwrowe double *ctm = state->getCTM();
024e70e05386a6367eb45d0d1cc406764520ff4cwrowe double scaledCTM[6];
dc80439e9fba60c753cd145cb6799409ffea9b71ronald for (int i = 0; i < 6; ++i) {
29c30db45f6a469017e16b606611e460cc1a1f2caaron baseMatrix[i] = ctm[i];
97d20d37d21b8d427a920e211858172f0a82427epoirier scaledCTM[i] = Inkscape::Util::Quantity::convert(ctm[i], "pt", "px");
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald saveState();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->setTransform((double*)&scaledCTM);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding formDepth = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
97d20d37d21b8d427a920e211858172f0a82427epoirier // set crop box
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (cropBox) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (printCommands)
97d20d37d21b8d427a920e211858172f0a82427epoirier printf("cropBox: %f %f %f %f\n", cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // do not clip if it's not needed
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (cropBox->x1 != 0.0 || cropBox->y1 != 0.0 ||
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding cropBox->x2 != state->getPageWidth() || cropBox->y2 != state->getPageHeight()) {
024e70e05386a6367eb45d0d1cc406764520ff4cwrowe
024e70e05386a6367eb45d0d1cc406764520ff4cwrowe state->moveTo(cropBox->x1, cropBox->y1);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald state->lineTo(cropBox->x2, cropBox->y1);
29c30db45f6a469017e16b606611e460cc1a1f2caaron state->lineTo(cropBox->x2, cropBox->y2);
97d20d37d21b8d427a920e211858172f0a82427epoirier state->lineTo(cropBox->x1, cropBox->y2);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald state->closePath();
dc80439e9fba60c753cd145cb6799409ffea9b71ronald state->clip();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding clipHistory->setClip(state->getPath(), clipNormal);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->setClipPath(state);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->clearPath();
97d20d37d21b8d427a920e211858172f0a82427epoirier }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron pushOperator("startPage");
97d20d37d21b8d427a920e211858172f0a82427epoirier}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingPdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron Dict *resDict, PDFRectangle *box) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int i;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding parser = NULL;
97d20d37d21b8d427a920e211858172f0a82427epoirier
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding xref = xrefA;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding subPage = gTrue;
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein printCommands = false;
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick // start the resource stack
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick res = new GfxResources(xref, resDict, NULL);
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick
8ea968d7e798635ab742673e5d5eef35798259c9sf // initialize
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick operatorHistory = NULL;
43997561b2302d13dee973998e77743a3ddd2374trawick builder = builderA;
f7376afc33a9e035921be9114c0e246820d7c8besf state = new GfxState(72, 72, box, 0, gFalse);
f7376afc33a9e035921be9114c0e246820d7c8besf clipHistory = new ClipHistoryEntry();
f7376afc33a9e035921be9114c0e246820d7c8besf setDefaultApproximationPrecision();
f7376afc33a9e035921be9114c0e246820d7c8besf
f7376afc33a9e035921be9114c0e246820d7c8besf fontChanged = gFalse;
8ea968d7e798635ab742673e5d5eef35798259c9sf clip = clipNone;
8ea968d7e798635ab742673e5d5eef35798259c9sf ignoreUndef = 0;
8ea968d7e798635ab742673e5d5eef35798259c9sf for (i = 0; i < 6; ++i) {
8ea968d7e798635ab742673e5d5eef35798259c9sf baseMatrix[i] = state->getCTM()[i];
8ea968d7e798635ab742673e5d5eef35798259c9sf }
8ea968d7e798635ab742673e5d5eef35798259c9sf formDepth = 0;
8ea968d7e798635ab742673e5d5eef35798259c9sf}
8ea968d7e798635ab742673e5d5eef35798259c9sf
8ea968d7e798635ab742673e5d5eef35798259c9sfPdfParser::~PdfParser() {
8ea968d7e798635ab742673e5d5eef35798259c9sf while (state->hasSaves()) {
8ea968d7e798635ab742673e5d5eef35798259c9sf restoreState();
8ea968d7e798635ab742673e5d5eef35798259c9sf }
8ea968d7e798635ab742673e5d5eef35798259c9sf if (!subPage) {
8ea968d7e798635ab742673e5d5eef35798259c9sf //out->endPage();
8ea968d7e798635ab742673e5d5eef35798259c9sf }
8ea968d7e798635ab742673e5d5eef35798259c9sf while (res) {
8ea968d7e798635ab742673e5d5eef35798259c9sf popResources();
8ea968d7e798635ab742673e5d5eef35798259c9sf }
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick if (state) {
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick delete state;
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein }
9d0665da83d1e22c0ea0e5f6f940f70f75bf5237ianh if (clipHistory) {
e1753aabf5df187b5b04e72a958af4b65b1a125daaron delete clipHistory;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
e1753aabf5df187b5b04e72a958af4b65b1a125daaron}
e1753aabf5df187b5b04e72a958af4b65b1a125daaron
e1753aabf5df187b5b04e72a958af4b65b1a125daaronvoid PdfParser::parse(Object *obj, GBool topLevel) {
59d316b83d42d2a07e25c20d8c35a07b369618bdsf Object obj2;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
59d316b83d42d2a07e25c20d8c35a07b369618bdsf if (obj->isArray()) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald for (int i = 0; i < obj->arrayGetLength(); ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj->arrayGet(i, &obj2);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!obj2.isStream()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errInternal, -1, "Weird page contents");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm error(-1, const_cast<char*>("Weird page contents"));
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj2.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
97d20d37d21b8d427a920e211858172f0a82427epoirier obj2.free();
97d20d37d21b8d427a920e211858172f0a82427epoirier }
97d20d37d21b8d427a920e211858172f0a82427epoirier } else if (!obj->isStream()) {
97d20d37d21b8d427a920e211858172f0a82427epoirier#ifdef POPPLER_NEW_ERRORAPI
066877f1a045103acfdd376d48cdd473c33f409bdougm error(errInternal, -1, "Weird page contents");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
9d0665da83d1e22c0ea0e5f6f940f70f75bf5237ianh error(-1, const_cast<char*>("Weird page contents"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald parser = new Parser(xref, new Lexer(xref, obj), gFalse);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm go(topLevel);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald delete parser;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron parser = NULL;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
dc80439e9fba60c753cd145cb6799409ffea9b71ronaldvoid PdfParser::go(GBool /*topLevel*/)
97d20d37d21b8d427a920e211858172f0a82427epoirier{
97d20d37d21b8d427a920e211858172f0a82427epoirier Object obj;
97d20d37d21b8d427a920e211858172f0a82427epoirier Object args[maxArgs];
97d20d37d21b8d427a920e211858172f0a82427epoirier
97d20d37d21b8d427a920e211858172f0a82427epoirier // scan a sequence of objects
97d20d37d21b8d427a920e211858172f0a82427epoirier int numArgs = 0;
97d20d37d21b8d427a920e211858172f0a82427epoirier parser->getObj(&obj);
97d20d37d21b8d427a920e211858172f0a82427epoirier while (!obj.isEOF()) {
97d20d37d21b8d427a920e211858172f0a82427epoirier
97d20d37d21b8d427a920e211858172f0a82427epoirier // got a command - execute it
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick if (obj.isCmd()) {
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick if (printCommands) {
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick obj.print(stdout);
29c30db45f6a469017e16b606611e460cc1a1f2caaron for (int i = 0; i < numArgs; ++i) {
29c30db45f6a469017e16b606611e460cc1a1f2caaron printf(" ");
29c30db45f6a469017e16b606611e460cc1a1f2caaron args[i].print(stdout);
29c30db45f6a469017e16b606611e460cc1a1f2caaron }
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick printf("\n");
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick fflush(stdout);
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick }
29c30db45f6a469017e16b606611e460cc1a1f2caaron
29c30db45f6a469017e16b606611e460cc1a1f2caaron // Run the operation
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron execOp(&obj, args, numArgs);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
dc80439e9fba60c753cd145cb6799409ffea9b71ronald obj.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (int i = 0; i < numArgs; ++i)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding args[i].free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding numArgs = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // got an argument - save it
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm } else if (numArgs < maxArgs) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding args[numArgs++] = obj;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // too many arguments - something is wrong
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "Too many args in content stream");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm error(getPos(), const_cast<char*>("Too many args in content stream"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf if (printCommands) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron printf("throwing away arg: ");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj.print(stdout);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron printf("\n");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding fflush(stdout);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // grab the next object
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding parser->getObj(&obj);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
19f9bc5e12b4e6178eb4709779c28af45012c205rjung obj.free();
c7de1955eb0eaeabf7042902476397692672d549sf
c7de1955eb0eaeabf7042902476397692672d549sf // args at end with no command
c7de1955eb0eaeabf7042902476397692672d549sf if (numArgs > 0) {
c7de1955eb0eaeabf7042902476397692672d549sf#ifdef POPPLER_NEW_ERRORAPI
c7de1955eb0eaeabf7042902476397692672d549sf error(errSyntaxError, getPos(), "Leftover args in content stream");
c7de1955eb0eaeabf7042902476397692672d549sf#else
c7de1955eb0eaeabf7042902476397692672d549sf error(getPos(), const_cast<char*>("Leftover args in content stream"));
c7de1955eb0eaeabf7042902476397692672d549sf#endif
c7de1955eb0eaeabf7042902476397692672d549sf if (printCommands) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding printf("%d leftovers:", numArgs);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (int i = 0; i < numArgs; ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding printf(" ");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding args[i].print(stdout);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding printf("\n");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding fflush(stdout);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (int i = 0; i < numArgs; ++i)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding args[i].free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
066877f1a045103acfdd376d48cdd473c33f409bdougm
c7de1955eb0eaeabf7042902476397692672d549sfvoid PdfParser::pushOperator(const char *name) {
066877f1a045103acfdd376d48cdd473c33f409bdougm OpHistoryEntry *newEntry = new OpHistoryEntry;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron newEntry->name = name;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding newEntry->state = NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding newEntry->depth = (operatorHistory != NULL ? (operatorHistory->depth+1) : 0);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding newEntry->next = operatorHistory;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding operatorHistory = newEntry;
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz // Truncate list if needed
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (operatorHistory->depth > maxOperatorHistoryDepth) {
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz OpHistoryEntry *curr = operatorHistory;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz OpHistoryEntry *prev = NULL;
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz while (curr && curr->next != NULL) {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz curr->depth--;
05a5d2147e0dadae69d00691f814049dc9999efdsf prev = curr;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz curr = curr->next;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz }
e9f8410b788ef1e6f1baed6c706ffdf3da395a16jerenkrantz if (prev) {
2e242dca7111f99d54dd144b7b8418d88d560032chrisd if (curr->state != NULL)
2e242dca7111f99d54dd144b7b8418d88d560032chrisd delete curr->state;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz delete curr;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz prev->next = NULL;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz}
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz
bdfba727693ab86e9914ca90af68e62896946755jerenkrantzconst char *PdfParser::getPreviousOperator(unsigned int look_back) {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz OpHistoryEntry *prev = NULL;
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz if (operatorHistory != NULL && look_back > 0) {
75031befec2825183c13931fc3266b56ed575c3dcovener prev = operatorHistory->next;
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez while (--look_back > 0 && prev != NULL) {
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez prev = prev->next;
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez }
941fcca87a4607a388e88cff3fd0cdefc29bb81cjerenkrantz }
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez if (prev != NULL) {
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez return prev->name;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz } else {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz return "";
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz}
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz
bdfba727693ab86e9914ca90af68e62896946755jerenkrantzvoid PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz PdfOperator *op;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz char *name;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz Object *argPtr;
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz int i;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz // find operator
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz name = cmd->getCmd();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!(op = findOp(name))) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (ignoreUndef == 0)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "Unknown operator '{0:s}'", name);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("Unknown operator '%s'"), name);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf }
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // type check args
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron argPtr = args;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (op->numArgs >= 0) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (numArgs < op->numArgs) {
44a02fb58380bb801585f586ad3c7569de11840dpoirier#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "Too few ({0:d}) args to '{1:d}' operator", numArgs, name);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("Too few (%d) args to '%s' operator"), numArgs, name);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return;
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (numArgs > op->numArgs) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#if 0
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator", numArgs, name);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding argPtr += numArgs - op->numArgs;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald numArgs = op->numArgs;
e8f95a682820a599fe41b22977010636be5c2717jim }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (numArgs > -op->numArgs) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator",
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("Too many (%d) args to '%s' operator"),
e0fe4de2016336428729a620ac0034cd1198ad7awrowe#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding numArgs, name);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron for (i = 0; i < numArgs; ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!checkArg(&argPtr[i], op->tchk[i])) {
f7376afc33a9e035921be9114c0e246820d7c8besf#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "Arg #{0:d} to '{1:s}' operator is wrong type ({2:s})",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("Arg #%d to '%s' operator is wrong type (%s)"),
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier i, name, argPtr[i].getTypeName());
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier return;
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier
ac2eb54bac2d978c323ab346161b8591d134100cpoirier // add to history
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier pushOperator((char*)&op->name);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // do it
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (this->*op->func)(argPtr, numArgs);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingPdfOperator* PdfParser::findOp(char *name) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int a = -1;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald int b = numOps;
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier int cmp = -1;
f7376afc33a9e035921be9114c0e246820d7c8besf // invariant: opTab[a] < name < opTab[b]
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron while (b - a > 1) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron const int m = (a + b) / 2;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron cmp = strcmp(opTab[m].name, name);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (cmp < 0)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a = m;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if (cmp > 0)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding b = m;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a = b = m;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (cmp != 0)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return &opTab[a];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronGBool PdfParser::checkArg(Object *arg, TchkType type) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron switch (type) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron case tchkBool: return arg->isBool();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case tchkInt: return arg->isInt();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case tchkNum: return arg->isNum();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case tchkString: return arg->isString();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case tchkName: return arg->isName();
dc80439e9fba60c753cd145cb6799409ffea9b71ronald case tchkArray: return arg->isArray();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron case tchkProps: return arg->isDict() || arg->isName();
dc80439e9fba60c753cd145cb6799409ffea9b71ronald case tchkSCN: return arg->isNum() || arg->isName();
dc80439e9fba60c753cd145cb6799409ffea9b71ronald case tchkNone: return gFalse;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald return gFalse;
e8f95a682820a599fe41b22977010636be5c2717jim}
10a4cdd68ef1ca0e54af296fe1d08ac00150c90bwrowe
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronint PdfParser::getPos() {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return parser ? parser->getPos() : -1;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron//------------------------------------------------------------------------
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron// graphics state operators
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron//------------------------------------------------------------------------
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::opSave(Object /*args*/[], int /*numArgs*/)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron saveState();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
dc80439e9fba60c753cd145cb6799409ffea9b71ronaldvoid PdfParser::opRestore(Object /*args*/[], int /*numArgs*/)
dc80439e9fba60c753cd145cb6799409ffea9b71ronald{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron restoreState();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron// TODO not good that numArgs is ignored but args[] is used:
dc80439e9fba60c753cd145cb6799409ffea9b71ronaldvoid PdfParser::opConcat(Object args[], int /*numArgs*/)
dc80439e9fba60c753cd145cb6799409ffea9b71ronald{
dc80439e9fba60c753cd145cb6799409ffea9b71ronald state->concatCTM(args[0].getNum(), args[1].getNum(),
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron args[2].getNum(), args[3].getNum(),
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron args[4].getNum(), args[5].getNum());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron const char *prevOp = getPreviousOperator();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double a0 = args[0].getNum();
185aa71728867671e105178b4c66fbc22b65ae26sf double a1 = args[1].getNum();
678a15e91d6a44569c956445442731bb64a98a63sf double a2 = args[2].getNum();
6217bba0eab68d7d4c407ed3aedc76e1cc2bbb9atrawick double a3 = args[3].getNum();
dc80439e9fba60c753cd145cb6799409ffea9b71ronald double a4 = args[4].getNum();
dc80439e9fba60c753cd145cb6799409ffea9b71ronald double a5 = args[5].getNum();
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (!strcmp(prevOp, "q")) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald builder->setTransform(a0, a1, a2, a3, a4, a5);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else if (!strcmp(prevOp, "cm") || !strcmp(prevOp, "startPage")) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // multiply it with the previous transform
e8f95a682820a599fe41b22977010636be5c2717jim double otherMatrix[6];
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb if (!builder->getTransform(otherMatrix)) { // invalid transform
1df208eeb79b689410598b0f6fd1ac3fb2401c44nd // construct identity matrix
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz otherMatrix[0] = otherMatrix[3] = 1.0;
e8f95a682820a599fe41b22977010636be5c2717jim otherMatrix[1] = otherMatrix[2] = otherMatrix[4] = otherMatrix[5] = 0.0;
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb }
e8f95a682820a599fe41b22977010636be5c2717jim double c0 = a0*otherMatrix[0] + a1*otherMatrix[2];
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb double c1 = a0*otherMatrix[1] + a1*otherMatrix[3];
e8f95a682820a599fe41b22977010636be5c2717jim double c2 = a2*otherMatrix[0] + a3*otherMatrix[2];
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb double c3 = a2*otherMatrix[1] + a3*otherMatrix[3];
e8f95a682820a599fe41b22977010636be5c2717jim double c4 = a4*otherMatrix[0] + a5*otherMatrix[2] + otherMatrix[4];
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb double c5 = a4*otherMatrix[1] + a5*otherMatrix[3] + otherMatrix[5];
e8f95a682820a599fe41b22977010636be5c2717jim builder->setTransform(c0, c1, c2, c3, c4, c5);
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb } else {
e8f95a682820a599fe41b22977010636be5c2717jim builder->pushGroup();
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb builder->setTransform(a0, a1, a2, a3, a4, a5);
e8f95a682820a599fe41b22977010636be5c2717jim }
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb fontChanged = gTrue;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetDash(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding double *dash = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
b6832863054a2d09233ce92945e0faceb932a620jwoolley Array *a = args[0].getArray();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int length = a->getLength();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (length != 0) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding dash = (double *)gmallocn(length, sizeof(double));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (int i = 0; i < length; ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding Object obj;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding dash[i] = a->get(i, &obj)->getNum();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setLineDash(dash, length, args[1].getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->updateStyle(state);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetFlat(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFlatness((int)args[0].getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetLineJoin(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setLineJoin(args[0].getInt());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->updateStyle(state);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetLineCap(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setLineCap(args[0].getInt());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->updateStyle(state);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetMiterLimit(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setMiterLimit(args[0].getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->updateStyle(state);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
b29f87f4b6c6886a04dccc296177a7033f70dfedtrawickvoid PdfParser::opSetLineWidth(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (args[0].getNum() > 0.0)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setLineWidth(args[0].getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setLineWidth(1.0); // default
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->updateStyle(state);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding Object obj1, obj2, obj3, obj4, obj5;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding Function *funcs[4] = {0, 0, 0, 0};
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GfxColor backdropColor;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GBool haveBackdropColor = gFalse;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GBool alpha = gFalse;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!res->lookupGState(args[0].getName(), &obj1)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!obj1.isDict()) {
29c30db45f6a469017e16b606611e460cc1a1f2caaron#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "ExtGState '{0:s}' is wrong type"), args[0].getName();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("ExtGState '%s' is wrong type"), args[0].getName());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj1.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (printCommands) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron printf(" gfx state dict: ");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj1.print();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding printf("\n");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
29c30db45f6a469017e16b606611e460cc1a1f2caaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // transparency support: blend mode, fill/stroke opacity
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!obj1.dictLookup(const_cast<char*>("BM"), &obj2)->isNull()) {
185aa71728867671e105178b4c66fbc22b65ae26sf GfxBlendMode mode = gfxBlendNormal;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (state->parseBlendMode(&obj2, &mode)) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setBlendMode(mode);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
185aa71728867671e105178b4c66fbc22b65ae26sf#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("Invalid blend mode in ExtGState"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj2.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj1.dictLookup(const_cast<char*>("ca"), &obj2)->isNum()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillOpacity(obj2.getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj2.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj1.dictLookup(const_cast<char*>("CA"), &obj2)->isNum()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setStrokeOpacity(obj2.getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj2.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // fill/stroke overprint
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GBool haveFillOP = gFalse;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if ((haveFillOP = (obj1.dictLookup(const_cast<char*>("op"), &obj2)->isBool()))) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setFillOverprint(obj2.getBool());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj2.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (obj1.dictLookup(const_cast<char*>("OP"), &obj2)->isBool()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setStrokeOverprint(obj2.getBool());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!haveFillOP) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setFillOverprint(obj2.getBool());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj2.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // stroke adjust
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (obj1.dictLookup(const_cast<char*>("SA"), &obj2)->isBool()) {
97d20d37d21b8d427a920e211858172f0a82427epoirier state->setStrokeAdjust(obj2.getBool());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj2.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // transfer function
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj1.dictLookup(const_cast<char*>("TR2"), &obj2)->isNull()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj2.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj1.dictLookup(const_cast<char*>("TR"), &obj2);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj2.isName(const_cast<char*>("Default")) ||
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj2.isName(const_cast<char*>("Identity"))) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding funcs[0] = funcs[1] = funcs[2] = funcs[3] = NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setTransfer(funcs);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else if (obj2.isArray() && obj2.arrayGetLength() == 4) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int pos = 4;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (int i = 0; i < 4; ++i) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald obj2.arrayGet(i, &obj3);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding funcs[i] = Function::parse(&obj3);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald obj3.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!funcs[i]) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding pos = i;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding break;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (pos == 4) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setTransfer(funcs);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else if (obj2.isName() || obj2.isDict() || obj2.isStream()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((funcs[0] = Function::parse(&obj2))) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding funcs[1] = funcs[2] = funcs[3] = NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setTransfer(funcs);
29c30db45f6a469017e16b606611e460cc1a1f2caaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else if (!obj2.isNull()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "Invalid transfer function in ExtGState");
97d20d37d21b8d427a920e211858172f0a82427epoirier#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("Invalid transfer function in ExtGState"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
185aa71728867671e105178b4c66fbc22b65ae26sf }
678a15e91d6a44569c956445442731bb64a98a63sf obj2.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // soft mask
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!obj1.dictLookup(const_cast<char*>("SMask"), &obj2)->isNull()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (obj2.isName(const_cast<char*>("None"))) {
97d20d37d21b8d427a920e211858172f0a82427epoirier builder->clearSoftMask(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else if (obj2.isDict()) {
185aa71728867671e105178b4c66fbc22b65ae26sf if (obj2.dictLookup(const_cast<char*>("S"), &obj3)->isName(const_cast<char*>("Alpha"))) {
97d20d37d21b8d427a920e211858172f0a82427epoirier alpha = gTrue;
97d20d37d21b8d427a920e211858172f0a82427epoirier } else { // "Luminosity"
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron alpha = gFalse;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj3.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding funcs[0] = NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!obj2.dictLookup(const_cast<char*>("TR"), &obj3)->isNull()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding funcs[0] = Function::parse(&obj3);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (funcs[0]->getInputSize() != 1 ||
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding funcs[0]->getOutputSize() != 1) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "Invalid transfer function in soft mask in ExtGState");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("Invalid transfer function in soft mask in ExtGState"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
29c30db45f6a469017e16b606611e460cc1a1f2caaron delete funcs[0];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding funcs[0] = NULL;
185aa71728867671e105178b4c66fbc22b65ae26sf }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj3.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((haveBackdropColor = obj2.dictLookup(const_cast<char*>("BC"), &obj3)->isArray())) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (int i = 0; i < gfxColorMaxComps; ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding backdropColor.c[i] = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (int i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj3.arrayGet(i, &obj4);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj4.isNum()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding backdropColor.c[i] = dblToCol(obj4.getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj4.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
58fd79b56eb624bf011772994e9761d3c2e228c1orlikowski obj3.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj2.dictLookup(const_cast<char*>("G"), &obj3)->isStream()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj3.streamGetDict()->lookup(const_cast<char*>("Group"), &obj4)->isDict()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GfxColorSpace *blendingColorSpace = 0;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm GBool isolated = gFalse;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GBool knockout = gFalse;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!obj4.dictLookup(const_cast<char*>("CS"), &obj5)->isNull()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding blendingColorSpace = GfxColorSpace::parse(&obj5, NULL);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron blendingColorSpace = GfxColorSpace::parse(&obj5);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj5.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj4.dictLookup(const_cast<char*>("I"), &obj5)->isBool()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron isolated = obj5.getBool();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj5.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj4.dictLookup(const_cast<char*>("K"), &obj5)->isBool()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding knockout = obj5.getBool();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm obj5.free();
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if (!haveBackdropColor) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (blendingColorSpace) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding blendingColorSpace->getDefaultColor(&backdropColor);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron //~ need to get the parent or default color space (?)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron for (int i = 0; i < gfxColorMaxComps; ++i) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron backdropColor.c[i] = 0;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron doSoftMask(&obj3, alpha, blendingColorSpace,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron isolated, knockout, funcs[0], &backdropColor);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (funcs[0]) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron delete funcs[0];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj4.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj3.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else if (!obj2.isNull()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj2.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj1.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::doSoftMask(Object *str, GBool alpha,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxColorSpace *blendingColorSpace,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GBool isolated, GBool knockout,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron Function *transferFunc, GfxColor *backdropColor) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron Dict *dict, *resDict;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double m[6], bbox[4];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron Object obj1, obj2;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron int i;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // check for excessive recursion
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (formDepth > 20) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // get stream dict
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron dict = str->streamGetDict();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // check form type
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron dict->lookup(const_cast<char*>("FormType"), &obj1);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "Unknown form type");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("Unknown form type"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj1.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // get bounding box
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron dict->lookup(const_cast<char*>("BBox"), &obj1);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!obj1.isArray()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj1.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "Bad form bounding box");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("Bad form bounding box"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (i = 0; i < 4; ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj1.arrayGet(i, &obj2);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron bbox[i] = obj2.getNum();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj2.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj1.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // get matrix
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding dict->lookup(const_cast<char*>("Matrix"), &obj1);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj1.isArray()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (i = 0; i < 6; ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj1.arrayGet(i, &obj2);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding m[i] = obj2.getNum();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj2.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding m[0] = 1; m[1] = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding m[2] = 0; m[3] = 1;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding m[4] = 0; m[5] = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj1.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald // get resources
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding dict->lookup(const_cast<char*>("Resources"), &obj1);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // draw it
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron ++formDepth;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron doForm1(str, resDict, m, bbox, gTrue, gTrue,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron blendingColorSpace, isolated, knockout,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding alpha, transferFunc, backdropColor);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm --formDepth;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (blendingColorSpace) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding delete blendingColorSpace;
7ddfd45e4d3d13de264931df8eb27ee7619fdb0ejerenkrantz }
138c8f7cb8254e035c6f45288e3909cd9c21be5cmartin obj1.free();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetRenderingIntent(Object /*args*/[], int /*numArgs*/)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding//------------------------------------------------------------------------
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// color operators
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding//------------------------------------------------------------------------
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetFillGray(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GfxColor color;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
dc80439e9fba60c753cd145cb6799409ffea9b71ronald state->setFillPattern(NULL);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald state->setFillColorSpace(new GfxDeviceGrayColorSpace());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding color.c[0] = dblToCol(args[0].getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillColor(&color);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->updateStyle(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe// TODO not good that numArgs is ignored but args[] is used:
b980ad7fdc218b4855cde9f75a747527f50c554dwrowevoid PdfParser::opSetStrokeGray(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GfxColor color;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
066877f1a045103acfdd376d48cdd473c33f409bdougm state->setStrokePattern(NULL);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
066877f1a045103acfdd376d48cdd473c33f409bdougm color.c[0] = dblToCol(args[0].getNum());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setStrokeColor(&color);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald builder->updateStyle(state);
066877f1a045103acfdd376d48cdd473c33f409bdougm}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron// TODO not good that numArgs is ignored but args[] is used:
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::opSetFillCMYKColor(Object args[], int /*numArgs*/)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron{
066877f1a045103acfdd376d48cdd473c33f409bdougm GfxColor color;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int i;
3adacd72419923c0eb3c2373d063d1a792181a88sf
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillPattern(NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (i = 0; i < 4; ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding color.c[i] = dblToCol(args[i].getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm state->setFillColor(&color);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->updateStyle(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetStrokeCMYKColor(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxColor color;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setStrokePattern(NULL);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron for (int i = 0; i < 4; ++i) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron color.c[i] = dblToCol(args[i].getNum());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setStrokeColor(&color);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->updateStyle(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
953ffc322984217eb04f911e041b40b7a91b54aawrowe
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron// TODO not good that numArgs is ignored but args[] is used:
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::opSetFillRGBColor(Object args[], int /*numArgs*/)
a9a941ed6ca86039137d64bdc7b1c4fda9d07d12sf{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GfxColor color;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillPattern(NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillColorSpace(new GfxDeviceRGBColorSpace());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (int i = 0; i < 3; ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding color.c[i] = dblToCol(args[i].getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillColor(&color);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->updateStyle(state);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetStrokeRGBColor(Object args[], int /*numArgs*/) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GfxColor color;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setStrokePattern(NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
f7376afc33a9e035921be9114c0e246820d7c8besf for (int i = 0; i < 3; ++i) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding color.c[i] = dblToCol(args[i].getNum());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setStrokeColor(&color);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->updateStyle(state);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
29c30db45f6a469017e16b606611e460cc1a1f2caaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
97d20d37d21b8d427a920e211858172f0a82427epoiriervoid PdfParser::opSetFillColorSpace(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
dc80439e9fba60c753cd145cb6799409ffea9b71ronald Object obj;
185aa71728867671e105178b4c66fbc22b65ae26sf
678a15e91d6a44569c956445442731bb64a98a63sf state->setFillPattern(NULL);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron res->lookupColorSpace(args[0].getName(), &obj);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GfxColorSpace *colorSpace = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj.isNull()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding colorSpace = GfxColorSpace::parse(&args[0], NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding colorSpace = GfxColorSpace::parse(&obj, NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj.isNull()) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm colorSpace = GfxColorSpace::parse(&args[0]);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron colorSpace = GfxColorSpace::parse(&obj);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron obj.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (colorSpace) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxColor color;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillColorSpace(colorSpace);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding colorSpace->getDefaultColor(&color);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillColor(&color);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->updateStyle(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "Bad color space (fill)");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("Bad color space (fill)"));
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf#endif
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron// TODO not good that numArgs is ignored but args[] is used:
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::opSetStrokeColorSpace(Object args[], int /*numArgs*/)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron{
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf Object obj;
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf GfxColorSpace *colorSpace = 0;
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf state->setStrokePattern(NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding res->lookupColorSpace(args[0].getName(), &obj);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (obj.isNull()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding colorSpace = GfxColorSpace::parse(&args[0], NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron colorSpace = GfxColorSpace::parse(&obj, NULL);
f7376afc33a9e035921be9114c0e246820d7c8besf }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (obj.isNull()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron colorSpace = GfxColorSpace::parse(&args[0]);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron colorSpace = GfxColorSpace::parse(&obj);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding obj.free();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (colorSpace) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxColor color;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setStrokeColorSpace(colorSpace);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron colorSpace->getDefaultColor(&color);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setStrokeColor(&color);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->updateStyle(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "Bad color space (stroke)");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("Bad color space (stroke)"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetFillColor(Object args[], int numArgs) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GfxColor color;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron int i;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (numArgs != state->getFillColorSpace()->getNComps()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "Incorrect number of arguments in 'sc' command");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("Incorrect number of arguments in 'sc' command"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setFillPattern(NULL);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron for (i = 0; i < numArgs; ++i) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron color.c[i] = dblToCol(args[i].getNum());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillColor(&color);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->updateStyle(state);
b76a31daaa6e83bb0fd627a04f20e82bffcf1df4poirier}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opSetStrokeColor(Object args[], int numArgs) {
e8f95a682820a599fe41b22977010636be5c2717jim GfxColor color;
820be4f3a1a5b0565a072b0bf582d19fb791b68dnd int i;
820be4f3a1a5b0565a072b0bf582d19fb791b68dnd
7af19efc4667363f74d332a8d010b49e88d56fd5trawick if (numArgs != state->getStrokeColorSpace()->getNComps()) {
820be4f3a1a5b0565a072b0bf582d19fb791b68dnd#ifdef POPPLER_NEW_ERRORAPI
820be4f3a1a5b0565a072b0bf582d19fb791b68dnd error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SC' command");
e8f95a682820a599fe41b22977010636be5c2717jim#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SC' command"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
820be4f3a1a5b0565a072b0bf582d19fb791b68dnd return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setStrokePattern(NULL);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm for (i = 0; i < numArgs; ++i) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron color.c[i] = dblToCol(args[i].getNum());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setStrokeColor(&color);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->updateStyle(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::opSetFillColorN(Object args[], int numArgs) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxColor color;
c7d0205ec1649076e7742d72a25ac53779768312stoddard int i;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (state->getFillColorSpace()->getMode() == csPattern) {
a44d29a3794110c558c940bd903a1930d717a7d7sf if (numArgs > 1) {
a44d29a3794110c558c940bd903a1930d717a7d7sf if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() ||
a44d29a3794110c558c940bd903a1930d717a7d7sf numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace())
a44d29a3794110c558c940bd903a1930d717a7d7sf ->getUnder()->getNComps()) {
a44d29a3794110c558c940bd903a1930d717a7d7sf#ifdef POPPLER_NEW_ERRORAPI
a44d29a3794110c558c940bd903a1930d717a7d7sf error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
a44d29a3794110c558c940bd903a1930d717a7d7sf#else
a44d29a3794110c558c940bd903a1930d717a7d7sf error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
a44d29a3794110c558c940bd903a1930d717a7d7sf#endif
a44d29a3794110c558c940bd903a1930d717a7d7sf return;
a44d29a3794110c558c940bd903a1930d717a7d7sf }
a44d29a3794110c558c940bd903a1930d717a7d7sf for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
a44d29a3794110c558c940bd903a1930d717a7d7sf if (args[i].isNum()) {
a44d29a3794110c558c940bd903a1930d717a7d7sf color.c[i] = dblToCol(args[i].getNum());
a44d29a3794110c558c940bd903a1930d717a7d7sf }
a44d29a3794110c558c940bd903a1930d717a7d7sf }
a44d29a3794110c558c940bd903a1930d717a7d7sf state->setFillColor(&color);
a44d29a3794110c558c940bd903a1930d717a7d7sf builder->updateStyle(state);
a44d29a3794110c558c940bd903a1930d717a7d7sf }
a44d29a3794110c558c940bd903a1930d717a7d7sf GfxPattern *pattern;
a44d29a3794110c558c940bd903a1930d717a7d7sf#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
a44d29a3794110c558c940bd903a1930d717a7d7sf if (args[numArgs-1].isName() &&
a44d29a3794110c558c940bd903a1930d717a7d7sf (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
a44d29a3794110c558c940bd903a1930d717a7d7sf state->setFillPattern(pattern);
a44d29a3794110c558c940bd903a1930d717a7d7sf builder->updateStyle(state);
a44d29a3794110c558c940bd903a1930d717a7d7sf }
a44d29a3794110c558c940bd903a1930d717a7d7sf#else
a44d29a3794110c558c940bd903a1930d717a7d7sf if (args[numArgs-1].isName() &&
a44d29a3794110c558c940bd903a1930d717a7d7sf (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
a44d29a3794110c558c940bd903a1930d717a7d7sf state->setFillPattern(pattern);
a44d29a3794110c558c940bd903a1930d717a7d7sf builder->updateStyle(state);
a44d29a3794110c558c940bd903a1930d717a7d7sf }
a44d29a3794110c558c940bd903a1930d717a7d7sf#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (numArgs != state->getFillColorSpace()->getNComps()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
f78505c7d260473bf11002f5028186f27d0ed8a0geoff#else
f78505c7d260473bf11002f5028186f27d0ed8a0geoff error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz return;
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz state->setFillPattern(NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz if (args[i].isNum()) {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz color.c[i] = dblToCol(args[i].getNum());
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz state->setFillColor(&color);
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz builder->updateStyle(state);
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz}
e9f8410b788ef1e6f1baed6c706ffdf3da395a16jerenkrantz
2e242dca7111f99d54dd144b7b8418d88d560032chrisdvoid PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
2e242dca7111f99d54dd144b7b8418d88d560032chrisd GfxColor color;
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez int i;
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez
185aa71728867671e105178b4c66fbc22b65ae26sf if (state->getStrokeColorSpace()->getMode() == csPattern) {
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez if (numArgs > 1) {
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez if (!((GfxPatternColorSpace *)state->getStrokeColorSpace())
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez ->getUnder() ||
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace())
33b444dee16ba708960701c5b1ceb69df1548017pquerna ->getUnder()->getNComps()) {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz#ifdef POPPLER_NEW_ERRORAPI
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz#else
33b444dee16ba708960701c5b1ceb69df1548017pquerna error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz#endif
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz return;
69c1e98e10528ac12ed3f56a811c57fc1c9e31e5bnicholes }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz if (args[i].isNum()) {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz color.c[i] = dblToCol(args[i].getNum());
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz }
69c1e98e10528ac12ed3f56a811c57fc1c9e31e5bnicholes }
69c1e98e10528ac12ed3f56a811c57fc1c9e31e5bnicholes state->setStrokeColor(&color);
4d4953238984d603c574511f35ef8d5bdbc70862wsanchez builder->updateStyle(state);
4d4953238984d603c574511f35ef8d5bdbc70862wsanchez }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz GfxPattern *pattern;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz if (args[numArgs-1].isName() &&
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz state->setStrokePattern(pattern);
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz builder->updateStyle(state);
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz#else
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz if (args[numArgs-1].isName() &&
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz state->setStrokePattern(pattern);
f78505c7d260473bf11002f5028186f27d0ed8a0geoff builder->updateStyle(state);
f78505c7d260473bf11002f5028186f27d0ed8a0geoff }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz#endif
f78505c7d260473bf11002f5028186f27d0ed8a0geoff
f78505c7d260473bf11002f5028186f27d0ed8a0geoff } else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (numArgs != state->getStrokeColorSpace()->getNComps()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#endif
dc80439e9fba60c753cd145cb6799409ffea9b71ronald return;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setStrokePattern(NULL);
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier if (args[i].isNum()) {
185aa71728867671e105178b4c66fbc22b65ae26sf color.c[i] = dblToCol(args[i].getNum());
678a15e91d6a44569c956445442731bb64a98a63sf }
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier }
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier state->setStrokeColor(&color);
e5db2522dbe503cbf5399094b6239c88c246a8c5poirier builder->updateStyle(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding//------------------------------------------------------------------------
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf// path segment operators
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf//------------------------------------------------------------------------
ec8b1faa56744b338f6d6421144b56c2bb3faae6poirier
ec8b1faa56744b338f6d6421144b56c2bb3faae6poirier// TODO not good that numArgs is ignored but args[] is used:
185aa71728867671e105178b4c66fbc22b65ae26sfvoid PdfParser::opMoveTo(Object args[], int /*numArgs*/)
678a15e91d6a44569c956445442731bb64a98a63sf{
ec8b1faa56744b338f6d6421144b56c2bb3faae6poirier state->moveTo(args[0].getNum(), args[1].getNum());
ec8b1faa56744b338f6d6421144b56c2bb3faae6poirier}
ec8b1faa56744b338f6d6421144b56c2bb3faae6poirier
ec8b1faa56744b338f6d6421144b56c2bb3faae6poirier// TODO not good that numArgs is ignored but args[] is used:
ec8b1faa56744b338f6d6421144b56c2bb3faae6poiriervoid PdfParser::opLineTo(Object args[], int /*numArgs*/)
ec8b1faa56744b338f6d6421144b56c2bb3faae6poirier{
ec8b1faa56744b338f6d6421144b56c2bb3faae6poirier if (!state->isCurPt()) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald#ifdef POPPLER_NEW_ERRORAPI
10a4cdd68ef1ca0e54af296fe1d08ac00150c90bwrowe error(errSyntaxError, getPos(), "No current point in lineto");
185aa71728867671e105178b4c66fbc22b65ae26sf#else
678a15e91d6a44569c956445442731bb64a98a63sf error(getPos(), const_cast<char*>("No current point in lineto"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
dc80439e9fba60c753cd145cb6799409ffea9b71ronald return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->lineTo(args[0].getNum(), args[1].getNum());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
dc80439e9fba60c753cd145cb6799409ffea9b71ronaldvoid PdfParser::opCurveTo(Object args[], int /*numArgs*/)
185aa71728867671e105178b4c66fbc22b65ae26sf{
678a15e91d6a44569c956445442731bb64a98a63sf if (!state->isCurPt()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errSyntaxError, getPos(), "No current point in curveto");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("No current point in curveto"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding double x1 = args[0].getNum();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding double y1 = args[1].getNum();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double x2 = args[2].getNum();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding double y2 = args[3].getNum();
54062d8f070826e448822c315895f1ea2b9414adwrowe double x3 = args[4].getNum();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding double y3 = args[5].getNum();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->curveTo(x1, y1, x2, y2, x3, y3);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
185aa71728867671e105178b4c66fbc22b65ae26sf// TODO not good that numArgs is ignored but args[] is used:
678a15e91d6a44569c956445442731bb64a98a63sfvoid PdfParser::opCurveTo1(Object args[], int /*numArgs*/)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!state->isCurPt()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(errSyntaxError, getPos(), "No current point in curveto1");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error(getPos(), const_cast<char*>("No current point in curveto1"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
a9a941ed6ca86039137d64bdc7b1c4fda9d07d12sf return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding double x1 = state->getCurX();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding double y1 = state->getCurY();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding double x2 = args[0].getNum();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding double y2 = args[1].getNum();
185aa71728867671e105178b4c66fbc22b65ae26sf double x3 = args[2].getNum();
678a15e91d6a44569c956445442731bb64a98a63sf double y3 = args[3].getNum();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->curveTo(x1, y1, x2, y2, x3, y3);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opCurveTo2(Object args[], int /*numArgs*/)
c7d0205ec1649076e7742d72a25ac53779768312stoddard{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!state->isCurPt()) {
185aa71728867671e105178b4c66fbc22b65ae26sf#ifdef POPPLER_NEW_ERRORAPI
678a15e91d6a44569c956445442731bb64a98a63sf error(errSyntaxError, getPos(), "No current point in curveto2");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("No current point in curveto2"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding double x1 = args[0].getNum();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double y1 = args[1].getNum();
185aa71728867671e105178b4c66fbc22b65ae26sf double x2 = args[2].getNum();
678a15e91d6a44569c956445442731bb64a98a63sf double y2 = args[3].getNum();
e8f95a682820a599fe41b22977010636be5c2717jim double x3 = x2;
a6b7c81f40de22f96f08092379da5ba44cb4714ebrianp double y3 = y2;
a6b7c81f40de22f96f08092379da5ba44cb4714ebrianp state->curveTo(x1, y1, x2, y2, x3, y3);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opRectangle(Object args[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double x = args[0].getNum();
185aa71728867671e105178b4c66fbc22b65ae26sf double y = args[1].getNum();
678a15e91d6a44569c956445442731bb64a98a63sf double w = args[2].getNum();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double h = args[3].getNum();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->moveTo(x, y);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->lineTo(x + w, y);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->lineTo(x + w, y + h);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->lineTo(x, y + h);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->closePath();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opClosePath(Object /*args*/[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!state->isCurPt()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef POPPLER_NEW_ERRORAPI
dc80439e9fba60c753cd145cb6799409ffea9b71ronald error(errSyntaxError, getPos(), "No current point in closepath");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("No current point in closepath"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#endif
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
7ddfd45e4d3d13de264931df8eb27ee7619fdb0ejerenkrantz state->closePath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron//------------------------------------------------------------------------
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron// path painting operators
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding//------------------------------------------------------------------------
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
dc80439e9fba60c753cd145cb6799409ffea9b71ronaldvoid PdfParser::opEndPath(Object /*args*/[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron doEndPath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opStroke(Object /*args*/[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
f7376afc33a9e035921be9114c0e246820d7c8besf if (!state->isCurPt()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron //error(getPos(), const_cast<char*>("No path in stroke"));
f7376afc33a9e035921be9114c0e246820d7c8besf return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (state->isPath()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (state->getStrokeColorSpace()->getMode() == csPattern &&
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron !builder->isPatternTypeSupported(state->getStrokePattern())) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron doPatternStrokeFallback();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->addPath(state, false, true);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding doEndPath();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
e8f95a682820a599fe41b22977010636be5c2717jim
8b99f2a316c5e2fa6ab208206fdd7fc2bfc4a921dougmvoid PdfParser::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!state->isCurPt()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron //error(getPos(), const_cast<char*>("No path in closepath/stroke"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->closePath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (state->isPath()) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (state->getStrokeColorSpace()->getMode() == csPattern &&
dc80439e9fba60c753cd145cb6799409ffea9b71ronald !builder->isPatternTypeSupported(state->getStrokePattern())) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron doPatternStrokeFallback();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->addPath(state, false, true);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald doEndPath();
dc80439e9fba60c753cd145cb6799409ffea9b71ronald}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::opFill(Object /*args*/[], int /*numArgs*/)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!state->isCurPt()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron //error(getPos(), const_cast<char*>("No path in fill"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (state->isPath()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (state->getFillColorSpace()->getMode() == csPattern &&
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron !builder->isPatternTypeSupported(state->getFillPattern())) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron doPatternFillFallback(gFalse);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->addPath(state, true, false);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald doEndPath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::opEOFill(Object /*args*/[], int /*numArgs*/)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!state->isCurPt()) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald //error(getPos(), const_cast<char*>("No path in eofill"));
60f406441b71be7779bd5794e9745ab0c60bc336jorton return;
60f406441b71be7779bd5794e9745ab0c60bc336jorton }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (state->isPath()) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (state->getFillColorSpace()->getMode() == csPattern &&
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding !builder->isPatternTypeSupported(state->getFillPattern())) {
000b67449410515eac43e76ef6667915bfd4d2abgstein doPatternFillFallback(gTrue);
000b67449410515eac43e76ef6667915bfd4d2abgstein } else {
000b67449410515eac43e76ef6667915bfd4d2abgstein builder->addPath(state, true, false, true);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding doEndPath();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opFillStroke(Object /*args*/[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!state->isCurPt()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding //error(getPos(), const_cast<char*>("No path in fill/stroke"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (state->isPath()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding doFillAndStroke(gFalse);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->addPath(state, true, true);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding doEndPath();
f78505c7d260473bf11002f5028186f27d0ed8a0geoff}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opCloseFillStroke(Object /*args*/[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!state->isCurPt()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron //error(getPos(), const_cast<char*>("No path in closepath/fill/stroke"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (state->isPath()) {
185aa71728867671e105178b4c66fbc22b65ae26sf state->closePath();
678a15e91d6a44569c956445442731bb64a98a63sf doFillAndStroke(gFalse);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding doEndPath();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opEOFillStroke(Object /*args*/[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!state->isCurPt()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron //error(getPos(), const_cast<char*>("No path in eofill/stroke"));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (state->isPath()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron doFillAndStroke(gTrue);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding doEndPath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opCloseEOFillStroke(Object /*args*/[], int /*numArgs*/)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!state->isCurPt()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding //error(getPos(), const_cast<char*>("No path in closepath/eofill/stroke"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (state->isPath()) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald state->closePath();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding doFillAndStroke(gTrue);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding doEndPath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
185aa71728867671e105178b4c66fbc22b65ae26sf
678a15e91d6a44569c956445442731bb64a98a63sfvoid PdfParser::doFillAndStroke(GBool eoFill) {
678a15e91d6a44569c956445442731bb64a98a63sf GBool fillOk = gTrue, strokeOk = gTrue;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (state->getFillColorSpace()->getMode() == csPattern &&
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron !builder->isPatternTypeSupported(state->getFillPattern())) {
185aa71728867671e105178b4c66fbc22b65ae26sf fillOk = gFalse;
678a15e91d6a44569c956445442731bb64a98a63sf }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (state->getStrokeColorSpace()->getMode() == csPattern &&
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron !builder->isPatternTypeSupported(state->getStrokePattern())) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron strokeOk = gFalse;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (fillOk && strokeOk) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->addPath(state, true, true, eoFill);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding doPatternFillFallback(eoFill);
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald doPatternStrokeFallback();
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::doPatternFillFallback(GBool eoFill) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald GfxPattern *pattern;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!(pattern = state->getFillPattern())) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron switch (pattern->getType()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron case 1:
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron break;
185aa71728867671e105178b4c66fbc22b65ae26sf case 2:
678a15e91d6a44569c956445442731bb64a98a63sf doShadingPatternFillFallback(static_cast<GfxShadingPattern *>(pattern), gFalse, eoFill);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron break;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron default:
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#ifdef POPPLER_NEW_ERRORAPI
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(errUnimplemented, getPos(), "Unimplemented pattern type (%d) in fill",
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#else
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in fill"),
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron pattern->getType());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron break;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
781888a651637edc0b043a6787cb0c2acf30a187geoff}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::doPatternStrokeFallback() {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxPattern *pattern;
781888a651637edc0b043a6787cb0c2acf30a187geoff
e8f95a682820a599fe41b22977010636be5c2717jim if (!(pattern = state->getStrokePattern())) {
781888a651637edc0b043a6787cb0c2acf30a187geoff return;
781888a651637edc0b043a6787cb0c2acf30a187geoff }
781888a651637edc0b043a6787cb0c2acf30a187geoff switch (pattern->getType()) {
781888a651637edc0b043a6787cb0c2acf30a187geoff case 1:
e8f95a682820a599fe41b22977010636be5c2717jim break;
781888a651637edc0b043a6787cb0c2acf30a187geoff case 2:
e8f95a682820a599fe41b22977010636be5c2717jim doShadingPatternFillFallback(static_cast<GfxShadingPattern *>(pattern), gTrue, gFalse);
781888a651637edc0b043a6787cb0c2acf30a187geoff break;
781888a651637edc0b043a6787cb0c2acf30a187geoff default:
e8f95a682820a599fe41b22977010636be5c2717jim#ifdef POPPLER_NEW_ERRORAPI
781888a651637edc0b043a6787cb0c2acf30a187geoff error(errUnimplemented, getPos(), "Unimplemented pattern type ({0:d}) in stroke",
781888a651637edc0b043a6787cb0c2acf30a187geoff#else
781888a651637edc0b043a6787cb0c2acf30a187geoff error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in stroke"),
781888a651637edc0b043a6787cb0c2acf30a187geoff#endif
e8f95a682820a599fe41b22977010636be5c2717jim pattern->getType());
781888a651637edc0b043a6787cb0c2acf30a187geoff break;
e8f95a682820a599fe41b22977010636be5c2717jim }
185aa71728867671e105178b4c66fbc22b65ae26sf}
781888a651637edc0b043a6787cb0c2acf30a187geoff
781888a651637edc0b043a6787cb0c2acf30a187geoffvoid PdfParser::doShadingPatternFillFallback(GfxShadingPattern *sPat,
781888a651637edc0b043a6787cb0c2acf30a187geoff GBool stroke, GBool eoFill) {
781888a651637edc0b043a6787cb0c2acf30a187geoff GfxShading *shading;
e8f95a682820a599fe41b22977010636be5c2717jim GfxPath *savedPath;
781888a651637edc0b043a6787cb0c2acf30a187geoff double *ctm, *btm, *ptm;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double m[6], ictm[6], m1[6];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double xMin, yMin, xMax, yMax;
60f406441b71be7779bd5794e9745ab0c60bc336jorton double det;
185aa71728867671e105178b4c66fbc22b65ae26sf
678a15e91d6a44569c956445442731bb64a98a63sf shading = sPat->getShading();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // save current graphics state
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron savedPath = state->getPath()->copy();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron saveState();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // clip to bbox
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (0 ){//shading->getHasBBox()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron shading->getBBox(&xMin, &yMin, &xMax, &yMax);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->moveTo(xMin, yMin);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->lineTo(xMax, yMin);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->lineTo(xMax, yMax);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->lineTo(xMin, yMax);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->closePath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->clip();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron //builder->clip(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setPath(savedPath->copy());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // clip to current path
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (stroke) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->clipToStrokePath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron //out->clipToStrokePath(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->clip();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (eoFill) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->setClipPath(state, true);
185aa71728867671e105178b4c66fbc22b65ae26sf } else {
678a15e91d6a44569c956445442731bb64a98a63sf builder->setClipPath(state);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // set the color space
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->setFillColorSpace(shading->getColorSpace()->copy());
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
185aa71728867671e105178b4c66fbc22b65ae26sf // background color fill
678a15e91d6a44569c956445442731bb64a98a63sf if (shading->getHasBackground()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setFillColor(shading->getBackground());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->addPath(state, true, false);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->clearPath();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
aa6cb33e0279a72e5b5f482871844ebd85dfd527minfrin // construct a (pattern space) -> (current space) transform matrix
aa6cb33e0279a72e5b5f482871844ebd85dfd527minfrin ctm = state->getCTM();
aa6cb33e0279a72e5b5f482871844ebd85dfd527minfrin btm = baseMatrix;
aa6cb33e0279a72e5b5f482871844ebd85dfd527minfrin ptm = sPat->getMatrix();
aa6cb33e0279a72e5b5f482871844ebd85dfd527minfrin // iCTM = invert CTM
aa6cb33e0279a72e5b5f482871844ebd85dfd527minfrin det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
aa6cb33e0279a72e5b5f482871844ebd85dfd527minfrin ictm[0] = ctm[3] * det;
aa6cb33e0279a72e5b5f482871844ebd85dfd527minfrin ictm[1] = -ctm[1] * det;
aa6cb33e0279a72e5b5f482871844ebd85dfd527minfrin ictm[2] = -ctm[2] * det;
185aa71728867671e105178b4c66fbc22b65ae26sf ictm[3] = ctm[0] * det;
678a15e91d6a44569c956445442731bb64a98a63sf ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // m1 = PTM * BTM = PTM * base transform matrix
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
f7376afc33a9e035921be9114c0e246820d7c8besf m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
185aa71728867671e105178b4c66fbc22b65ae26sf m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
678a15e91d6a44569c956445442731bb64a98a63sf // m = m1 * iCTM = (PTM * BTM) * (iCTM)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
f78505c7d260473bf11002f5028186f27d0ed8a0geoff m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
f78505c7d260473bf11002f5028186f27d0ed8a0geoff
f78505c7d260473bf11002f5028186f27d0ed8a0geoff // set the new matrix
185aa71728867671e105178b4c66fbc22b65ae26sf state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
678a15e91d6a44569c956445442731bb64a98a63sf builder->setTransform(m[0], m[1], m[2], m[3], m[4], m[5]);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // do shading type-specific operations
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron switch (shading->getType()) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case 1:
f78505c7d260473bf11002f5028186f27d0ed8a0geoff doFunctionShFill(static_cast<GfxFunctionShading *>(shading));
f78505c7d260473bf11002f5028186f27d0ed8a0geoff break;
f78505c7d260473bf11002f5028186f27d0ed8a0geoff case 2:
f769c33501f474aed3e0f7c769477c8c4f478783geoff case 3:
f769c33501f474aed3e0f7c769477c8c4f478783geoff // no need to implement these
185aa71728867671e105178b4c66fbc22b65ae26sf break;
678a15e91d6a44569c956445442731bb64a98a63sf case 4:
f769c33501f474aed3e0f7c769477c8c4f478783geoff case 5:
f769c33501f474aed3e0f7c769477c8c4f478783geoff doGouraudTriangleShFill(static_cast<GfxGouraudTriangleShading *>(shading));
f769c33501f474aed3e0f7c769477c8c4f478783geoff break;
f769c33501f474aed3e0f7c769477c8c4f478783geoff case 6:
d8ea9d035301c33f3d9d3ecf3335f78ffcde1fb2covener case 7:
d8ea9d035301c33f3d9d3ecf3335f78ffcde1fb2covener doPatchMeshShFill(static_cast<GfxPatchMeshShading *>(shading));
d8ea9d035301c33f3d9d3ecf3335f78ffcde1fb2covener break;
f78505c7d260473bf11002f5028186f27d0ed8a0geoff }
f78505c7d260473bf11002f5028186f27d0ed8a0geoff
f78505c7d260473bf11002f5028186f27d0ed8a0geoff // restore graphics state
f78505c7d260473bf11002f5028186f27d0ed8a0geoff restoreState();
f78505c7d260473bf11002f5028186f27d0ed8a0geoff state->setPath(savedPath);
f78505c7d260473bf11002f5028186f27d0ed8a0geoff}
f78505c7d260473bf11002f5028186f27d0ed8a0geoff
e8f95a682820a599fe41b22977010636be5c2717jim// TODO not good that numArgs is ignored but args[] is used:
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingvoid PdfParser::opShFill(Object args[], int /*numArgs*/)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxShading *shading = 0;
185aa71728867671e105178b4c66fbc22b65ae26sf GfxPath *savedPath = NULL;
678a15e91d6a44569c956445442731bb64a98a63sf double xMin, yMin, xMax, yMax;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double xTemp, yTemp;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double gradientTransform[6];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double *matrix = NULL;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GBool savedState = gFalse;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!(shading = res->lookupShading(args[0].getName(), NULL))) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return;
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf }
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf#else
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf if (!(shading = res->lookupShading(args[0].getName()))) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron#endif
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // save current graphics state
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (shading->getType() != 2 && shading->getType() != 3) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron savedPath = state->getPath()->copy();
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf saveState();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron savedState = gTrue;
185aa71728867671e105178b4c66fbc22b65ae26sf } else { // get gradient transform if possible
678a15e91d6a44569c956445442731bb64a98a63sf // check proper operator sequence
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // first there should be one W(*) and then one 'cm' somewhere before 'sh'
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GBool seenClip, seenConcat;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron seenClip = (clipHistory->getClipPath() != NULL);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron seenConcat = gFalse;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron int i = 1;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron while (i <= maxOperatorHistoryDepth) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron const char *opName = getPreviousOperator(i);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!strcmp(opName, "cm")) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (seenConcat) { // more than one 'cm'
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron break;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron } else {
185aa71728867671e105178b4c66fbc22b65ae26sf seenConcat = gTrue;
678a15e91d6a44569c956445442731bb64a98a63sf }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron i++;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (seenConcat && seenClip) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (builder->getTransform(gradientTransform)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding matrix = (double*)&gradientTransform;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->setTransform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); // remove transform
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // clip to bbox
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (shading->getHasBBox()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron shading->getBBox(&xMin, &yMin, &xMax, &yMax);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (matrix != NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding xTemp = matrix[0]*xMin + matrix[2]*yMin + matrix[4];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding yTemp = matrix[1]*xMin + matrix[3]*yMin + matrix[5];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->moveTo(xTemp, yTemp);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding xTemp = matrix[0]*xMax + matrix[2]*yMin + matrix[4];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding yTemp = matrix[1]*xMax + matrix[3]*yMin + matrix[5];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->lineTo(xTemp, yTemp);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding xTemp = matrix[0]*xMax + matrix[2]*yMax + matrix[4];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding yTemp = matrix[1]*xMax + matrix[3]*yMax + matrix[5];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->lineTo(xTemp, yTemp);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding xTemp = matrix[0]*xMin + matrix[2]*yMax + matrix[4];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding yTemp = matrix[1]*xMin + matrix[3]*yMax + matrix[5];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->lineTo(xTemp, yTemp);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->moveTo(xMin, yMin);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->lineTo(xMax, yMin);
00231c86206cfcb141a0a21fa44ff7d4c590208ejorton state->lineTo(xMax, yMax);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->lineTo(xMin, yMax);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->closePath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->clip();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (savedState)
00231c86206cfcb141a0a21fa44ff7d4c590208ejorton builder->setClipPath(state);
00231c86206cfcb141a0a21fa44ff7d4c590208ejorton else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding builder->clip(state);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->clearPath();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // set the color space
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (savedState)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setFillColorSpace(shading->getColorSpace()->copy());
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // do shading type-specific operations
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron switch (shading->getType()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron case 1:
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron doFunctionShFill(static_cast<GfxFunctionShading *>(shading));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron break;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case 2:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case 3:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (clipHistory->getClipPath()) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->addShadedFill(shading, matrix, clipHistory->getClipPath(),
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron clipHistory->getClipType() == clipEO ? true : false);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding break;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case 4:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case 5:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding doGouraudTriangleShFill(static_cast<GfxGouraudTriangleShading *>(shading));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding break;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case 6:
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf case 7:
fd9b4a0b713bc4816b9b80f52d567f5c2ac06bafsf doPatchMeshShFill(static_cast<GfxPatchMeshShading *>(shading));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron break;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
00231c86206cfcb141a0a21fa44ff7d4c590208ejorton
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // restore graphics state
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (savedState) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron restoreState();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->setPath(savedPath);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
f7376afc33a9e035921be9114c0e246820d7c8besf delete shading;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
f7376afc33a9e035921be9114c0e246820d7c8besf
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::doFunctionShFill(GfxFunctionShading *shading) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double x0, y0, x1, y1;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxColor colors[4];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron shading->getDomain(&x0, &y0, &x1, &y1);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron shading->getColor(x0, y0, &colors[0]);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron shading->getColor(x0, y1, &colors[1]);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron shading->getColor(x1, y0, &colors[2]);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron shading->getColor(x1, y1, &colors[3]);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronvoid PdfParser::doFunctionShFill1(GfxFunctionShading *shading,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double x0, double y0,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double x1, double y1,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxColor *colors, int depth) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxColor fillColor;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxColor color0M, color1M, colorM0, colorM1, colorMM;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron GfxColor colors2[4];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double functionColorDelta = colorDeltas[pdfFunctionShading-1];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double *matrix;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron double xM, yM;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron int nComps, i, j;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron nComps = shading->getColorSpace()->getNComps();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron matrix = shading->getMatrix();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron // compare the four corner colors
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron for (i = 0; i < 4; ++i) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron for (j = 0; j < nComps; ++j) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron break;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (j < nComps) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron break;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
73e8b26287de5c06fa470d36162e103dbac9c7e5wrowe // center of the rectangle
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald xM = 0.5 * (x0 + x1);
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald yM = 0.5 * (y0 + y1);
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald // the four corner colors are close (or we hit the recursive limit)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick // -- fill the rectangle; but require at least one subdivision
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe // (depth==0) to avoid problems when the four outer corners of the
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe // shaded region are the same color
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe if ((i == 4 && depth > 0) || depth == maxDepths[pdfFunctionShading-1]) {
a72211e92bab814bfa28ee086ca9b2a1a6095c92chrisd
a72211e92bab814bfa28ee086ca9b2a1a6095c92chrisd // use the center color
b4a287513d176e4355dd56ea47b27228e0e5d75fjerenkrantz shading->getColor(xM, yM, &fillColor);
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe state->setFillColor(&fillColor);
a44d29a3794110c558c940bd903a1930d717a7d7sf
a44d29a3794110c558c940bd903a1930d717a7d7sf // fill the rectangle
a44d29a3794110c558c940bd903a1930d717a7d7sf state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4],
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald x0 * matrix[1] + y0 * matrix[3] + matrix[5]);
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4],
36ef8f77bffe75d1aa327882be1b5bdbe2ff567asf x1 * matrix[1] + y0 * matrix[3] + matrix[5]);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4],
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald x1 * matrix[1] + y1 * matrix[3] + matrix[5]);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4],
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron x0 * matrix[1] + y1 * matrix[3] + matrix[5]);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->closePath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron builder->addPath(state, true, false);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron state->clearPath();
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // the four corner colors are not close enough -- subdivide the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding // rectangle
} else {
// colors[0] colorM0 colors[2]
// (x0,y0) (xM,y0) (x1,y0)
// +----------+----------+
// | | |
// | UL | UR |
// color0M | colorMM | color1M
// (x0,yM) +----------+----------+ (x1,yM)
// | (xM,yM) |
// | LL | LR |
// | | |
// +----------+----------+
// colors[1] colorM1 colors[3]
// (x0,y1) (xM,y1) (x1,y1)
shading->getColor(x0, yM, &color0M);
shading->getColor(x1, yM, &color1M);
shading->getColor(xM, y0, &colorM0);
shading->getColor(xM, y1, &colorM1);
shading->getColor(xM, yM, &colorMM);
// upper-left sub-rectangle
colors2[0] = colors[0];
colors2[1] = color0M;
colors2[2] = colorM0;
colors2[3] = colorMM;
doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1);
// lower-left sub-rectangle
colors2[0] = color0M;
colors2[1] = colors[1];
colors2[2] = colorMM;
colors2[3] = colorM1;
doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1);
// upper-right sub-rectangle
colors2[0] = colorM0;
colors2[1] = colorMM;
colors2[2] = colors[2];
colors2[3] = color1M;
doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1);
// lower-right sub-rectangle
colors2[0] = colorMM;
colors2[1] = colorM1;
colors2[2] = color1M;
colors2[3] = colors[3];
doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1);
}
}
void PdfParser::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
double x0, y0, x1, y1, x2, y2;
GfxColor color0, color1, color2;
int i;
for (i = 0; i < shading->getNTriangles(); ++i) {
shading->getTriangle(i, &x0, &y0, &color0,
&x1, &y1, &color1,
&x2, &y2, &color2);
gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
shading->getColorSpace()->getNComps(), 0);
}
}
void PdfParser::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
double x1, double y1, GfxColor *color1,
double x2, double y2, GfxColor *color2,
int nComps, int depth) {
double x01, y01, x12, y12, x20, y20;
double gouraudColorDelta = colorDeltas[pdfGouraudTriangleShading-1];
GfxColor color01, color12, color20;
int i;
for (i = 0; i < nComps; ++i) {
if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta ||
abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) {
break;
}
}
if (i == nComps || depth == maxDepths[pdfGouraudTriangleShading-1]) {
state->setFillColor(color0);
state->moveTo(x0, y0);
state->lineTo(x1, y1);
state->lineTo(x2, y2);
state->closePath();
builder->addPath(state, true, false);
state->clearPath();
} else {
x01 = 0.5 * (x0 + x1);
y01 = 0.5 * (y0 + y1);
x12 = 0.5 * (x1 + x2);
y12 = 0.5 * (y1 + y2);
x20 = 0.5 * (x2 + x0);
y20 = 0.5 * (y2 + y0);
//~ if the shading has a Function, this should interpolate on the
//~ function parameter, not on the color components
for (i = 0; i < nComps; ++i) {
color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
}
gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
x20, y20, &color20, nComps, depth + 1);
gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
x12, y12, &color12, nComps, depth + 1);
gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
x20, y20, &color20, nComps, depth + 1);
gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
x2, y2, color2, nComps, depth + 1);
}
}
void PdfParser::doPatchMeshShFill(GfxPatchMeshShading *shading) {
int start, i;
if (shading->getNPatches() > 128) {
start = 3;
} else if (shading->getNPatches() > 64) {
start = 2;
} else if (shading->getNPatches() > 16) {
start = 1;
} else {
start = 0;
}
for (i = 0; i < shading->getNPatches(); ++i) {
fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(),
start);
}
}
void PdfParser::fillPatch(GfxPatch *patch, int nComps, int depth) {
GfxPatch patch00, patch01, patch10, patch11;
#ifdef POPPLER_NEW_GFXPATCH
GfxColor color;
#endif
double xx[4][8], yy[4][8];
double xxm, yym;
double patchColorDelta = colorDeltas[pdfPatchMeshShading-1];
int i;
for (i = 0; i < nComps; ++i) {
if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
> patchColorDelta ||
abs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
> patchColorDelta ||
abs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
> patchColorDelta ||
abs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
> patchColorDelta) {
break;
}
#ifdef POPPLER_NEW_GFXPATCH
color.c[i] = GfxColorComp(patch->color[0][0].c[i]);
#endif
}
if (i == nComps || depth == maxDepths[pdfPatchMeshShading-1]) {
#ifdef POPPLER_NEW_GFXPATCH
state->setFillColor(&color);
#else
state->setFillColor(&patch->color[0][0]);
#endif
state->moveTo(patch->x[0][0], patch->y[0][0]);
state->curveTo(patch->x[0][1], patch->y[0][1],
patch->x[0][2], patch->y[0][2],
patch->x[0][3], patch->y[0][3]);
state->curveTo(patch->x[1][3], patch->y[1][3],
patch->x[2][3], patch->y[2][3],
patch->x[3][3], patch->y[3][3]);
state->curveTo(patch->x[3][2], patch->y[3][2],
patch->x[3][1], patch->y[3][1],
patch->x[3][0], patch->y[3][0]);
state->curveTo(patch->x[2][0], patch->y[2][0],
patch->x[1][0], patch->y[1][0],
patch->x[0][0], patch->y[0][0]);
state->closePath();
builder->addPath(state, true, false);
state->clearPath();
} else {
for (i = 0; i < 4; ++i) {
xx[i][0] = patch->x[i][0];
yy[i][0] = patch->y[i][0];
xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]);
yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]);
xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]);
yym = 0.5 * (patch->y[i][1] + patch->y[i][2]);
xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]);
yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]);
xx[i][2] = 0.5 * (xx[i][1] + xxm);
yy[i][2] = 0.5 * (yy[i][1] + yym);
xx[i][5] = 0.5 * (xxm + xx[i][6]);
yy[i][5] = 0.5 * (yym + yy[i][6]);
xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]);
yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]);
xx[i][7] = patch->x[i][3];
yy[i][7] = patch->y[i][3];
}
for (i = 0; i < 4; ++i) {
patch00.x[0][i] = xx[0][i];
patch00.y[0][i] = yy[0][i];
patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]);
patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]);
xxm = 0.5 * (xx[1][i] + xx[2][i]);
yym = 0.5 * (yy[1][i] + yy[2][i]);
patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]);
patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]);
patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm);
patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym);
patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]);
patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]);
patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]);
patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]);
patch10.x[0][i] = patch00.x[3][i];
patch10.y[0][i] = patch00.y[3][i];
patch10.x[3][i] = xx[3][i];
patch10.y[3][i] = yy[3][i];
}
for (i = 4; i < 8; ++i) {
patch01.x[0][i-4] = xx[0][i];
patch01.y[0][i-4] = yy[0][i];
patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]);
patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]);
xxm = 0.5 * (xx[1][i] + xx[2][i]);
yym = 0.5 * (yy[1][i] + yy[2][i]);
patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]);
patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]);
patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm);
patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym);
patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]);
patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]);
patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]);
patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]);
patch11.x[0][i-4] = patch01.x[3][i-4];
patch11.y[0][i-4] = patch01.y[3][i-4];
patch11.x[3][i-4] = xx[3][i];
patch11.y[3][i-4] = yy[3][i];
}
//~ if the shading has a Function, this should interpolate on the
//~ function parameter, not on the color components
for (i = 0; i < nComps; ++i) {
patch00.color[0][0].c[i] = patch->color[0][0].c[i];
patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
patch->color[0][1].c[i]) / 2;
patch01.color[0][0].c[i] = patch00.color[0][1].c[i];
patch01.color[0][1].c[i] = patch->color[0][1].c[i];
patch01.color[1][1].c[i] = (patch->color[0][1].c[i] +
patch->color[1][1].c[i]) / 2;
patch11.color[0][1].c[i] = patch01.color[1][1].c[i];
patch11.color[1][1].c[i] = patch->color[1][1].c[i];
patch11.color[1][0].c[i] = (patch->color[1][1].c[i] +
patch->color[1][0].c[i]) / 2;
patch10.color[1][1].c[i] = patch11.color[1][0].c[i];
patch10.color[1][0].c[i] = patch->color[1][0].c[i];
patch10.color[0][0].c[i] = (patch->color[1][0].c[i] +
patch->color[0][0].c[i]) / 2;
patch00.color[1][0].c[i] = patch10.color[0][0].c[i];
patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] +
patch01.color[1][1].c[i]) / 2;
patch01.color[1][0].c[i] = patch00.color[1][1].c[i];
patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
}
fillPatch(&patch00, nComps, depth + 1);
fillPatch(&patch10, nComps, depth + 1);
fillPatch(&patch01, nComps, depth + 1);
fillPatch(&patch11, nComps, depth + 1);
}
}
void PdfParser::doEndPath() {
if (state->isCurPt() && clip != clipNone) {
state->clip();
if (clip == clipNormal) {
clipHistory->setClip(state->getPath(), clipNormal);
builder->clip(state);
} else {
clipHistory->setClip(state->getPath(), clipEO);
builder->clip(state, true);
}
}
clip = clipNone;
state->clearPath();
}
//------------------------------------------------------------------------
// path clipping operators
//------------------------------------------------------------------------
void PdfParser::opClip(Object /*args*/[], int /*numArgs*/)
{
clip = clipNormal;
}
void PdfParser::opEOClip(Object /*args*/[], int /*numArgs*/)
{
clip = clipEO;
}
//------------------------------------------------------------------------
// text object operators
//------------------------------------------------------------------------
void PdfParser::opBeginText(Object /*args*/[], int /*numArgs*/)
{
state->setTextMat(1, 0, 0, 1, 0, 0);
state->textMoveTo(0, 0);
builder->updateTextPosition(0.0, 0.0);
fontChanged = gTrue;
builder->beginTextObject(state);
}
void PdfParser::opEndText(Object /*args*/[], int /*numArgs*/)
{
builder->endTextObject(state);
}
//------------------------------------------------------------------------
// text state operators
//------------------------------------------------------------------------
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opSetCharSpacing(Object args[], int /*numArgs*/)
{
state->setCharSpace(args[0].getNum());
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opSetFont(Object args[], int /*numArgs*/)
{
GfxFont *font = res->lookupFont(args[0].getName());
if (!font) {
// unsetting the font (drawing no text) is better than using the
// previous one and drawing random glyphs from it
state->setFont(NULL, args[1].getNum());
fontChanged = gTrue;
return;
}
if (printCommands) {
printf(" font: tag=%s name='%s' %g\n",
font->getTag()->getCString(),
font->getName() ? font->getName()->getCString() : "???",
args[1].getNum());
fflush(stdout);
}
font->incRefCnt();
state->setFont(font, args[1].getNum());
fontChanged = gTrue;
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opSetTextLeading(Object args[], int /*numArgs*/)
{
state->setLeading(args[0].getNum());
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opSetTextRender(Object args[], int /*numArgs*/)
{
state->setRender(args[0].getInt());
builder->updateStyle(state);
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opSetTextRise(Object args[], int /*numArgs*/)
{
state->setRise(args[0].getNum());
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opSetWordSpacing(Object args[], int /*numArgs*/)
{
state->setWordSpace(args[0].getNum());
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opSetHorizScaling(Object args[], int /*numArgs*/)
{
state->setHorizScaling(args[0].getNum());
builder->updateTextMatrix(state);
fontChanged = gTrue;
}
//------------------------------------------------------------------------
// text positioning operators
//------------------------------------------------------------------------
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opTextMove(Object args[], int /*numArgs*/)
{
double tx, ty;
tx = state->getLineX() + args[0].getNum();
ty = state->getLineY() + args[1].getNum();
state->textMoveTo(tx, ty);
builder->updateTextPosition(tx, ty);
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opTextMoveSet(Object args[], int /*numArgs*/)
{
double tx, ty;
tx = state->getLineX() + args[0].getNum();
ty = args[1].getNum();
state->setLeading(-ty);
ty += state->getLineY();
state->textMoveTo(tx, ty);
builder->updateTextPosition(tx, ty);
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opSetTextMatrix(Object args[], int /*numArgs*/)
{
state->setTextMat(args[0].getNum(), args[1].getNum(),
args[2].getNum(), args[3].getNum(),
args[4].getNum(), args[5].getNum());
state->textMoveTo(0, 0);
builder->updateTextMatrix(state);
builder->updateTextPosition(0.0, 0.0);
fontChanged = gTrue;
}
void PdfParser::opTextNextLine(Object /*args*/[], int /*numArgs*/)
{
double tx, ty;
tx = state->getLineX();
ty = state->getLineY() - state->getLeading();
state->textMoveTo(tx, ty);
builder->updateTextPosition(tx, ty);
}
//------------------------------------------------------------------------
// text string operators
//------------------------------------------------------------------------
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opShowText(Object args[], int /*numArgs*/)
{
if (!state->getFont()) {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No font in show");
#else
error(getPos(), const_cast<char*>("No font in show"));
#endif
return;
}
if (fontChanged) {
builder->updateFont(state);
fontChanged = gFalse;
}
doShowText(args[0].getString());
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opMoveShowText(Object args[], int /*numArgs*/)
{
double tx = 0;
double ty = 0;
if (!state->getFont()) {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No font in move/show");
#else
error(getPos(), const_cast<char*>("No font in move/show"));
#endif
return;
}
if (fontChanged) {
builder->updateFont(state);
fontChanged = gFalse;
}
tx = state->getLineX();
ty = state->getLineY() - state->getLeading();
state->textMoveTo(tx, ty);
builder->updateTextPosition(tx, ty);
doShowText(args[0].getString());
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opMoveSetShowText(Object args[], int /*numArgs*/)
{
double tx = 0;
double ty = 0;
if (!state->getFont()) {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No font in move/set/show");
#else
error(getPos(), const_cast<char*>("No font in move/set/show"));
#endif
return;
}
if (fontChanged) {
builder->updateFont(state);
fontChanged = gFalse;
}
state->setWordSpace(args[0].getNum());
state->setCharSpace(args[1].getNum());
tx = state->getLineX();
ty = state->getLineY() - state->getLeading();
state->textMoveTo(tx, ty);
builder->updateTextPosition(tx, ty);
doShowText(args[2].getString());
}
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opShowSpaceText(Object args[], int /*numArgs*/)
{
Array *a = 0;
Object obj;
int wMode = 0;
if (!state->getFont()) {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No font in show/space");
#else
error(getPos(), const_cast<char*>("No font in show/space"));
#endif
return;
}
if (fontChanged) {
builder->updateFont(state);
fontChanged = gFalse;
}
wMode = state->getFont()->getWMode();
a = args[0].getArray();
for (int i = 0; i < a->getLength(); ++i) {
a->get(i, &obj);
if (obj.isNum()) {
// this uses the absolute value of the font size to match
// Acrobat's behavior
if (wMode) {
state->textShift(0, -obj.getNum() * 0.001 *
fabs(state->getFontSize()));
} else {
state->textShift(-obj.getNum() * 0.001 *
fabs(state->getFontSize()), 0);
}
builder->updateTextShift(state, obj.getNum());
} else if (obj.isString()) {
doShowText(obj.getString());
} else {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Element of show/space array must be number or string");
#else
error(getPos(), const_cast<char*>("Element of show/space array must be number or string"));
#endif
}
obj.free();
}
}
/*
* The `POPPLER_NEW_GFXFONT' stuff is for the change to GfxFont's getNextChar() call.
* Thanks to tsdgeos for the fix.
* Miklos, does this look ok?
*/
void PdfParser::doShowText(GooString *s) {
GfxFont *font;
int wMode;
double riseX, riseY;
CharCode code;
#ifdef POPPLER_NEW_GFXFONT
Unicode *u = NULL;
#else
Unicode u[8];
#endif
double x, y, dx, dy, tdx, tdy;
double originX, originY, tOriginX, tOriginY;
double oldCTM[6], newCTM[6];
double *mat;
Object charProc;
Dict *resDict;
Parser *oldParser;
char *p;
int len, n, uLen;
font = state->getFont();
wMode = font->getWMode();
builder->beginString(state, s);
// handle a Type 3 char
if (font->getType() == fontType3 && 0) {//out->interpretType3Chars()) {
mat = state->getCTM();
for (int i = 0; i < 6; ++i) {
oldCTM[i] = mat[i];
}
mat = state->getTextMat();
newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
mat = font->getFontMatrix();
newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
newCTM[0] *= state->getFontSize();
newCTM[1] *= state->getFontSize();
newCTM[2] *= state->getFontSize();
newCTM[3] *= state->getFontSize();
newCTM[0] *= state->getHorizScaling();
newCTM[2] *= state->getHorizScaling();
state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
double curX = state->getCurX();
double curY = state->getCurY();
double lineX = state->getLineX();
double lineY = state->getLineY();
oldParser = parser;
p = s->getCString();
len = s->getLength();
while (len > 0) {
n = font->getNextChar(p, len, &code,
#ifdef POPPLER_NEW_GFXFONT
&u, &uLen, /* TODO: This looks like a memory leak for u. */
#else
u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
#endif
&dx, &dy, &originX, &originY);
dx = dx * state->getFontSize() + state->getCharSpace();
if (n == 1 && *p == ' ') {
dx += state->getWordSpace();
}
dx *= state->getHorizScaling();
dy *= state->getFontSize();
state->textTransformDelta(dx, dy, &tdx, &tdy);
state->transform(curX + riseX, curY + riseY, &x, &y);
saveState();
state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
//~ the CTM concat values here are wrong (but never used)
//out->updateCTM(state, 1, 0, 0, 1, 0, 0);
if (0){ /*!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy,
code, u, uLen)) {*/
((Gfx8BitFont *)font)->getCharProc(code, &charProc);
if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
pushResources(resDict);
}
if (charProc.isStream()) {
//parse(&charProc, gFalse); // TODO: parse into SVG font
} else {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Missing or bad Type3 CharProc entry");
#else
error(getPos(), const_cast<char*>("Missing or bad Type3 CharProc entry"));
#endif
}
//out->endType3Char(state);
if (resDict) {
popResources();
}
charProc.free();
}
restoreState();
// GfxState::restore() does *not* restore the current position,
// so we deal with it here using (curX, curY) and (lineX, lineY)
curX += tdx;
curY += tdy;
state->moveTo(curX, curY);
state->textSetPos(lineX, lineY);
p += n;
len -= n;
}
parser = oldParser;
} else {
state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
p = s->getCString();
len = s->getLength();
while (len > 0) {
n = font->getNextChar(p, len, &code,
#ifdef POPPLER_NEW_GFXFONT
&u, &uLen, /* TODO: This looks like a memory leak for u. */
#else
u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
#endif
&dx, &dy, &originX, &originY);
if (wMode) {
dx *= state->getFontSize();
dy = dy * state->getFontSize() + state->getCharSpace();
if (n == 1 && *p == ' ') {
dy += state->getWordSpace();
}
} else {
dx = dx * state->getFontSize() + state->getCharSpace();
if (n == 1 && *p == ' ') {
dx += state->getWordSpace();
}
dx *= state->getHorizScaling();
dy *= state->getFontSize();
}
state->textTransformDelta(dx, dy, &tdx, &tdy);
originX *= state->getFontSize();
originY *= state->getFontSize();
state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
builder->addChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
dx, dy, tOriginX, tOriginY, code, n, u, uLen);
state->shift(tdx, tdy);
p += n;
len -= n;
}
}
builder->endString(state);
}
//------------------------------------------------------------------------
// XObject operators
//------------------------------------------------------------------------
// TODO not good that numArgs is ignored but args[] is used:
void PdfParser::opXObject(Object args[], int /*numArgs*/)
{
Object obj1, obj2, obj3, refObj;
char *name = args[0].getName();
if (!res->lookupXObject(name, &obj1)) {
return;
}
if (!obj1.isStream()) {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "XObject '{0:s}' is wrong type", name);
#else
error(getPos(), const_cast<char*>("XObject '%s' is wrong type"), name);
#endif
obj1.free();
return;
}
obj1.streamGetDict()->lookup(const_cast<char*>("Subtype"), &obj2);
if (obj2.isName(const_cast<char*>("Image"))) {
res->lookupXObjectNF(name, &refObj);
doImage(&refObj, obj1.getStream(), gFalse);
refObj.free();
} else if (obj2.isName(const_cast<char*>("Form"))) {
doForm(&obj1);
} else if (obj2.isName(const_cast<char*>("PS"))) {
obj1.streamGetDict()->lookup(const_cast<char*>("Level1"), &obj3);
/* out->psXObject(obj1.getStream(),
obj3.isStream() ? obj3.getStream() : (Stream *)NULL);*/
} else if (obj2.isName()) {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Unknown XObject subtype '{0:s}'", obj2.getName());
#else
error(getPos(), const_cast<char*>("Unknown XObject subtype '%s'"), obj2.getName());
#endif
} else {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "XObject subtype is missing or wrong type");
#else
error(getPos(), const_cast<char*>("XObject subtype is missing or wrong type"));
#endif
}
obj2.free();
obj1.free();
}
void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg)
{
Dict *dict;
int width, height;
int bits;
StreamColorSpaceMode csMode;
GBool mask;
GBool invert;
Object maskObj, smaskObj;
GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
GBool maskInvert;
Object obj1, obj2;
// get info from the stream
bits = 0;
csMode = streamCSNone;
str->getImageParams(&bits, &csMode);
// get stream dict
dict = str->getDict();
// get size
dict->lookup(const_cast<char*>("Width"), &obj1);
if (obj1.isNull()) {
obj1.free();
dict->lookup(const_cast<char*>("W"), &obj1);
}
if (obj1.isInt()){
width = obj1.getInt();
}
else if (obj1.isReal()) {
width = (int)obj1.getReal();
}
else {
goto err2;
}
obj1.free();
dict->lookup(const_cast<char*>("Height"), &obj1);
if (obj1.isNull()) {
obj1.free();
dict->lookup(const_cast<char*>("H"), &obj1);
}
if (obj1.isInt()) {
height = obj1.getInt();
}
else if (obj1.isReal()){
height = static_cast<int>(obj1.getReal());
}
else {
goto err2;
}
obj1.free();
// image or mask?
dict->lookup(const_cast<char*>("ImageMask"), &obj1);
if (obj1.isNull()) {
obj1.free();
dict->lookup(const_cast<char*>("IM"), &obj1);
}
mask = gFalse;
if (obj1.isBool()) {
mask = obj1.getBool();
}
else if (!obj1.isNull()) {
goto err2;
}
obj1.free();
// bit depth
if (bits == 0) {
dict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
if (obj1.isNull()) {
obj1.free();
dict->lookup(const_cast<char*>("BPC"), &obj1);
}
if (obj1.isInt()) {
bits = obj1.getInt();
} else if (mask) {
bits = 1;
} else {
goto err2;
}
obj1.free();
}
// display a mask
if (mask) {
// check for inverted mask
if (bits != 1) {
goto err1;
}
invert = gFalse;
dict->lookup(const_cast<char*>("Decode"), &obj1);
if (obj1.isNull()) {
obj1.free();
dict->lookup(const_cast<char*>("D"), &obj1);
}
if (obj1.isArray()) {
obj1.arrayGet(0, &obj2);
if (obj2.isInt() && obj2.getInt() == 1) {
invert = gTrue;
}
obj2.free();
} else if (!obj1.isNull()) {
goto err2;
}
obj1.free();
// draw it
builder->addImageMask(state, str, width, height, invert);
} else {
// get color space and color map
GfxColorSpace *colorSpace;
dict->lookup(const_cast<char*>("ColorSpace"), &obj1);
if (obj1.isNull()) {
obj1.free();
dict->lookup(const_cast<char*>("CS"), &obj1);
}
if (obj1.isName()) {
res->lookupColorSpace(obj1.getName(), &obj2);
if (!obj2.isNull()) {
obj1.free();
obj1 = obj2;
} else {
obj2.free();
}
}
if (!obj1.isNull()) {
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
colorSpace = GfxColorSpace::parse(&obj1, NULL);
#else
colorSpace = GfxColorSpace::parse(&obj1);
#endif
} else if (csMode == streamCSDeviceGray) {
colorSpace = new GfxDeviceGrayColorSpace();
} else if (csMode == streamCSDeviceRGB) {
colorSpace = new GfxDeviceRGBColorSpace();
} else if (csMode == streamCSDeviceCMYK) {
colorSpace = new GfxDeviceCMYKColorSpace();
} else {
colorSpace = NULL;
}
obj1.free();
if (!colorSpace) {
goto err1;
}
dict->lookup(const_cast<char*>("Decode"), &obj1);
if (obj1.isNull()) {
obj1.free();
dict->lookup(const_cast<char*>("D"), &obj1);
}
GfxImageColorMap *colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
obj1.free();
if (!colorMap->isOk()) {
delete colorMap;
goto err1;
}
// get the mask
int maskColors[2*gfxColorMaxComps];
haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse;
Stream *maskStr = NULL;
int maskWidth = 0;
int maskHeight = 0;
maskInvert = gFalse;
GfxImageColorMap *maskColorMap = NULL;
dict->lookup(const_cast<char*>("Mask"), &maskObj);
dict->lookup(const_cast<char*>("SMask"), &smaskObj);
Dict* maskDict;
if (smaskObj.isStream()) {
// soft mask
if (inlineImg) {
goto err1;
}
maskStr = smaskObj.getStream();
maskDict = smaskObj.streamGetDict();
maskDict->lookup(const_cast<char*>("Width"), &obj1);
if (obj1.isNull()) {
obj1.free();
maskDict->lookup(const_cast<char*>("W"), &obj1);
}
if (!obj1.isInt()) {
goto err2;
}
maskWidth = obj1.getInt();
obj1.free();
maskDict->lookup(const_cast<char*>("Height"), &obj1);
if (obj1.isNull()) {
obj1.free();
maskDict->lookup(const_cast<char*>("H"), &obj1);
}
if (!obj1.isInt()) {
goto err2;
}
maskHeight = obj1.getInt();
obj1.free();
maskDict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
if (obj1.isNull()) {
obj1.free();
maskDict->lookup(const_cast<char*>("BPC"), &obj1);
}
if (!obj1.isInt()) {
goto err2;
}
int maskBits = obj1.getInt();
obj1.free();
maskDict->lookup(const_cast<char*>("ColorSpace"), &obj1);
if (obj1.isNull()) {
obj1.free();
maskDict->lookup(const_cast<char*>("CS"), &obj1);
}
if (obj1.isName()) {
res->lookupColorSpace(obj1.getName(), &obj2);
if (!obj2.isNull()) {
obj1.free();
obj1 = obj2;
} else {
obj2.free();
}
}
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1, NULL);
#else
GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1);
#endif
obj1.free();
if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
goto err1;
}
maskDict->lookup(const_cast<char*>("Decode"), &obj1);
if (obj1.isNull()) {
obj1.free();
maskDict->lookup(const_cast<char*>("D"), &obj1);
}
maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
obj1.free();
if (!maskColorMap->isOk()) {
delete maskColorMap;
goto err1;
}
//~ handle the Matte entry
haveSoftMask = gTrue;
} else if (maskObj.isArray()) {
// color key mask
int i;
for (i = 0; i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps; ++i) {
maskObj.arrayGet(i, &obj1);
maskColors[i] = obj1.getInt();
obj1.free();
}
haveColorKeyMask = gTrue;
} else if (maskObj.isStream()) {
// explicit mask
if (inlineImg) {
goto err1;
}
maskStr = maskObj.getStream();
maskDict = maskObj.streamGetDict();
maskDict->lookup(const_cast<char*>("Width"), &obj1);
if (obj1.isNull()) {
obj1.free();
maskDict->lookup(const_cast<char*>("W"), &obj1);
}
if (!obj1.isInt()) {
goto err2;
}
maskWidth = obj1.getInt();
obj1.free();
maskDict->lookup(const_cast<char*>("Height"), &obj1);
if (obj1.isNull()) {
obj1.free();
maskDict->lookup(const_cast<char*>("H"), &obj1);
}
if (!obj1.isInt()) {
goto err2;
}
maskHeight = obj1.getInt();
obj1.free();
maskDict->lookup(const_cast<char*>("ImageMask"), &obj1);
if (obj1.isNull()) {
obj1.free();
maskDict->lookup(const_cast<char*>("IM"), &obj1);
}
if (!obj1.isBool() || !obj1.getBool()) {
goto err2;
}
obj1.free();
maskInvert = gFalse;
maskDict->lookup(const_cast<char*>("Decode"), &obj1);
if (obj1.isNull()) {
obj1.free();
maskDict->lookup(const_cast<char*>("D"), &obj1);
}
if (obj1.isArray()) {
obj1.arrayGet(0, &obj2);
if (obj2.isInt() && obj2.getInt() == 1) {
maskInvert = gTrue;
}
obj2.free();
} else if (!obj1.isNull()) {
goto err2;
}
obj1.free();
haveExplicitMask = gTrue;
}
// draw it
if (haveSoftMask) {
builder->addSoftMaskedImage(state, str, width, height, colorMap,
maskStr, maskWidth, maskHeight, maskColorMap);
delete maskColorMap;
} else if (haveExplicitMask) {
builder->addMaskedImage(state, str, width, height, colorMap,
maskStr, maskWidth, maskHeight, maskInvert);
} else {
builder->addImage(state, str, width, height, colorMap,
haveColorKeyMask ? maskColors : static_cast<int *>(NULL));
}
delete colorMap;
maskObj.free();
smaskObj.free();
}
return;
err2:
obj1.free();
err1:
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Bad image parameters");
#else
error(getPos(), const_cast<char*>("Bad image parameters"));
#endif
}
void PdfParser::doForm(Object *str) {
Dict *dict;
GBool transpGroup, isolated, knockout;
GfxColorSpace *blendingColorSpace;
Object matrixObj, bboxObj;
double m[6], bbox[4];
Object resObj;
Dict *resDict;
Object obj1, obj2, obj3;
int i;
// check for excessive recursion
if (formDepth > 20) {
return;
}
// get stream dict
dict = str->streamGetDict();
// check form type
dict->lookup(const_cast<char*>("FormType"), &obj1);
if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Unknown form type");
#else
error(getPos(), const_cast<char*>("Unknown form type"));
#endif
}
obj1.free();
// get bounding box
dict->lookup(const_cast<char*>("BBox"), &bboxObj);
if (!bboxObj.isArray()) {
bboxObj.free();
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Bad form bounding box");
#else
error(getPos(), const_cast<char*>("Bad form bounding box"));
#endif
return;
}
for (i = 0; i < 4; ++i) {
bboxObj.arrayGet(i, &obj1);
bbox[i] = obj1.getNum();
obj1.free();
}
bboxObj.free();
// get matrix
dict->lookup(const_cast<char*>("Matrix"), &matrixObj);
if (matrixObj.isArray()) {
for (i = 0; i < 6; ++i) {
matrixObj.arrayGet(i, &obj1);
m[i] = obj1.getNum();
obj1.free();
}
} else {
m[0] = 1; m[1] = 0;
m[2] = 0; m[3] = 1;
m[4] = 0; m[5] = 0;
}
matrixObj.free();
// get resources
dict->lookup(const_cast<char*>("Resources"), &resObj);
resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
// check for a transparency group
transpGroup = isolated = knockout = gFalse;
blendingColorSpace = NULL;
if (dict->lookup(const_cast<char*>("Group"), &obj1)->isDict()) {
if (obj1.dictLookup(const_cast<char*>("S"), &obj2)->isName(const_cast<char*>("Transparency"))) {
transpGroup = gTrue;
if (!obj1.dictLookup(const_cast<char*>("CS"), &obj3)->isNull()) {
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
blendingColorSpace = GfxColorSpace::parse(&obj3, NULL);
#else
blendingColorSpace = GfxColorSpace::parse(&obj3);
#endif
}
obj3.free();
if (obj1.dictLookup(const_cast<char*>("I"), &obj3)->isBool()) {
isolated = obj3.getBool();
}
obj3.free();
if (obj1.dictLookup(const_cast<char*>("K"), &obj3)->isBool()) {
knockout = obj3.getBool();
}
obj3.free();
}
obj2.free();
}
obj1.free();
// draw it
++formDepth;
doForm1(str, resDict, m, bbox,
transpGroup, gFalse, blendingColorSpace, isolated, knockout);
--formDepth;
if (blendingColorSpace) {
delete blendingColorSpace;
}
resObj.free();
}
void PdfParser::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
GBool transpGroup, GBool softMask,
GfxColorSpace *blendingColorSpace,
GBool isolated, GBool knockout,
GBool alpha, Function *transferFunc,
GfxColor *backdropColor) {
Parser *oldParser;
double oldBaseMatrix[6];
int i;
// push new resources on stack
pushResources(resDict);
// save current graphics state
saveState();
// kill any pre-existing path
state->clearPath();
if (softMask || transpGroup) {
builder->clearSoftMask(state);
builder->pushTransparencyGroup(state, bbox, blendingColorSpace,
isolated, knockout, softMask);
}
// save current parser
oldParser = parser;
// set form transformation matrix
state->concatCTM(matrix[0], matrix[1], matrix[2],
matrix[3], matrix[4], matrix[5]);
builder->setTransform(matrix[0], matrix[1], matrix[2],
matrix[3], matrix[4], matrix[5]);
// set form bounding box
state->moveTo(bbox[0], bbox[1]);
state->lineTo(bbox[2], bbox[1]);
state->lineTo(bbox[2], bbox[3]);
state->lineTo(bbox[0], bbox[3]);
state->closePath();
state->clip();
clipHistory->setClip(state->getPath());
builder->clip(state);
state->clearPath();
if (softMask || transpGroup) {
if (state->getBlendMode() != gfxBlendNormal) {
state->setBlendMode(gfxBlendNormal);
}
if (state->getFillOpacity() != 1) {
builder->setGroupOpacity(state->getFillOpacity());
state->setFillOpacity(1);
}
if (state->getStrokeOpacity() != 1) {
state->setStrokeOpacity(1);
}
}
// set new base matrix
for (i = 0; i < 6; ++i) {
oldBaseMatrix[i] = baseMatrix[i];
baseMatrix[i] = state->getCTM()[i];
}
// draw the form
parse(str, gFalse);
// restore base matrix
for (i = 0; i < 6; ++i) {
baseMatrix[i] = oldBaseMatrix[i];
}
// restore parser
parser = oldParser;
if (softMask || transpGroup) {
builder->popTransparencyGroup(state);
}
// restore graphics state
restoreState();
// pop resource stack
popResources();
if (softMask) {
builder->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
} else if (transpGroup) {
builder->paintTransparencyGroup(state, bbox);
}
return;
}
//------------------------------------------------------------------------
// in-line image operators
//------------------------------------------------------------------------
void PdfParser::opBeginImage(Object /*args*/[], int /*numArgs*/)
{
// build dict/stream
Stream *str = buildImageStream();
// display the image
if (str) {
doImage(NULL, str, gTrue);
// skip 'EI' tag
int c1 = str->getUndecodedStream()->getChar();
int c2 = str->getUndecodedStream()->getChar();
while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
c1 = c2;
c2 = str->getUndecodedStream()->getChar();
}
delete str;
}
}
Stream *PdfParser::buildImageStream() {
Object dict;
Object obj;
char *key;
Stream *str;
// build dictionary
dict.initDict(xref);
parser->getObj(&obj);
while (!obj.isCmd(const_cast<char*>("ID")) && !obj.isEOF()) {
if (!obj.isName()) {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Inline image dictionary key must be a name object");
#else
error(getPos(), const_cast<char*>("Inline image dictionary key must be a name object"));
#endif
obj.free();
} else {
key = copyString(obj.getName());
obj.free();
parser->getObj(&obj);
if (obj.isEOF() || obj.isError()) {
gfree(key);
break;
}
dict.dictAdd(key, &obj);
}
parser->getObj(&obj);
}
if (obj.isEOF()) {
#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "End of file in inline image");
#else
error(getPos(), const_cast<char*>("End of file in inline image"));
#endif
obj.free();
dict.free();
return NULL;
}
obj.free();
// make stream
str = new EmbedStream(parser->getStream(), &dict, gFalse, 0);
str = str->addFilters(&dict);
return str;
}
void PdfParser::opImageData(Object /*args*/[], int /*numArgs*/)
{
#ifdef POPPLER_NEW_ERRORAPI
error(errInternal, getPos(), "Internal: got 'ID' operator");
#else
error(getPos(), const_cast<char*>("Internal: got 'ID' operator"));
#endif
}
void PdfParser::opEndImage(Object /*args*/[], int /*numArgs*/)
{
#ifdef POPPLER_NEW_ERRORAPI
error(errInternal, getPos(), "Internal: got 'EI' operator");
#else
error(getPos(), const_cast<char*>("Internal: got 'EI' operator"));
#endif
}
//------------------------------------------------------------------------
// type 3 font operators
//------------------------------------------------------------------------
void PdfParser::opSetCharWidth(Object /*args*/[], int /*numArgs*/)
{
}
void PdfParser::opSetCacheDevice(Object /*args*/[], int /*numArgs*/)
{
}
//------------------------------------------------------------------------
// compatibility operators
//------------------------------------------------------------------------
void PdfParser::opBeginIgnoreUndef(Object /*args*/[], int /*numArgs*/)
{
++ignoreUndef;
}
void PdfParser::opEndIgnoreUndef(Object /*args*/[], int /*numArgs*/)
{
if (ignoreUndef > 0)
--ignoreUndef;
}
//------------------------------------------------------------------------
// marked content operators
//------------------------------------------------------------------------
void PdfParser::opBeginMarkedContent(Object args[], int numArgs) {
if (printCommands) {
printf(" marked content: %s ", args[0].getName());
if (numArgs == 2)
args[2].print(stdout);
printf("\n");
fflush(stdout);
}
if(numArgs == 2) {
//out->beginMarkedContent(args[0].getName(),args[1].getDict());
} else {
//out->beginMarkedContent(args[0].getName());
}
}
void PdfParser::opEndMarkedContent(Object /*args*/[], int /*numArgs*/)
{
//out->endMarkedContent();
}
void PdfParser::opMarkPoint(Object args[], int numArgs) {
if (printCommands) {
printf(" mark point: %s ", args[0].getName());
if (numArgs == 2)
args[2].print(stdout);
printf("\n");
fflush(stdout);
}
if(numArgs == 2) {
//out->markPoint(args[0].getName(),args[1].getDict());
} else {
//out->markPoint(args[0].getName());
}
}
//------------------------------------------------------------------------
// misc
//------------------------------------------------------------------------
void PdfParser::saveState() {
bool is_radial = false;
GfxPattern *pattern = state->getFillPattern();
if (pattern != NULL)
if (pattern->getType() == 2 ) {
GfxShadingPattern *shading_pattern = static_cast<GfxShadingPattern *>(pattern);
GfxShading *shading = shading_pattern->getShading();
if (shading->getType() == 3)
is_radial = true;
}
builder->saveState();
if (is_radial)
state->save(); // nasty hack to prevent GfxRadialShading from getting corrupted during copy operation
else
state = state->save(); // see LP Bug 919176 comment 8
clipHistory = clipHistory->save();
}
void PdfParser::restoreState() {
clipHistory = clipHistory->restore();
state = state->restore();
builder->restoreState();
}
void PdfParser::pushResources(Dict *resDict) {
res = new GfxResources(xref, resDict, res);
}
void PdfParser::popResources() {
GfxResources *resPtr;
resPtr = res->getNext();
delete res;
res = resPtr;
}
void PdfParser::setDefaultApproximationPrecision() {
int i;
for (i = 1; i <= pdfNumShadingTypes; ++i) {
setApproximationPrecision(i, defaultShadingColorDelta, defaultShadingMaxDepth);
}
}
void PdfParser::setApproximationPrecision(int shadingType, double colorDelta,
int maxDepth) {
if (shadingType > pdfNumShadingTypes || shadingType < 1) {
return;
}
colorDeltas[shadingType-1] = dblToCol(colorDelta);
maxDepths[shadingType-1] = maxDepth;
}
//------------------------------------------------------------------------
// ClipHistoryEntry
//------------------------------------------------------------------------
ClipHistoryEntry::ClipHistoryEntry(GfxPath *clipPathA, GfxClipType clipTypeA) {
if (clipPathA) {
clipPath = clipPathA->copy();
} else {
clipPath = NULL;
}
clipType = clipTypeA;
saved = NULL;
}
ClipHistoryEntry::~ClipHistoryEntry() {
if (clipPath) {
delete clipPath;
}
}
void ClipHistoryEntry::setClip(GfxPath *clipPathA, GfxClipType clipTypeA) {
// Free previous clip path
if (clipPath) {
delete clipPath;
}
if (clipPathA) {
clipPath = clipPathA->copy();
clipType = clipTypeA;
} else {
clipPath = NULL;
}
}
ClipHistoryEntry *ClipHistoryEntry::save() {
ClipHistoryEntry *newEntry = new ClipHistoryEntry(this);
newEntry->saved = this;
return newEntry;
}
ClipHistoryEntry *ClipHistoryEntry::restore() {
ClipHistoryEntry *oldEntry;
if (saved) {
oldEntry = saved;
saved = NULL;
delete this;
} else {
oldEntry = this;
}
return oldEntry;
}
ClipHistoryEntry::ClipHistoryEntry(ClipHistoryEntry *other) {
if (other->clipPath) {
this->clipPath = other->clipPath->copy();
this->clipType = other->clipType;
} else {
this->clipPath = NULL;
}
saved = NULL;
}
#endif /* HAVE_POPPLER */