From 722cce25e5d4583ce44e9cb8261a49a44eeda2ba Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 2 Mar 2005 23:20:44 +0000 Subject: [PATCH 001/245] Do not start kttsd only to see if we can use it, use ktrader for that. Only start kttsd when the user really ask for a text to be spoken. Same patch as the one sent to core-devel + a i18n() we are not allowed to backport svn path=/trunk/kdegraphics/kpdf/; revision=394483 --- part.cpp | 7 +++---- ui/pageview.cpp | 46 ++++++++++++++++++++++++++++++---------------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/part.cpp b/part.cpp index 4b5c2e692..1c1ad7924 100644 --- a/part.cpp +++ b/part.cpp @@ -49,6 +49,7 @@ #include #include #include +#include // local includes #include "xpdf/GlobalParams.h" @@ -251,10 +252,8 @@ Part::Part(QWidget *parentWidget, const char *widgetName, connect( m_dirtyHandler, SIGNAL( timeout() ),this, SLOT( slotDoFileDirty() ) ); // [SPEECH] check for KTTSD presence and usability - Settings::setUseKTTSD( true ); - if ( !kapp->dcopClient()->isApplicationRegistered("kttsd") ) - if ( KApplication::startServiceByDesktopName( "kttsd" ) ) - Settings::setUseKTTSD( false ); + KTrader::OfferList offers = KTrader::self()->query("DCOP/Text-to-Speech", "Name == 'KTTSD'"); + Settings::setUseKTTSD( (offers.count() > 0) ); // set our XML-UI resource file setXMLFile("part.rc"); diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 920b5b4b6..36b6ca414 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include // system includes @@ -1039,23 +1040,36 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) DCOPClient * client = DCOPClient::mainClient(); // Albert says is this ever necessary? // we already attached on Part constructor - if ( !client->isAttached() ) - client->attach(); - // serialize the text to speech (selectedText) and the - // preferred reader ("" is the default voice) ... - QByteArray data; - QDataStream arg( data, IO_WriteOnly ); - arg << selectedText; - arg << QString(); - QCString replyType; - QByteArray replyData; - // ..and send it to KTTSD - if (client->call( "kttsd", "KSpeech", "setText(QString,QString)", data, replyType, replyData, true )) + // if ( !client->isAttached() ) + // client->attach(); + // If KTTSD not running, start it. + if (!client->isApplicationRegistered("kttsd")) { - QByteArray data2; - QDataStream arg2(data2, IO_WriteOnly); - arg2 << 0; - client->send("kttsd", "KSpeech", "startText(uint)", data2 ); + QString error; + if (KApplication::startServiceByDesktopName("kttsd", QStringList(), &error)) + { + d->messageWindow->display( i18n("Starting KTTSD Failed: %1").arg(error) ); + Settings::setUseKTTSD(false); + } + } + if ( Settings::useKTTSD() ) + { + // serialize the text to speech (selectedText) and the + // preferred reader ("" is the default voice) ... + QByteArray data; + QDataStream arg( data, IO_WriteOnly ); + arg << selectedText; + arg << QString(); + QCString replyType; + QByteArray replyData; + // ..and send it to KTTSD + if (client->call( "kttsd", "KSpeech", "setText(QString,QString)", data, replyType, replyData, true )) + { + QByteArray data2; + QDataStream arg2(data2, IO_WriteOnly); + arg2 << 0; + client->send("kttsd", "KSpeech", "startText(uint)", data2 ); + } } } } From 1d36b9a0907d6750056d2bb7bece7e2d5045270f Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 3 Mar 2005 21:38:45 +0000 Subject: [PATCH 002/245] Compile on Solaris BUGS: 100767 svn path=/trunk/kdegraphics/kpdf/; revision=394700 --- xpdf/xpdf/GlobalParams.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index a454014f1..351f28102 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -13,6 +13,7 @@ #endif #include +#include // KPDF: additional includes for Qt and Xft #include #include From 764fd6cf284cdb367c0c1fb6dca42379bae1fbfb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 4 Mar 2005 17:22:16 +0000 Subject: [PATCH 003/245] Fix compile on Solaris svn path=/trunk/kdegraphics/kpdf/; revision=394901 --- ui/pageview.cpp | 2 +- ui/presentationwidget.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 36b6ca414..30b3f61b4 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -1500,7 +1500,7 @@ void PageView::slotRelayoutPages() // Here we find out column's width and row's height to compute a table // so we can place widgets 'centered in virtual cells'. int nCols = Settings::viewColumns(), - nRows = (int)ceilf( (float)pageCount / (float)nCols ), + nRows = (int)ceil( (float)pageCount / (float)nCols ), * colWidth = new int[ nCols ], * rowHeight = new int[ nRows ], cIdx = 0, diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index 1980006b7..a414282af 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -320,7 +320,7 @@ void PresentationWidget::overlayClick( const QPoint & position ) return; // compute angle relative to indicator (note coord transformation) - float angle = 0.5 + 0.5 * atan2f( -xPos, -yPos ) / M_PI; + float angle = 0.5 + 0.5 * atan2( -xPos, -yPos ) / M_PI; int pageIndex = (int)( angle * ( m_frames.count() - 1 ) + 0.5 ); // go to selected page From 1ba32eb82e6275c589c70114fab5cc6a8b9d7af3 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 5 Mar 2005 13:23:43 +0000 Subject: [PATCH 004/245] Fix 100881 svn path=/trunk/kdegraphics/kpdf/; revision=395030 --- ui/pageview.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 30b3f61b4..e0ea19968 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -834,7 +834,12 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) { // don't perform any mouse action when no document is shown if ( d->items.isEmpty() ) + { + // ..except for right Clicks (emitted even it viewport is empty) + if ( e->button() == RightButton ) + emit rightClick( 0, e->globalPos() ); return; + } // don't perform any mouse action when viewport is autoscrolling if ( d->viewportMoveActive ) From 620d54f9d46da6498957c7f14a9ec0e1da5685a3 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 5 Mar 2005 14:03:45 +0000 Subject: [PATCH 005/245] Increase version to 0.5 svn path=/trunk/kdegraphics/kpdf/; revision=395036 --- VERSION | 2 +- shell/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 055d46a44..9e9bc1dd3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -KPDF v0.4 +KPDF v0.5 diff --git a/shell/main.cpp b/shell/main.cpp index a95fbbcf5..de73825a8 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -21,7 +21,7 @@ static const char description[] = I18N_NOOP("kpdf, a kde pdf viewer based on xpdf"); -static const char version[] = "0.4"; +static const char version[] = "0.5"; static KCmdLineOptions options[] = { From 39f8e14d238158bfd7ebf9ef9365fa898ee7badb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 5 Mar 2005 17:20:41 +0000 Subject: [PATCH 006/245] Branchport fuzzy search (google like) and kwallet support for storing passwords from kpdf_annotations branch to HEAD. Enrico can you check that i have ported all the necessary bits? svn path=/trunk/kdegraphics/kpdf/; revision=395089 --- TODO | 4 +- core/document.cpp | 72 ++++++++++++++++++++++++++- core/document.h | 3 +- core/generator_pdf/generator_pdf.cpp | 57 ++++++++++++++++----- ui/searchwidget.cpp | 74 +++++++++++++++++----------- ui/searchwidget.h | 5 +- 6 files changed, 167 insertions(+), 48 deletions(-) diff --git a/TODO b/TODO index 84f73c977..91e367a5a 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,6 @@ In progress: -- 2005-Feb-26: Merge from 'kpdf_annotations' branch -- More items (first items will enter 'In progress list' first): --> search: google search in the page -> pageview: add scrollbar marks for bookmarks (like kate) -> screen editing (annotations): framework (BR67300,BR62793) -> screen editing (annotations): tools (BR67300), yellow notes 'post-it' like @@ -65,7 +64,6 @@ More items (first items will enter 'In progress list' first): -> investigate 'Splash' lack of smoothness at low resolutions (see lines in thumbnails) -> add search on the toc widget (a 'prune on type' lineedit like in thumbnails widget) -> goto 'logical' page (usually differs from pdf's page) (req. by Luca Burrelli) --> use wallet for storing passwords of encrypted files -> use shortcuts for next and prev page even in presenatation mode (by Tobias Koenig) -> move some document related features from part to the document (see find, goto dialog, ...) -> Albert: Read pdf specification and see if paths with length = 1 are allowed, in case they are allowed see how to fix 97131 without skipping paths with length = 1 @@ -75,6 +73,8 @@ More items (first items will enter 'In progress list' first): Done (newest features come first): -- merging from kdpf_annotations branch -- +-> ADD: google-like search on thumbnails +-> ADD: use kde wallet for storing passwords of protected files -> ADD: Obey DRM is now a configuration option -> FIX: leakfix when closing document while thread was running (no more leaks now) -> FIX: direct hi-performance pixels manipulation for highlighting (instead of the obsoleted setRasterOp) diff --git a/core/document.cpp b/core/document.cpp index e07bbb96c..57ae13da9 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -735,9 +735,77 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar else if ( type == PrevMatch ) { } - // 4. GOOGLELIKE //TODO - else if ( type == GoogleLike ) + // 4. GOOGLE* - process all document marking pages + else if ( type == GoogleAll || type == GoogleAny ) { + // search and highlight every word in 'text' on all pages + bool matchAll = type == GoogleAll; + QStringList words = QStringList::split( " ", text ); + int wordsCount = words.count(), + hueStep = (wordsCount > 1) ? (60 / (wordsCount - 1)) : 60, + baseHue, baseSat, baseVal; + color.getHsv( &baseHue, &baseSat, &baseVal ); + QValueVector< KPDFPage * >::iterator it = pages_vector.begin(), end = pages_vector.end(); + for ( ; it != end; ++it ) + { + // get page (from the first to the last) + KPDFPage * page = *it; + int pageNumber = page->number(); + + // request search page if needed + if ( !page->hasSearchPage() ) + requestTextPage( pageNumber ); + + // loop on a page adding highlights for all found items + bool allMatched = wordsCount > 0, + anyMatched = false; + for ( int w = 0; w < wordsCount; w++ ) + { + QString word = words[ w ]; + int newHue = baseHue - w * hueStep; + if ( newHue < 0 ) + newHue += 360; + QColor wordColor = QColor( newHue, baseSat, baseVal, QColor::Hsv ); + NormalizedRect * lastMatch = 0; + // add all highlights for current word + bool wordMatched = false; + while ( 1 ) + { + if ( lastMatch ) + lastMatch = page->findText( word, caseSensitive, lastMatch ); + else + lastMatch = page->findText( word, caseSensitive ); + + if ( !lastMatch ) + break; + + // add highligh rect to the page + page->setHighlight( searchID, lastMatch, wordColor ); + wordMatched = true; + } + allMatched = allMatched && wordMatched; + anyMatched = anyMatched || wordMatched; + } + + // if not all words are present in page, remove partial highlights + if ( !allMatched && matchAll ) + page->deleteHighlights( searchID ); + + // if page contains all words, udpate internals and queue page for notify + if ( (allMatched && matchAll) || (anyMatched && !matchAll) ) + { + foundAMatch = true; + s->highlightedPages.append( pageNumber ); + if ( !pagesToNotify.contains( pageNumber ) ) + pagesToNotify.append( pageNumber ); + } + } + + // reset cursor to previous shape + QApplication::restoreOverrideCursor(); + + // send page lists to update observers (since some filter on bookmarks) + foreachObserver( notifySetup( pages_vector, false ) ); } // notify observers about highlights changes diff --git a/core/document.h b/core/document.h index 00a6db380..574437516 100644 --- a/core/document.h +++ b/core/document.h @@ -62,7 +62,6 @@ class KPDFDocument : public QObject // enum definitions enum Permission { AllowModify = 1, AllowCopy = 2, AllowPrint = 4, AllowNotes = 8 }; - enum SearchType { NextMatch, PrevMatch, AllDoc, GoogleLike }; // query methods (const ones) bool isOpened() const; @@ -84,6 +83,8 @@ class KPDFDocument : public QObject void setNextViewport(); void requestPixmaps( const QValueList< PixmapRequest * > & requests ); void requestTextPage( uint page ); + + enum SearchType { NextMatch, PrevMatch, AllDoc, GoogleAll, GoogleAny }; bool searchText( int searchID, const QString & text, bool fromStart, bool caseSensitive, SearchType type, bool moveViewport, const QColor & color, bool noDialogs = false ); bool continueSearch( int searchID ); diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 1f8016289..330e6b557 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -87,7 +88,7 @@ PDFGenerator::~PDFGenerator() //BEGIN Generator inherited functions -bool PDFGenerator::loadDocument( const QString & fileName, QValueVector & pagesVector ) +bool PDFGenerator::loadDocument( const QString & filePath, QValueVector & pagesVector ) { #ifndef NDEBUG if ( pdfdoc ) @@ -97,28 +98,62 @@ bool PDFGenerator::loadDocument( const QString & fileName, QValueVectorisOk() && pdfdoc->getErrorCode() == errEncrypted ) { + QCString password; + + // 1.A. try to retrieve the first password from the kde wallet system + if ( !triedWallet ) + { + QString walletName = KWallet::Wallet::NetworkWallet(); + wallet = KWallet::Wallet::openWallet( walletName ); + if ( wallet ) + { + // use the KPdf folder (and create if missing) + if ( !wallet->hasFolder( "KPdf" ) ) + wallet->createFolder( "KPdf" ); + wallet->setFolder( "KPdf" ); + + // look for the pass in that folder + QString retrievedPass; + if ( !wallet->readPassword( filePath.section('/', -1, -1), retrievedPass ) ) + password = retrievedPass.local8Bit(); + } + triedWallet = true; + } + + // 1.B. if not retrieved, ask the password using the kde password dialog + if ( password.isNull() ) + { QString prompt; - if ( firstTry ) + if ( firstInput ) prompt = i18n( "Please insert the password to read the document:" ); else prompt = i18n( "Incorrect password. Try again:" ); - firstTry = false; + firstInput = false; - QCString pwd; - if ( KPasswordDialog::getPassword( pwd, prompt ) != KPasswordDialog::Accepted ) + // if the user presses cancel, abort opening + if ( KPasswordDialog::getPassword( password, prompt ) != KPasswordDialog::Accepted ) break; - else - { - GString * pwd2 = new GString( pwd.data() ); + } + + // 2. reopen the document using the password + GString * pwd2 = new GString( password.data() ); delete pdfdoc; - pdfdoc = new PDFDoc( new GString( QFile::encodeName( fileName ) ), pwd2, pwd2 ); + pdfdoc = new PDFDoc( new GString( QFile::encodeName( filePath ) ), pwd2, pwd2 ); delete pwd2; + + // 3. if the password is correct, store it to the wallet + if ( pdfdoc->isOk() && wallet && /*safety check*/ wallet->isOpen() ) + { + QString goodPass = QString::fromLocal8Bit( password.data() ); + wallet->writePassword( filePath.section('/', -1, -1), goodPass ); } } if ( !pdfdoc->isOk() ) diff --git a/ui/searchwidget.cpp b/ui/searchwidget.cpp index d510b8778..90ebcd990 100644 --- a/ui/searchwidget.cpp +++ b/ui/searchwidget.cpp @@ -24,14 +24,13 @@ #include "core/document.h" #include "conf/settings.h" -// uncomment following to enable the case switching button -//#define SW_ENABLE_CASE_BUTTON #define CLEAR_ID 1 #define LEDIT_ID 2 #define FIND_ID 3 SearchWidget::SearchWidget( QWidget * parent, KPDFDocument * document ) - : KToolBar( parent, "iSearchBar" ), m_document( document ), m_caseSensitive( false ) + : KToolBar( parent, "iSearchBar" ), m_document( document ), + m_searchType( 0 ), m_caseSensitive( false ) { // change toolbar appearance setMargin( 3 ); @@ -44,31 +43,31 @@ SearchWidget::SearchWidget( QWidget * parent, KPDFDocument * document ) connect( m_inputDelayTimer, SIGNAL( timeout() ), this, SLOT( startSearch() ) ); - // line edit + // 1. text line insertLined( QString::null, LEDIT_ID, SIGNAL( textChanged(const QString &) ), this, SLOT( slotTextChanged(const QString &) ), true, i18n( "Enter at least 3 letters to filter pages" ), 0/*size*/, 1 ); - // clear button (uses a lineEdit slot, so it must be created after) + // 2. clear button (uses a lineEdit slot, so it must be created after) insertButton( QApplication::reverseLayout() ? "clear_left" : "locationbar_erase", CLEAR_ID, SIGNAL( clicked() ), getLined( LEDIT_ID ), SLOT( clear() ), true, i18n( "Clear filter" ), 0/*index*/ ); -#ifdef SW_ENABLE_CASE_BUTTON - // create popup menu for change case button - m_caseMenu = new KPopupMenu( this ); - m_caseMenu->insertItem( i18n("Case Insensitive"), 1 ); - m_caseMenu->insertItem( i18n("Case Sensitive"), 2 ); - m_caseMenu->setItemChecked( 1, true ); - connect( m_caseMenu, SIGNAL( activated(int) ), SLOT( slotCaseChanged(int) ) ); + // 3.1. create the popup menu for changing filtering features + m_menu = new KPopupMenu( this ); + m_menu->insertItem( i18n("Case Sensitive"), 1 ); + m_menu->insertSeparator( 2 ); + m_menu->insertItem( i18n("Match Phrase"), 3 ); + m_menu->insertItem( i18n("Match All Words"), 4 ); + m_menu->insertItem( i18n("Match Any Word"), 5 ); + m_menu->setItemChecked( 3, true ); + connect( m_menu, SIGNAL( activated(int) ), SLOT( slotMenuChaged(int) ) ); - // create the change case button - insertButton( "find", FIND_ID, m_caseMenu, true, - i18n( "Change Case" ), 2/*index*/ ); -#endif + // 3.2. create the toolbar button that spawns the popup menu + insertButton( "kpdf", FIND_ID, m_menu, true, i18n( "Filter Options" ), 2/*index*/ ); - // setStretchableWidget( lineEditWidget ); + // always maximize the text line setItemAutoSized( LEDIT_ID ); } @@ -88,13 +87,40 @@ void SearchWidget::slotTextChanged( const QString & text ) m_inputDelayTimer->start(333, true); } +void SearchWidget::slotMenuChaged( int index ) +{ + // update internal variables and checked state + if ( index == 1 ) + { + m_caseSensitive = !m_caseSensitive; + m_menu->setItemChecked( 1, m_caseSensitive ); + } + else if ( index >= 3 && index <= 5 ) + { + m_searchType = index - 3; + for ( int i = 0; i < 3; i++ ) + m_menu->setItemChecked( i + 3, m_searchType == i ); + } + else + return; + + // update search + slotTextChanged( getLined( LEDIT_ID )->text() ); +} + void SearchWidget::startSearch() { // search text if have more than 3 chars or else clear search QString text = getLined( LEDIT_ID )->text(); bool ok = true; if ( text.length() >= 3 ) - ok = m_document->searchText( SW_SEARCH_ID, text, true, m_caseSensitive, KPDFDocument::AllDoc, false, qRgb( 0, 183, 255 ) ); + { + KPDFDocument::SearchType type = !m_searchType ? KPDFDocument::AllDoc : + ( (m_searchType > 1) ? KPDFDocument::GoogleAny : + KPDFDocument::GoogleAll ); + ok = m_document->searchText( SW_SEARCH_ID, text, true, m_caseSensitive, + type, false, qRgb( 0, 183, 255 ) ); + } else m_document->resetSearch( SW_SEARCH_ID ); // if not found, use warning colors @@ -106,16 +132,4 @@ void SearchWidget::startSearch() } } -void SearchWidget::slotCaseChanged( int index ) -{ - bool newState = (index == 2); - if ( newState != m_caseSensitive ) - { - m_caseSensitive = newState; - m_caseMenu->setItemChecked( 1, !m_caseSensitive ); - m_caseMenu->setItemChecked( 2, m_caseSensitive ); - slotTextChanged( getLined( LEDIT_ID )->text() ); - } -} - #include "searchwidget.moc" diff --git a/ui/searchwidget.h b/ui/searchwidget.h index 3bc192a3b..9f2a1e443 100644 --- a/ui/searchwidget.h +++ b/ui/searchwidget.h @@ -36,13 +36,14 @@ class SearchWidget : public KToolBar private: KPDFDocument * m_document; - KPopupMenu * m_caseMenu; + KPopupMenu * m_menu; QTimer * m_inputDelayTimer; + int m_searchType; bool m_caseSensitive; private slots: void slotTextChanged( const QString & text ); - void slotCaseChanged( int index ); + void slotMenuChaged( int index ); void startSearch(); }; From 05a5b37c7a77da3cf483ed7154c28624219375e0 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 8 Mar 2005 09:10:28 +0000 Subject: [PATCH 007/245] * Use fontconfig for searching CID Fonts too if no font is found the xpdf way * Don't parse "MS-Micho" to fontname "MS" and style "Mincho" * Apply patch given at 100551 that fixes crash on 101032 when the font was found, thanks LuRan for providing the patch * Stephan can you try it does not crashes there and then send a screenshot to the SuSe reported to see if what we display is the correct thing * Will backport when i'm sure the introduced patch does not causes any side effect BUGS: 101032, 100551 svn path=/trunk/kdegraphics/kpdf/; revision=395687 --- xpdf/xpdf/CharCodeToUnicode.h | 4 +++ xpdf/xpdf/GlobalParams.cc | 3 +++ xpdf/xpdf/SplashOutputDev.cc | 51 ++++++++++++++++++++++++++++++----- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/xpdf/xpdf/CharCodeToUnicode.h b/xpdf/xpdf/CharCodeToUnicode.h index 4a7a2cb26..04852aea8 100644 --- a/xpdf/xpdf/CharCodeToUnicode.h +++ b/xpdf/xpdf/CharCodeToUnicode.h @@ -67,6 +67,10 @@ public: // Map a CharCode to Unicode. int mapToUnicode(CharCode c, Unicode *u, int size); + // Return the mapping's length, i.e., one more than the max char + // code supported by the mapping. + CharCode getLength() { return mapLen; } + private: void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits); diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index 351f28102..3d3b1bd16 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -1046,6 +1046,8 @@ FILE *GlobalParams::findToUnicodeFile(GString *name) { void parseStyle(QString& name, int& weight, int& slant) { + if (name.find("MS-") == 0) name = "MS " + name.remove(0,3); + if (!name.contains('-') && !name.contains(',')) return; QString type = name.section(QRegExp("[-,]"),-1); name = name.section(QRegExp("[-,]"),0,-2); @@ -1106,6 +1108,7 @@ DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName, dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection); } unlockGlobalParams; + if (!dfp) dfp = getDisplayFont(fontName); return dfp; } diff --git a/xpdf/xpdf/SplashOutputDev.cc b/xpdf/xpdf/SplashOutputDev.cc index 8b06e41b7..9a9d7d9dc 100644 --- a/xpdf/xpdf/SplashOutputDev.cc +++ b/xpdf/xpdf/SplashOutputDev.cc @@ -497,10 +497,12 @@ void SplashOutputDev::updateFont(GfxState *state) { FILE *tmpFile; Gushort *codeToGID; DisplayFontParam *dfp; + CharCodeToUnicode *ctu; double m11, m12, m21, m22, w1, w2; SplashCoord mat[4]; const char *name; - int c, substIdx, n, code; + Unicode uBuf[8]; + int c, substIdx, n, code, cmap; needFontUpdate = gFalse; font = NULL; @@ -544,7 +546,6 @@ void SplashOutputDev::updateFont(GfxState *state) { } else if (!(fileName = gfxFont->getExtFontFile())) { // look for a display font mapping or a substitute font - dfp = NULL; if (gfxFont->isCIDFont()) { if (((GfxCIDFont *)gfxFont)->getCollection()) { dfp = globalParams-> @@ -650,10 +651,48 @@ void SplashOutputDev::updateFont(GfxState *state) { } break; case fontCIDType2: - n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); - codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort)); - memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), - n * sizeof(Gushort)); + codeToGID = NULL; + n = 0; + if (dfp) { + // create a CID-to-GID mapping, via Unicode + if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) { + if ((ff = FoFiTrueType::load(fileName->getCString()))) { + // look for a Unicode cmap + for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { + if ((ff->getCmapPlatform(cmap) == 3 && + ff->getCmapEncoding(cmap) == 1) || + ff->getCmapPlatform(cmap) == 0) { + break; + } + } + if (cmap < ff->getNumCmaps()) { + // map CID -> Unicode -> GID + n = ctu->getLength(); + codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort)); + for (code = 0; code < n; ++code) { + if (ctu->mapToUnicode(code, uBuf, 8) > 0) { + codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]); + } else { + codeToGID[code] = 0; + } + } + } + delete ff; + } + ctu->decRefCnt(); + } else { + error(-1, "Couldn't find a mapping to Unicode for font '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + } + } else { + if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { + n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); + codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort)); + memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), + n * sizeof(Gushort)); + } + } if (!(fontFile = fontEngine->loadTrueTypeFont( id, fileName->getCString(), From 2fc01e1d7ad57c398ff40e048b206a819b929ea9 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 8 Mar 2005 09:12:44 +0000 Subject: [PATCH 008/245] Missing bit from the LuRan patch svn path=/trunk/kdegraphics/kpdf/; revision=395688 --- xpdf/xpdf/SplashOutputDev.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/xpdf/xpdf/SplashOutputDev.cc b/xpdf/xpdf/SplashOutputDev.cc index 9a9d7d9dc..10c51b116 100644 --- a/xpdf/xpdf/SplashOutputDev.cc +++ b/xpdf/xpdf/SplashOutputDev.cc @@ -508,6 +508,7 @@ void SplashOutputDev::updateFont(GfxState *state) { font = NULL; tmpFileName = NULL; substIdx = -1; + dfp = NULL; if (!(gfxFont = state->getFont())) { goto err1; From 633fef5eff905b49661aff416f12f39dc39a5fa2 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 8 Mar 2005 19:17:03 +0000 Subject: [PATCH 009/245] Do not crash on files that use [possibly bad] MS Gothic font Stephan can you check if you can still make it crash? BUGS: 101032 svn path=/trunk/kdegraphics/kpdf/; revision=395899 --- xpdf/splash/SplashFTFont.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpdf/splash/SplashFTFont.cc b/xpdf/splash/SplashFTFont.cc index 15c985e0f..b416fa6b8 100644 --- a/xpdf/splash/SplashFTFont.cc +++ b/xpdf/splash/SplashFTFont.cc @@ -219,7 +219,7 @@ SplashPath *SplashFTFont::getGlyphPath(int c) { } else { gid = (FT_UInt)c; } - if (FT_Load_Glyph(ff->face, gid, FT_LOAD_DEFAULT)) { + if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) { return NULL; } if (FT_Get_Glyph(slot, &glyph)) { From 55286640e41fa331cf0f35a33f08a9b92a75c52a Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 8 Mar 2005 19:19:20 +0000 Subject: [PATCH 010/245] Reverting that decreases font quality a lot on the first pdf of that bug BUGS: 101032 svn path=/trunk/kdegraphics/kpdf/; revision=395901 --- xpdf/splash/SplashFTFont.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpdf/splash/SplashFTFont.cc b/xpdf/splash/SplashFTFont.cc index b416fa6b8..15c985e0f 100644 --- a/xpdf/splash/SplashFTFont.cc +++ b/xpdf/splash/SplashFTFont.cc @@ -219,7 +219,7 @@ SplashPath *SplashFTFont::getGlyphPath(int c) { } else { gid = (FT_UInt)c; } - if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) { + if (FT_Load_Glyph(ff->face, gid, FT_LOAD_DEFAULT)) { return NULL; } if (FT_Get_Glyph(slot, &glyph)) { From d358dec14df763258b493572494fd607391fb560 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 9 Mar 2005 22:08:35 +0000 Subject: [PATCH 011/245] Comitting a fix for the memory leak that happens when reloading a file because it was beign watched. To fix it what we do is close the document, show a message telling that the document is beign reloaded and then open the document again when it's ready, that presents a big problem to a backport, because without the text it is really not understood that something is happening. Enrico any idea to do this in a better way so we can backport it? BUGS: 101192 svn path=/trunk/kdegraphics/kpdf/; revision=396219 --- part.cpp | 21 +++++++++++++++++---- part.h | 3 ++- ui/pageview.cpp | 7 +++++++ ui/pageview.h | 2 ++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/part.cpp b/part.cpp index 1c1ad7924..3838a0c68 100644 --- a/part.cpp +++ b/part.cpp @@ -356,6 +356,8 @@ bool Part::openURL(const KURL &url) bool b = KParts::ReadOnlyPart::openURL(url); if ( !b ) KMessageBox::error( widget(), i18n("Could not open %1").arg( url.prettyURL() ) ); + else + m_viewportDirty.pageNumber = -1; return b; } @@ -402,11 +404,22 @@ void Part::slotFileDirty( const QString& fileName ) void Part::slotDoFileDirty() { - uint p = m_document->currentPage() + 1; - if (openFile()) + if (m_viewportDirty.pageNumber == -1) + { + m_viewportDirty = m_document->viewport(); + m_pageView->showText(i18n("Reloading the document..."), 0); + } + + if (KParts::ReadOnlyPart::openURL(m_file)) { - if (p > m_document->pages()) p = m_document->pages(); - goToPage(p); + if (m_viewportDirty.pageNumber > m_document->pages()) m_viewportDirty.pageNumber = m_document->pages(); + m_document->setViewport(m_viewportDirty); + m_viewportDirty.pageNumber = -1; + } + else + { + m_watcher->addFile(m_file); + m_dirtyHandler->start( 750, true ); } } diff --git a/part.h b/part.h index f817774d5..4875d545e 100644 --- a/part.h +++ b/part.h @@ -19,6 +19,7 @@ #include #include #include +#include "core/document.h" #include "core/observer.h" #include "dcop.h" @@ -35,7 +36,6 @@ class KSelectAction; class KAboutData; class KPrinter; -class KPDFDocument; class ThumbnailList; class ThumbnailController; class PageView; @@ -133,6 +133,7 @@ private: KDirWatch *m_watcher; QTimer *m_dirtyHandler; + DocumentViewport m_viewportDirty; // actions KAction *m_gotoPage; diff --git a/ui/pageview.cpp b/ui/pageview.cpp index e0ea19968..d7c1cacb0 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -403,6 +403,13 @@ bool PageView::canUnloadPixmap( int pageNumber ) } //END DocumentObserver inherited methods + +void PageView::showText( const QString &text, int ms ) +{ + d->messageWindow->display(text, PageViewMessage::Info, ms ); +} + + //BEGIN widget events void PageView::viewportPaintEvent( QPaintEvent * pe ) { diff --git a/ui/pageview.h b/ui/pageview.h index a232316f5..e0b944535 100644 --- a/ui/pageview.h +++ b/ui/pageview.h @@ -63,6 +63,8 @@ class PageView : public QScrollView, public DocumentObserver void notifyContentsCleared( int changedFlags ); bool canUnloadPixmap( int pageNum ); + void showText( const QString &text, int ms ); + signals: void urlDropped( const KURL& ); void rightClick( const KPDFPage *, const QPoint & ); From 61ba6bd575bac29580ffcf14f8aac9c6b62dd197 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 9 Mar 2005 22:28:27 +0000 Subject: [PATCH 012/245] Fix the bug introduced by my last fix, Correctly restore last page if last page viewed before a "watch file" reload does not exists anymore svn path=/trunk/kdegraphics/kpdf/; revision=396229 --- part.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/part.cpp b/part.cpp index 3838a0c68..763e373b2 100644 --- a/part.cpp +++ b/part.cpp @@ -412,7 +412,7 @@ void Part::slotDoFileDirty() if (KParts::ReadOnlyPart::openURL(m_file)) { - if (m_viewportDirty.pageNumber > m_document->pages()) m_viewportDirty.pageNumber = m_document->pages(); + if (m_viewportDirty.pageNumber >= (int)m_document->pages()) m_viewportDirty.pageNumber = (int)m_document->pages() - 1; m_document->setViewport(m_viewportDirty); m_viewportDirty.pageNumber = -1; } From 45d2e302ddfe719309b427e99ea8932aa28e5330 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 10 Mar 2005 23:44:28 +0000 Subject: [PATCH 013/245] Partly implement destXYZ Links (zoom is missing). As destXYZ links say the TopLeft corner of the screen that should be displayed i've changed documentViewport syntax a bit, mainly now it includes a Position pos; that can be Center or TopLeft, everything still uses Centered viewports except that pageview::notifyViewportChanged understands TopLeft and translates it to a Center documentviewport so the smoothscroll and so one still work. A good document to test is cups/idd.pdf that has links 1, 1.1, 1.2 and 1.3 all to the same page but with different viewports Seems to work but a review of the code is always good :-D svn path=/trunk/kdegraphics/kpdf/; revision=396528 --- core/document.cpp | 50 ++++++++++++++++++----------- core/document.h | 10 ++++-- core/generator_pdf/gp_outputdev.cpp | 21 +++++++----- ui/pageview.cpp | 41 ++++++++++++++--------- 4 files changed, 76 insertions(+), 46 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 57ae13da9..5f00a7f8c 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -722,9 +722,9 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar if ( moveViewport ) { DocumentViewport searchViewport( currentPage ); - searchViewport.reCenter.enabled = true; - searchViewport.reCenter.normalizedCenterX = (match->left + match->right) / 2.0; - searchViewport.reCenter.normalizedCenterY = (match->top + match->bottom) / 2.0; + searchViewport.rePos.enabled = true; + searchViewport.rePos.normalizedX = (match->left + match->right) / 2.0; + searchViewport.rePos.normalizedY = (match->top + match->bottom) / 2.0; setViewport( searchViewport, -1, true ); } } @@ -1391,9 +1391,10 @@ DocumentViewport::DocumentViewport( int n ) : pageNumber( n ) { // default settings - reCenter.enabled = false; - reCenter.normalizedCenterX = 0.5; - reCenter.normalizedCenterY = 0.0; + rePos.enabled = false; + rePos.normalizedX = 0.5; + rePos.normalizedY = 0.0; + rePos.pos = Center; autoFit.enabled = false; autoFit.width = false; autoFit.height = false; @@ -1403,9 +1404,10 @@ DocumentViewport::DocumentViewport( const QString & xmlDesc ) : pageNumber( -1 ) { // default settings (maybe overridden below) - reCenter.enabled = false; - reCenter.normalizedCenterX = 0.5; - reCenter.normalizedCenterY = 0.0; + rePos.enabled = false; + rePos.normalizedX = 0.5; + rePos.normalizedY = 0.0; + rePos.pos = Center; autoFit.enabled = false; autoFit.width = false; autoFit.height = false; @@ -1429,9 +1431,18 @@ DocumentViewport::DocumentViewport( const QString & xmlDesc ) } else if ( token.startsWith( "C1" ) ) { - reCenter.enabled = true; - reCenter.normalizedCenterX = token.section( ':', 1, 1 ).toDouble(); - reCenter.normalizedCenterY = token.section( ':', 2, 2 ).toDouble(); + rePos.enabled = true; + rePos.normalizedX = token.section( ':', 1, 1 ).toDouble(); + rePos.normalizedY = token.section( ':', 2, 2 ).toDouble(); + rePos.pos = Center; + } + else if ( token.startsWith( "C2" ) ) + { + rePos.enabled = true; + rePos.normalizedX = token.section( ':', 1, 1 ).toDouble(); + rePos.normalizedY = token.section( ':', 2, 2 ).toDouble(); + if (token.section( ':', 3, 3 ).toInt() == 1) rePos.pos = Center; + else rePos.pos = TopLeft; } else if ( token.startsWith( "AF1" ) ) { @@ -1450,9 +1461,10 @@ QString DocumentViewport::toString() const // start string with page number QString s = QString::number( pageNumber ); // if has center coordinates, save them on string - if ( reCenter.enabled ) - s += QString( ";C1:" ) + QString::number( reCenter.normalizedCenterX ) + - ':' + QString::number( reCenter.normalizedCenterY ); + if ( rePos.enabled ) + s += QString( ";C2:" ) + QString::number( rePos.normalizedX ) + + ':' + QString::number( rePos.normalizedY ) + + ':' + QString::number( rePos.pos ); // if has autofit enabled, save its state on string if ( autoFit.enabled ) s += QString( ";AF1:" ) + (autoFit.width ? "T" : "F") + @@ -1463,13 +1475,13 @@ QString DocumentViewport::toString() const bool DocumentViewport::operator==( const DocumentViewport & vp ) const { bool equal = ( pageNumber == vp.pageNumber ) && - ( reCenter.enabled == vp.reCenter.enabled ) && + ( rePos.enabled == vp.rePos.enabled ) && ( autoFit.enabled == vp.autoFit.enabled ); if ( !equal ) return false; - if ( reCenter.enabled && - (( reCenter.normalizedCenterX != vp.reCenter.normalizedCenterX ) || - ( reCenter.normalizedCenterY != vp.reCenter.normalizedCenterY )) ) + if ( rePos.enabled && + (( rePos.normalizedX != vp.rePos.normalizedX) || + ( rePos.normalizedY != vp.rePos.normalizedY ) || rePos.pos != vp.rePos.pos) ) return false; if ( autoFit.enabled && (( autoFit.width != vp.autoFit.width ) || diff --git a/core/document.h b/core/document.h index 574437516..e845f94db 100644 --- a/core/document.h +++ b/core/document.h @@ -136,12 +136,16 @@ class DocumentViewport // the page nearest the center of the viewport int pageNumber; + // enum definitions + enum Position { Center = 1, TopLeft = 2}; + // if reCenter.enabled, this contains the viewport center struct { bool enabled; - double normalizedCenterX; - double normalizedCenterY; - } reCenter; + double normalizedX; + double normalizedY; + Position pos; + } rePos; // if autoFit.enabled, page must be autofitted in the viewport struct { diff --git a/core/generator_pdf/gp_outputdev.cpp b/core/generator_pdf/gp_outputdev.cpp index 5efb43583..38d8e904c 100644 --- a/core/generator_pdf/gp_outputdev.cpp +++ b/core/generator_pdf/gp_outputdev.cpp @@ -377,14 +377,19 @@ DocumentViewport KPDFOutputDev::decodeViewport( GString * namedDest, LinkDest * switch ( dest->getKind() ) { case destXYZ: -/* OD -> cvtUserToDev( dest->getLeft(), dest->getTop(), &X, &Y ); - if ( dest->getChangeLeft() ) - make hor change - if ( dest->getChangeTop() ) - make ver change - if ( dest->getChangeZoom() ) - make zoom change -*/ break; + if (dest->getChangeLeft() || dest->getChangeTop()) + { + int left, top; + cvtUserToDev( dest->getLeft(), dest->getTop(), &left, &top ); + vp.rePos.normalizedX = (double)left / (double)m_pixmapWidth; + vp.rePos.normalizedY = (double)top / (double)m_pixmapHeight; + vp.rePos.enabled = true; + vp.rePos.pos = DocumentViewport::TopLeft; + } + /* TODO + if ( dest->getChangeZoom() ) + make zoom change*/ + break; case destFit: case destFitB: diff --git a/ui/pageview.cpp b/ui/pageview.cpp index d7c1cacb0..667270a38 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -312,10 +312,19 @@ void PageView::notifyViewportChanged( bool smoothMove ) const QRect & r = item->geometry(); int newCenterX = r.left(), newCenterY = r.top(); - if ( vp.reCenter.enabled ) + if ( vp.rePos.enabled ) { - newCenterX += (int)( vp.reCenter.normalizedCenterX * (double)r.width() ); - newCenterY += (int)( vp.reCenter.normalizedCenterY * (double)r.height() ); + if (vp.rePos.pos == DocumentViewport::Center) + { + newCenterX += (int)( vp.rePos.normalizedX * (double)r.width() ); + newCenterY += (int)( vp.rePos.normalizedY * (double)r.height() ); + } + else + { + // TopLeft + newCenterX += (int)( vp.rePos.normalizedX * (double)r.width() + viewport()->width() / 2 ); + newCenterY += (int)( vp.rePos.normalizedY * (double)r.height() + viewport()->height() / 2 ); + } } else { @@ -649,8 +658,8 @@ void PageView::keyPressEvent( QKeyEvent * e ) // more optimized than document->setPrevPage and then move view to bottom DocumentViewport newViewport = d->document->viewport(); newViewport.pageNumber -= 1; - newViewport.reCenter.enabled = true; - newViewport.reCenter.normalizedCenterY = 1.0; + newViewport.rePos.enabled = true; + newViewport.rePos.normalizedY = 1.0; d->document->setViewport( newViewport ); } break; @@ -669,8 +678,8 @@ void PageView::keyPressEvent( QKeyEvent * e ) // more optmized than document->setNextPage and then move view to top DocumentViewport newViewport = d->document->viewport(); newViewport.pageNumber += 1; - newViewport.reCenter.enabled = true; - newViewport.reCenter.normalizedCenterY = 0.0; + newViewport.rePos.enabled = true; + newViewport.rePos.normalizedY = 0.0; d->document->setViewport( newViewport ); } break; @@ -1128,8 +1137,8 @@ void PageView::wheelEvent( QWheelEvent *e ) // more optmized than document->setNextPage and then move view to top DocumentViewport newViewport = d->document->viewport(); newViewport.pageNumber += 1; - newViewport.reCenter.enabled = true; - newViewport.reCenter.normalizedCenterY = 0.0; + newViewport.rePos.enabled = true; + newViewport.rePos.normalizedY = 0.0; d->document->setViewport( newViewport ); } } @@ -1141,8 +1150,8 @@ void PageView::wheelEvent( QWheelEvent *e ) // more optmized than document->setPrevPage and then move view to bottom DocumentViewport newViewport = d->document->viewport(); newViewport.pageNumber -= 1; - newViewport.reCenter.enabled = true; - newViewport.reCenter.normalizedCenterY = 1.0; + newViewport.rePos.enabled = true; + newViewport.rePos.normalizedY = 1.0; d->document->setViewport( newViewport ); } } @@ -1646,8 +1655,8 @@ void PageView::slotRelayoutPages() int prevX = contentsX(), prevY = contentsY(); const QRect & geometry = d->items[ vp.pageNumber ]->geometry(); - double nX = vp.reCenter.enabled ? vp.reCenter.normalizedCenterX : 0.5, - nY = vp.reCenter.enabled ? vp.reCenter.normalizedCenterY : 0.0; + double nX = vp.rePos.enabled ? vp.rePos.normalizedX : 0.5, + nY = vp.rePos.enabled ? vp.rePos.normalizedY : 0.0; center( geometry.left() + ROUND( nX * (double)geometry.width() ), geometry.top() + ROUND( nY * (double)geometry.height() ) ); // center() usually moves the viewport, that requests pixmaps too. @@ -1767,9 +1776,9 @@ void PageView::slotRequestVisiblePixmaps( int newLeft, int newTop ) { // determine the document viewport DocumentViewport newViewport( nearPageNumber ); - newViewport.reCenter.enabled = true; - newViewport.reCenter.normalizedCenterX = focusedX; - newViewport.reCenter.normalizedCenterY = focusedY; + newViewport.rePos.enabled = true; + newViewport.rePos.normalizedX = focusedX; + newViewport.rePos.normalizedY = focusedY; // set the viewport to other observers d->document->setViewport( newViewport , PAGEVIEW_ID); } From 742ed0b9554608b98745ba0593afd620259ecd56 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 10 Mar 2005 23:52:56 +0000 Subject: [PATCH 014/245] Update changelog and make links use the cool smooth scrolling if nobody says that is bad i think that gives us a wow factor and no configure option is needed svn path=/trunk/kdegraphics/kpdf/; revision=396533 --- TODO | 1 + core/document.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index 91e367a5a..96e83d65d 100644 --- a/TODO +++ b/TODO @@ -73,6 +73,7 @@ More items (first items will enter 'In progress list' first): Done (newest features come first): -- merging from kdpf_annotations branch -- +-> ADD: partial implementation of XYZ links -> ADD: google-like search on thumbnails -> ADD: use kde wallet for storing passwords of protected files -> ADD: Obey DRM is now a configuration option diff --git a/core/document.cpp b/core/document.cpp index 5f00a7f8c..e6093cb85 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -895,7 +895,7 @@ void KPDFDocument::processLink( const KPDFLink * link ) } else { - setViewport( d->nextDocumentViewport ); + setViewport( d->nextDocumentViewport, -1, true ); d->nextDocumentViewport = DocumentViewport(); } From 7fb48499c97d69cb806157f49729c61645367fb7 Mon Sep 17 00:00:00 2001 From: Jakub Stachowski Date: Sat, 12 Mar 2005 15:58:47 +0000 Subject: [PATCH 015/245] Backport fix for bug 99316 (accel for showing/hiding sidebar) from experimental branch to HEAD. svn path=/trunk/kdegraphics/kpdf/; revision=396986 --- conf/dlggeneral.ui | 85 ++++++++++++---------------------------------- part.cpp | 46 +++++++++++++------------ part.h | 4 +-- part.rc | 2 +- 4 files changed, 49 insertions(+), 88 deletions(-) diff --git a/conf/dlggeneral.ui b/conf/dlggeneral.ui index 9a7bb2c16..be381b593 100644 --- a/conf/dlggeneral.ui +++ b/conf/dlggeneral.ui @@ -40,60 +40,25 @@ - kcfg_ShowLeftPanel + kcfg_ShowSearchBar + + + true - Show &left panel + Show &search bar in thumbnails list - + - layout5 - - - - unnamed - - - - kcfg_ShowSearchBar - - - false - - - Show &search bar in thumbnails list - - - - - spacer2 - - - Horizontal - - - Fixed - - - - 16 - 30 - - - - - - kcfg_SyncThumbnailsViewport - - - false - - - Link the &thumbnails with the page - - - + kcfg_SyncThumbnailsViewport + + + true + + + Link the &thumbnails with the page + @@ -119,6 +84,14 @@ &Obey DRM limitations + + + kcfg_WatchFile + + + &Watch File + + @@ -185,20 +158,6 @@ - - - kcfg_ShowLeftPanel - toggled(bool) - kcfg_ShowSearchBar - setEnabled(bool) - - - kcfg_ShowLeftPanel - toggled(bool) - kcfg_SyncThumbnailsViewport - setEnabled(bool) - - kdialog.h kiconloader.h diff --git a/part.cpp b/part.cpp index 763e373b2..6a21c25c9 100644 --- a/part.cpp +++ b/part.cpp @@ -116,8 +116,10 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_splitter = new QSplitter( parentWidget, widgetName ); m_splitter->setOpaqueResize( true ); setWidget( m_splitter ); - m_watchFile = new KToggleAction( i18n( "&Watch File" ), 0, this, SLOT( slotWatchFile() ), actionCollection(), "watch_file" ); - m_watchFile->setChecked( Settings::watchFile() ); + + m_showLeftPanel = new KToggleAction( i18n( "Show &left panel"), 0, this, SLOT( slotShowLeftPanel() ), actionCollection(), "show_leftpanel" ); + m_showLeftPanel->setShortcut( "CTRL+L" ); + m_showLeftPanel->setChecked( Settings::showLeftPanel() ); // widgets: [left panel] | [] m_leftPanel = new QWidget( m_splitter ); @@ -149,6 +151,8 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_toolBox->addItem( thumbsBox, QIconSet(SmallIcon("thumbnail")), i18n("Thumbnails") ); m_toolBox->setCurrentItem( thumbsBox ); + slotShowLeftPanel(); + /* // [left toolbox: Annotations] | [] QFrame * editFrame = new QFrame( m_toolBox ); int iIdx = m_toolBox->addItem( editFrame, QIconSet(SmallIcon("pencil")), i18n("Annotations") ); @@ -244,13 +248,13 @@ Part::Part(QWidget *parentWidget, const char *widgetName, splitterSizes.push_back( 500 ); } m_splitter->setSizes( splitterSizes ); - slotNewConfig(); - m_watcher = new KDirWatch( this ); connect( m_watcher, SIGNAL( dirty( const QString& ) ), this, SLOT( slotFileDirty( const QString& ) ) ); m_dirtyHandler = new QTimer( this ); connect( m_dirtyHandler, SIGNAL( timeout() ),this, SLOT( slotDoFileDirty() ) ); + slotNewConfig(); + // [SPEECH] check for KTTSD presence and usability KTrader::OfferList offers = KTrader::self()->query("DCOP/Text-to-Speech", "Name == 'KTTSD'"); Settings::setUseKTTSD( (offers.count() > 0) ); @@ -258,7 +262,6 @@ Part::Part(QWidget *parentWidget, const char *widgetName, // set our XML-UI resource file setXMLFile("part.rc"); updateViewActions(); - slotWatchFile(); } Part::~Part() @@ -377,16 +380,14 @@ bool Part::closeURL() return KParts::ReadOnlyPart::closeURL(); } -void Part::slotWatchFile() +void Part::slotShowLeftPanel() { - Settings::setWatchFile(m_watchFile->isChecked()); - if( m_watchFile->isChecked() ) - m_watcher->startScan(); - else - { - m_dirtyHandler->stop(); - m_watcher->stopScan(); - } + bool showLeft = m_showLeftPanel->isChecked(); + Settings::setShowLeftPanel(showLeft); + // show/hide left qtoolbox + m_leftPanel->setShown( showLeft ); + // this needs to be hidden explicitly to disable thumbnails gen + m_thumbnailList->setShown( showLeft ); } void Part::slotFileDirty( const QString& fileName ) @@ -580,15 +581,16 @@ void Part::slotNewConfig() // Apply settings here. A good policy is to check wether the setting has // changed before applying changes. - // Left Panel and search Widget - bool showLeft = Settings::showLeftPanel(); - if ( m_leftPanel->isShown() != showLeft ) + // Watch File + bool watchFile = Settings::watchFile(); + if ( watchFile && m_watcher->isStopped() ) + m_watcher->startScan(); + if ( !watchFile && !m_watcher->isStopped() ) { - // show/hide left qtoolbox - m_leftPanel->setShown( showLeft ); - // this needs to be hidden explicitly to disable thumbnails gen - m_thumbnailList->setShown( showLeft ); + m_dirtyHandler->stop(); + m_watcher->stopScan(); } + bool showSearch = Settings::showSearchBar(); if ( m_searchWidget->isShown() != showSearch ) m_searchWidget->setShown( showSearch ); @@ -608,7 +610,7 @@ void Part::slotNewConfig() // update Main View and ThumbnailList contents // TODO do this only when changing Settings::renderMode() m_pageView->updateContents(); - if ( showLeft && m_thumbnailList->isShown() ) + if ( Settings::showLeftPanel() && m_thumbnailList->isShown() ) m_thumbnailList->updateWidgets(); } diff --git a/part.h b/part.h index 4875d545e..b0127a753 100644 --- a/part.h +++ b/part.h @@ -99,6 +99,7 @@ protected slots: void slotPrintPreview(); void slotShowMenu(const KPDFPage *page, const QPoint &point); void slotShowProperties(); + void slotShowLeftPanel(); void slotShowPresentation(); // can be connected to widget elements void updateViewActions(); @@ -109,7 +110,6 @@ public slots: void slotPrint(); void restoreDocument(const KURL &url, int page); void saveDocumentRestoreInfo(KConfig* config); - void slotWatchFile(); void slotFileDirty( const QString& ); void slotDoFileDirty(); @@ -149,8 +149,8 @@ private: KAction *m_printPreview; KAction *m_showProperties; KAction *m_showPresentation; - KToggleAction* m_watchFile; KToggleAction* m_showMenuBarAction; + KToggleAction* m_showLeftPanel; KToggleAction* m_showFullScreenAction; bool m_actionsSearched; bool m_searchStarted; diff --git a/part.rc b/part.rc index abcd1225d..e7592e70b 100644 --- a/part.rc +++ b/part.rc @@ -40,7 +40,7 @@ &Settings - + From a103f957aabbd0695c00c3e2e2df66ce250eab7c Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 12 Mar 2005 20:33:31 +0000 Subject: [PATCH 016/245] Fix the allocation size of libgoo on 64bit architectures. Patch by Takashi Iwai svn path=/trunk/kdegraphics/kpdf/; revision=397057 --- xpdf/goo/gmem.c | 10 +++++----- xpdf/goo/gmem.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/xpdf/goo/gmem.c b/xpdf/goo/gmem.c index 258596951..036beb8a3 100644 --- a/xpdf/goo/gmem.c +++ b/xpdf/goo/gmem.c @@ -53,9 +53,9 @@ static int gMemAlloc = 0; #endif /* DEBUG_MEM */ -void *gmalloc(int size) { +void *gmalloc(size_t size) { #ifdef DEBUG_MEM - int size1; + size_t size1; char *mem; GMemHdr *hdr; void *data; @@ -94,11 +94,11 @@ void *gmalloc(int size) { #endif } -void *grealloc(void *p, int size) { +void *grealloc(void *p, size_t size) { #ifdef DEBUG_MEM GMemHdr *hdr; void *q; - int oldSize; + size_t oldSize; if (size == 0) { if (p) @@ -137,7 +137,7 @@ void *grealloc(void *p, int size) { void gfree(void *p) { #ifdef DEBUG_MEM - int size; + size_t size; GMemHdr *hdr; GMemHdr *prevHdr, *q; int lst; diff --git a/xpdf/goo/gmem.h b/xpdf/goo/gmem.h index 17a5257da..3d38907ff 100644 --- a/xpdf/goo/gmem.h +++ b/xpdf/goo/gmem.h @@ -19,13 +19,13 @@ extern "C" { * Same as malloc, but prints error message and exits if malloc() * returns NULL. */ -extern void *gmalloc(int size); +extern void *gmalloc(size_t size); /* * Same as realloc, but prints error message and exits if realloc() * returns NULL. If

is NULL, calls malloc instead of realloc(). */ -extern void *grealloc(void *p, int size); +extern void *grealloc(void *p, size_t size); /* * Same as free, but checks for and ignores NULL pointers. From b26936a4a399c5e7a681d2a36df9630ad1b31fb9 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 14 Mar 2005 22:13:38 +0000 Subject: [PATCH 017/245] Lots of xpdf improvements thanks Takashi Iwai - Add suport for TTC font collections - Pass font files in memory instead of using a temporary file - Various CJK fonts fixes svn path=/trunk/kdegraphics/kpdf/; revision=397652 --- xpdf/fofi/FoFiTrueType.cc | 44 +++++++++-- xpdf/fofi/FoFiTrueType.h | 7 +- xpdf/fofi/FoFiType1C.h | 2 +- xpdf/splash/SplashFTFont.cc | 2 +- xpdf/splash/SplashFTFontEngine.cc | 42 ++++++---- xpdf/splash/SplashFTFontEngine.h | 16 ++-- xpdf/splash/SplashFTFontFile.cc | 47 ++++++----- xpdf/splash/SplashFTFontFile.h | 16 ++-- xpdf/splash/SplashFontEngine.cc | 46 +++++------ xpdf/splash/SplashFontEngine.h | 16 ++-- xpdf/splash/SplashFontFile.cc | 70 ++++++++++++++-- xpdf/splash/SplashFontFile.h | 25 +++++- xpdf/splash/SplashT1FontEngine.cc | 28 +++---- xpdf/splash/SplashT1FontFile.cc | 30 +++++-- xpdf/splash/SplashT1FontFile.h | 4 +- xpdf/xpdf/CharCodeToUnicode.h | 2 + xpdf/xpdf/GfxFont.cc | 49 +++++++++++- xpdf/xpdf/GfxFont.h | 2 + xpdf/xpdf/GlobalParams.cc | 18 ++++- xpdf/xpdf/GlobalParams.h | 1 + xpdf/xpdf/PSOutputDev.cc | 127 +++++++++++++++++++++++++++--- xpdf/xpdf/PSOutputDev.h | 4 +- xpdf/xpdf/SplashOutputDev.cc | 100 +++++++++++------------ 23 files changed, 498 insertions(+), 200 deletions(-) diff --git a/xpdf/fofi/FoFiTrueType.cc b/xpdf/fofi/FoFiTrueType.cc index 0bb605e68..5430df9ac 100644 --- a/xpdf/fofi/FoFiTrueType.cc +++ b/xpdf/fofi/FoFiTrueType.cc @@ -233,10 +233,10 @@ static const char *macGlyphNames[258] = { // FoFiTrueType //------------------------------------------------------------------------ -FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA) { +FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int faceIndexA) { FoFiTrueType *ff; - ff = new FoFiTrueType(fileA, lenA, gFalse); + ff = new FoFiTrueType(fileA, lenA, gFalse, faceIndexA); if (!ff->parsedOk) { delete ff; return NULL; @@ -244,7 +244,7 @@ FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA) { return ff; } -FoFiTrueType *FoFiTrueType::load(char *fileName) { +FoFiTrueType *FoFiTrueType::load(char *fileName, int faceIndexA) { FoFiTrueType *ff; char *fileA; int lenA; @@ -252,7 +252,7 @@ FoFiTrueType *FoFiTrueType::load(char *fileName) { if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { return NULL; } - ff = new FoFiTrueType(fileA, lenA, gTrue); + ff = new FoFiTrueType(fileA, lenA, gTrue, faceIndexA); if (!ff->parsedOk) { delete ff; return NULL; @@ -260,7 +260,7 @@ FoFiTrueType *FoFiTrueType::load(char *fileName) { return ff; } -FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA): +FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA): FoFiBase(fileA, lenA, freeFileDataA) { tables = NULL; @@ -269,6 +269,7 @@ FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA): nCmaps = 0; nameToGID = NULL; parsedOk = gFalse; + faceIndex = faceIndexA; parse(); } @@ -1262,18 +1263,47 @@ Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { return checksum; } +#define toTag(a,b,c,d) (((unsigned int)(a)<<24) | ((unsigned int)(b)<<16) | ((unsigned int)(c)<<8) | (d)) + void FoFiTrueType::parse() { int pos, i, j; + unsigned int head; parsedOk = gTrue; + pos = 0; // read the table directory - nTables = getU16BE(4, &parsedOk); + head = getU32BE(pos, &parsedOk); + if (! parsedOk) + return; + if (head == toTag('t','t','c','f')) { + /* TTC font */ +// unsigned int tableDir; + int dircount; + + dircount = getU32BE(8, &parsedOk); + if (!parsedOk) + return; + if (! dircount) { + parsedOk = gFalse; + return; + } + + if (faceIndex >= dircount) + faceIndex = 0; + pos = getU32BE(12 + faceIndex * 4, &parsedOk); + if (! parsedOk) + return; + } + + pos += 4; + nTables = getU16BE(pos, &parsedOk); if (!parsedOk) { return; } + + pos += 8; tables = (TrueTypeTable *)gmalloc(nTables * sizeof(TrueTypeTable)); - pos = 12; for (i = 0; i < nTables; ++i) { tables[i].tag = getU32BE(pos, &parsedOk); tables[i].checksum = getU32BE(pos + 4, &parsedOk); diff --git a/xpdf/fofi/FoFiTrueType.h b/xpdf/fofi/FoFiTrueType.h index 2c5b0cb6b..b3f7d3aca 100644 --- a/xpdf/fofi/FoFiTrueType.h +++ b/xpdf/fofi/FoFiTrueType.h @@ -30,11 +30,12 @@ class FoFiTrueType: public FoFiBase { public: // Create a FoFiTrueType object from a memory buffer. - static FoFiTrueType *make(char *fileA, int lenA); + static FoFiTrueType *make(char *fileA, int lenA, int faceIndexA=0); // Create a FoFiTrueType object from a file on disk. - static FoFiTrueType *load(char *fileName); + static FoFiTrueType *load(char *fileName, int faceIndexA=0); + FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA=0); virtual ~FoFiTrueType(); // Return the number of cmaps defined by this font. @@ -100,7 +101,6 @@ public: private: - FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA); void cvtEncoding(const char **encoding, FoFiOutputFunc outputFunc, void *outputStream); @@ -128,6 +128,7 @@ private: GHash *nameToGID; GBool parsedOk; + int faceIndex; }; #endif diff --git a/xpdf/fofi/FoFiType1C.h b/xpdf/fofi/FoFiType1C.h index 5516a65d7..1b980c7ea 100644 --- a/xpdf/fofi/FoFiType1C.h +++ b/xpdf/fofi/FoFiType1C.h @@ -135,6 +135,7 @@ public: // Create a FoFiType1C object from a file on disk. static FoFiType1C *load(char *fileName); + FoFiType1C(char *fileA, int lenA, GBool freeFileDataA); virtual ~FoFiType1C(); // Return the font name. @@ -170,7 +171,6 @@ public: private: - FoFiType1C(char *fileA, int lenA, GBool freeFileDataA); void eexecCvtGlyph(Type1CEexecBuf *eb, const char *glyphName, int offset, int nBytes, Type1CIndex *subrIdx, diff --git a/xpdf/splash/SplashFTFont.cc b/xpdf/splash/SplashFTFont.cc index 15c985e0f..b416fa6b8 100644 --- a/xpdf/splash/SplashFTFont.cc +++ b/xpdf/splash/SplashFTFont.cc @@ -219,7 +219,7 @@ SplashPath *SplashFTFont::getGlyphPath(int c) { } else { gid = (FT_UInt)c; } - if (FT_Load_Glyph(ff->face, gid, FT_LOAD_DEFAULT)) { + if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) { return NULL; } if (FT_Get_Glyph(slot, &glyph)) { diff --git a/xpdf/splash/SplashFTFontEngine.cc b/xpdf/splash/SplashFTFontEngine.cc index 58151317d..d6c078f04 100644 --- a/xpdf/splash/SplashFTFontEngine.cc +++ b/xpdf/splash/SplashFTFontEngine.cc @@ -58,22 +58,19 @@ SplashFTFontEngine::~SplashFTFontEngine() { } SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA, - char *fileName, - GBool deleteFile, + SplashFontSrc *src, const char **enc) { - return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc); + return SplashFTFontFile::loadType1Font(this, idA, src, enc); } SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, - char *fileName, - GBool deleteFile, + SplashFontSrc *src, const char **enc) { - return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc); + return SplashFTFontFile::loadType1Font(this, idA, src, enc); } SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, - char *fileName, - GBool deleteFile) { + SplashFontSrc *src) { Gushort *cidToGIDMap; int nCIDs; SplashFontFile *ret; @@ -81,7 +78,12 @@ SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, // check for a CFF font #if HAVE_FREETYPE_217_OR_OLDER FoFiType1C *ff; - if ((ff = FoFiType1C::load(fileName))) { + if (src->isFile) { + ff = FoFiType1C::load(src->fileName->getCString()); + } else { + ff = new FoFiType1C(src->buf, src->bufLen, gFalse); + } + if (ff) { cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); delete ff; } else { @@ -93,8 +95,7 @@ SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, cidToGIDMap = NULL; nCIDs = 0; #endif - ret = SplashFTFontFile::loadCIDFont(this, idA, fileName, deleteFile, - cidToGIDMap, nCIDs); + ret = SplashFTFontFile::loadCIDFont(this, idA, src, cidToGIDMap, nCIDs); if (!ret) { gfree(cidToGIDMap); } @@ -102,16 +103,17 @@ SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, } SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, - char *fileName, - GBool deleteFile, + SplashFontSrc *src, Gushort *codeToGID, - int codeToGIDLen) { + int codeToGIDLen, + int faceIndex) { +#if 0 FoFiTrueType *ff; GString *tmpFileName; FILE *tmpFile; SplashFontFile *ret; - if (!(ff = FoFiTrueType::load(fileName))) { + if (!(ff = FoFiTrueType::load(fileName, faceIndex))) { return NULL; } tmpFileName = NULL; @@ -124,7 +126,8 @@ SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, fclose(tmpFile); ret = SplashFTFontFile::loadTrueTypeFont(this, idA, tmpFileName->getCString(), - gTrue, codeToGID, codeToGIDLen); + gTrue, codeToGID, codeToGIDLen, + faceIndex); if (ret) { if (deleteFile) { unlink(fileName); @@ -134,6 +137,13 @@ SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, } delete tmpFileName; return ret; +#else + SplashFontFile *ret; + ret = SplashFTFontFile::loadTrueTypeFont(this, idA, src, + codeToGID, codeToGIDLen, + faceIndex); + return ret; +#endif } #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/xpdf/splash/SplashFTFontEngine.h b/xpdf/splash/SplashFTFontEngine.h index e454fd2c3..34e572be9 100644 --- a/xpdf/splash/SplashFTFontEngine.h +++ b/xpdf/splash/SplashFTFontEngine.h @@ -21,6 +21,7 @@ class SplashFontFile; class SplashFontFileID; +class SplashFontSrc; //------------------------------------------------------------------------ // SplashFTFontEngine @@ -34,15 +35,12 @@ public: ~SplashFTFontEngine(); // Load fonts. - SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, - GBool deleteFile, const char **enc); - SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, - GBool deleteFile, const char **enc); - SplashFontFile *loadCIDFont(SplashFontFileID *idA, char *fileName, - GBool deleteFile); - SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, char *fileName, - GBool deleteFile, - Gushort *codeToGID, int codeToGIDLen); + SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, + Gushort *codeToGID, int codeToGIDLen, + int faceIndex=0); private: diff --git a/xpdf/splash/SplashFTFontFile.cc b/xpdf/splash/SplashFTFontFile.cc index d730b969e..4a6e615fb 100644 --- a/xpdf/splash/SplashFTFontFile.cc +++ b/xpdf/splash/SplashFTFontFile.cc @@ -16,6 +16,7 @@ #include "SplashFTFontEngine.h" #include "SplashFTFont.h" #include "SplashFTFontFile.h" +#include "GString.h" //------------------------------------------------------------------------ // SplashFTFontFile @@ -23,16 +24,19 @@ SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, SplashFontFileID *idA, - char *fileNameA, - GBool deleteFileA, + SplashFontSrc *src, const char **encA) { FT_Face faceA; Gushort *codeToGIDA; const char *name; int i; - if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { - return NULL; + if (src->isFile) { + if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA)) + return NULL; + } else { + if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA)) + return NULL; } codeToGIDA = (Gushort *)gmalloc(256 * sizeof(int)); for (i = 0; i < 256; ++i) { @@ -42,48 +46,55 @@ SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, } } - return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, + return new SplashFTFontFile(engineA, idA, src, faceA, codeToGIDA, 256); } SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, - char *fileNameA, - GBool deleteFileA, + SplashFontSrc *src, Gushort *codeToGIDA, int codeToGIDLenA) { FT_Face faceA; - if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { - return NULL; + if (src->isFile) { + if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA)) + return NULL; + } else { + if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA)) + return NULL; } - return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, + return new SplashFTFontFile(engineA, idA, src, faceA, codeToGIDA, codeToGIDLenA); } SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, - char *fileNameA, - GBool deleteFileA, + SplashFontSrc *src, Gushort *codeToGIDA, - int codeToGIDLenA) { + int codeToGIDLenA, + int faceIndexA) { FT_Face faceA; - if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { - return NULL; + if (src->isFile) { + if (FT_New_Face(engineA->lib, src->fileName->getCString(), faceIndexA, &faceA)) + return NULL; + } else { + if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, faceIndexA, &faceA)) + return NULL; } - return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, + return new SplashFTFontFile(engineA, idA, src, faceA, codeToGIDA, codeToGIDLenA); } SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA, SplashFontFileID *idA, - char *fileNameA, GBool deleteFileA, + SplashFontSrc *srcA, FT_Face faceA, Gushort *codeToGIDA, int codeToGIDLenA): - SplashFontFile(idA, fileNameA, deleteFileA) + SplashFontFile(idA, srcA) { engine = engineA; face = faceA; diff --git a/xpdf/splash/SplashFTFontFile.h b/xpdf/splash/SplashFTFontFile.h index 006a2754c..91fed355c 100644 --- a/xpdf/splash/SplashFTFontFile.h +++ b/xpdf/splash/SplashFTFontFile.h @@ -30,18 +30,18 @@ class SplashFTFontFile: public SplashFontFile { public: static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA, - SplashFontFileID *idA, char *fileNameA, - GBool deleteFileA, const char **encA); + SplashFontFileID *idA, + SplashFontSrc *src, const char **encA); static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA, - SplashFontFileID *idA, char *fileNameA, - GBool deleteFileA, + SplashFontFileID *idA, + SplashFontSrc *src, Gushort *codeToCIDA, int codeToGIDLenA); static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, - char *fileNameA, - GBool deleteFileA, + SplashFontSrc *src, Gushort *codeToGIDA, - int codeToGIDLenA); + int codeToGIDLenA, + int faceIndexA=0); virtual ~SplashFTFontFile(); @@ -53,7 +53,7 @@ private: SplashFTFontFile(SplashFTFontEngine *engineA, SplashFontFileID *idA, - char *fileNameA, GBool deleteFileA, + SplashFontSrc *srcA, FT_Face faceA, Gushort *codeToGIDA, int codeToGIDLenA); diff --git a/xpdf/splash/SplashFontEngine.cc b/xpdf/splash/SplashFontEngine.cc index 055584a5d..152fd3b89 100644 --- a/xpdf/splash/SplashFontEngine.cc +++ b/xpdf/splash/SplashFontEngine.cc @@ -105,19 +105,19 @@ SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) { } SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA, - char *fileName, - GBool deleteFile, const char **enc) { + SplashFontSrc *src, + const char **enc) { SplashFontFile *fontFile; fontFile = NULL; #if HAVE_T1LIB_H if (!fontFile && t1Engine) { - fontFile = t1Engine->loadType1Font(idA, fileName, deleteFile, enc); + fontFile = t1Engine->loadType1Font(idA, src, enc); } #endif #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (!fontFile && ftEngine) { - fontFile = ftEngine->loadType1Font(idA, fileName, deleteFile, enc); + fontFile = ftEngine->loadType1Font(idA, src, enc); } #endif @@ -125,28 +125,25 @@ SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA, // semantics, this will remove the last link; otherwise it will // return an error, leaving the file to be deleted later (if // loadXYZFont failed, the file will always be deleted) - if (deleteFile) { - unlink(fontFile ? fontFile->fileName->getCString() : fileName); - } + src->unref(); return fontFile; } SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, - char *fileName, - GBool deleteFile, + SplashFontSrc *src, const char **enc) { SplashFontFile *fontFile; fontFile = NULL; #if HAVE_T1LIB_H if (!fontFile && t1Engine) { - fontFile = t1Engine->loadType1CFont(idA, fileName, deleteFile, enc); + fontFile = t1Engine->loadType1CFont(idA, src, enc); } #endif #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (!fontFile && ftEngine) { - fontFile = ftEngine->loadType1CFont(idA, fileName, deleteFile, enc); + fontFile = ftEngine->loadType1CFont(idA, src, enc); } #endif @@ -154,22 +151,19 @@ SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, // semantics, this will remove the last link; otherwise it will // return an error, leaving the file to be deleted later (if // loadXYZFont failed, the file will always be deleted) - if (deleteFile) { - unlink(fontFile ? fontFile->fileName->getCString() : fileName); - } + src->unref(); return fontFile; } SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, - char *fileName, - GBool deleteFile) { + SplashFontSrc *src) { SplashFontFile *fontFile; fontFile = NULL; #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (!fontFile && ftEngine) { - fontFile = ftEngine->loadCIDFont(idA, fileName, deleteFile); + fontFile = ftEngine->loadCIDFont(idA, src); } #endif @@ -177,25 +171,23 @@ SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, // semantics, this will remove the last link; otherwise it will // return an error, leaving the file to be deleted later (if // loadXYZFont failed, the file will always be deleted) - if (deleteFile) { - unlink(fontFile ? fontFile->fileName->getCString() : fileName); - } + src->unref(); return fontFile; } SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, - char *fileName, - GBool deleteFile, + SplashFontSrc *src, Gushort *codeToGID, - int codeToGIDLen) { + int codeToGIDLen, + int faceIndex) { SplashFontFile *fontFile; fontFile = NULL; #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (!fontFile && ftEngine) { - fontFile = ftEngine->loadTrueTypeFont(idA, fileName, deleteFile, - codeToGID, codeToGIDLen); + fontFile = ftEngine->loadTrueTypeFont(idA, src, + codeToGID, codeToGIDLen, faceIndex); } #endif @@ -207,9 +199,7 @@ SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, // semantics, this will remove the last link; otherwise it will // return an error, leaving the file to be deleted later (if // loadXYZFont failed, the file will always be deleted) - if (deleteFile) { - unlink(fontFile ? fontFile->fileName->getCString() : fileName); - } + src->unref(); return fontFile; } diff --git a/xpdf/splash/SplashFontEngine.h b/xpdf/splash/SplashFontEngine.h index 52bb17be7..ccc2105c1 100644 --- a/xpdf/splash/SplashFontEngine.h +++ b/xpdf/splash/SplashFontEngine.h @@ -21,6 +21,7 @@ class SplashDTFontEngine; class SplashFontFile; class SplashFontFileID; class SplashFont; +class SplashFontSrc; //------------------------------------------------------------------------ @@ -50,15 +51,12 @@ public: SplashFontFile *getFontFile(SplashFontFileID *id); // Load fonts - these create new SplashFontFile objects. - SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, - GBool deleteFile, const char **enc); - SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, - GBool deleteFile, const char **enc); - SplashFontFile *loadCIDFont(SplashFontFileID *idA, char *fileName, - GBool deleteFile); - SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, char *fileName, - GBool deleteFile, - Gushort *codeToGID, int codeToGIDLen); + SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, + Gushort *codeToGID, int codeToGIDLen, + int faceIndex=0); // Get a font - this does a cache lookup first, and if not found, // creates a new SplashFont object and adds it to the cache. The diff --git a/xpdf/splash/SplashFontFile.cc b/xpdf/splash/SplashFontFile.cc index acbc12a3b..6cc0dadcc 100644 --- a/xpdf/splash/SplashFontFile.cc +++ b/xpdf/splash/SplashFontFile.cc @@ -17,6 +17,7 @@ #include "GString.h" #include "SplashFontFile.h" #include "SplashFontFileID.h" +#include "gmem.h" #ifdef VMS #if (__VMS_VER < 70000000) @@ -28,19 +29,15 @@ extern "C" int unlink(char *filename); // SplashFontFile //------------------------------------------------------------------------ -SplashFontFile::SplashFontFile(SplashFontFileID *idA, char *fileNameA, - GBool deleteFileA) { +SplashFontFile::SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA) { id = idA; - fileName = new GString(fileNameA); - deleteFile = deleteFileA; + src = srcA; + src->ref(); refCnt = 0; } SplashFontFile::~SplashFontFile() { - if (deleteFile) { - unlink(fileName->getCString()); - } - delete fileName; + src->unref(); delete id; } @@ -53,3 +50,60 @@ void SplashFontFile::decRefCnt() { delete this; } } + +// + +SplashFontSrc::SplashFontSrc() { + isFile = gFalse; + deleteSrc = gFalse; + fileName = NULL; + buf = NULL; + refcnt = 1; +} + +SplashFontSrc::~SplashFontSrc() { + if (deleteSrc) { + if (isFile) { + if (fileName) + unlink(fileName->getCString()); + } else { + if (buf) + gfree(buf); + } + } + + if (isFile && fileName) + delete fileName; +} + +void SplashFontSrc::ref() { + refcnt++; +} + +void SplashFontSrc::unref() { + if (! --refcnt) + delete this; +} + +void SplashFontSrc::setFile(GString *file, GBool del) +{ + isFile = gTrue; + fileName = file->copy(); + deleteSrc = del; +} + +void SplashFontSrc::setFile(const char *file, GBool del) +{ + isFile = gTrue; + fileName = new GString(file); + deleteSrc = del; +} + +void SplashFontSrc::setBuf(char *bufA, int bufLenA, GBool del) +{ + isFile = gFalse; + buf = bufA; + bufLen = bufLenA; + deleteSrc = del; +} + diff --git a/xpdf/splash/SplashFontFile.h b/xpdf/splash/SplashFontFile.h index 2fe1def97..0ab0a3e85 100644 --- a/xpdf/splash/SplashFontFile.h +++ b/xpdf/splash/SplashFontFile.h @@ -25,6 +25,25 @@ class SplashFontFileID; // SplashFontFile //------------------------------------------------------------------------ +struct SplashFontSrc { + SplashFontSrc(); + ~SplashFontSrc(); + + void setFile(GString *file, GBool del); + void setFile(const char *file, GBool del); + void setBuf(char *bufA, int buflenA, GBool del); + + void ref(); + void unref(); + + GBool isFile; + GString *fileName; + char *buf; + int bufLen; + GBool deleteSrc; + int refcnt; +}; + class SplashFontFile { public: @@ -46,12 +65,10 @@ public: protected: - SplashFontFile(SplashFontFileID *idA, char *fileNameA, - GBool deleteFileA); + SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA); SplashFontFileID *id; - GString *fileName; - GBool deleteFile; + SplashFontSrc *src; int refCnt; friend class SplashFontEngine; diff --git a/xpdf/splash/SplashT1FontEngine.cc b/xpdf/splash/SplashT1FontEngine.cc index eff0e7feb..0fde8e222 100644 --- a/xpdf/splash/SplashT1FontEngine.cc +++ b/xpdf/splash/SplashT1FontEngine.cc @@ -82,22 +82,25 @@ SplashT1FontEngine::~SplashT1FontEngine() { } SplashFontFile *SplashT1FontEngine::loadType1Font(SplashFontFileID *idA, - char *fileName, - GBool deleteFile, + SplashFontSrc *src, const char **enc) { - return SplashT1FontFile::loadType1Font(this, idA, fileName, deleteFile, enc); + return SplashT1FontFile::loadType1Font(this, idA, src, enc); } SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA, - char *fileName, - GBool deleteFile, + SplashFontSrc *src, const char **enc) { FoFiType1C *ff; GString *tmpFileName; FILE *tmpFile; SplashFontFile *ret; + SplashFontSrc *newsrc; - if (!(ff = FoFiType1C::load(fileName))) { + if (src->isFile) + ff = FoFiType1C::load(src->fileName); + else + ff = new FoFiType1C(src->buf, src->bufLen, gFalse); + if (! ff) return NULL; } tmpFileName = NULL; @@ -108,16 +111,11 @@ SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA, ff->convertToType1(NULL, gTrue, &T1_fileWrite, tmpFile); delete ff; fclose(tmpFile); - ret = SplashT1FontFile::loadType1Font(this, idA, tmpFileName->getCString(), - gTrue, enc); - if (ret) { - if (deleteFile) { - unlink(fileName); - } - } else { - unlink(tmpFileName->getCString()); - } + newsrc = new SplashFontSrc; + newsrc->setFile(tmpFileName, gTrue); delete tmpFileName; + ret = SplashT1FontFile::loadType1Font(this, idA, newsrc, enc); + newsrc->unref(); return ret; } diff --git a/xpdf/splash/SplashT1FontFile.cc b/xpdf/splash/SplashT1FontFile.cc index 099654225..210726eca 100644 --- a/xpdf/splash/SplashT1FontFile.cc +++ b/xpdf/splash/SplashT1FontFile.cc @@ -25,8 +25,7 @@ SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA, SplashFontFileID *idA, - char *fileNameA, - GBool deleteFileA, + SplashFontSrc *src, const char **encA) { int t1libIDA; const char **encTmp; @@ -34,9 +33,27 @@ SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA, int encStrSize; char *encPtr; int i; + GString *fileNameA; + SplashFontSrc *newsrc = NULL; + SplashFontFile *ff; + if (! src->isFile) { + GString *tmpFileName; + FILE *tmpFile; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) + return NULL; + fwrite(src->buf, 1, src->bufLen, tmpFile); + fclose(tmpFile); + newsrc = new SplashFontSrc; + newsrc->setFile(tmpFileName, gTrue); + src = newsrc; + delete tmpFileName; + } + fileNameA = src->fileName; // load the font file if ((t1libIDA = T1_AddFont(fileNameA)) < 0) { + if (newsrc) + delete newsrc; return NULL; } T1_LoadFont(t1libIDA); @@ -63,15 +80,18 @@ SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA, encTmp[256] = "custom"; T1_ReencodeFont(t1libIDA, (char**)encTmp); - return new SplashT1FontFile(engineA, idA, fileNameA, deleteFileA, + ff = new SplashT1FontFile(engineA, idA, src, t1libIDA, encTmp, encStrTmp); + if (newsrc) + newsrc->unref(); + return ff; } SplashT1FontFile::SplashT1FontFile(SplashT1FontEngine *engineA, SplashFontFileID *idA, - char *fileNameA, GBool deleteFileA, + SplashFontSrc *srcA, int t1libIDA, const char **encA, char *encStrA): - SplashFontFile(idA, fileNameA, deleteFileA) + SplashFontFile(idA, srcA) { engine = engineA; t1libID = t1libIDA; diff --git a/xpdf/splash/SplashT1FontFile.h b/xpdf/splash/SplashT1FontFile.h index 8dc8dc10f..86d96165f 100644 --- a/xpdf/splash/SplashT1FontFile.h +++ b/xpdf/splash/SplashT1FontFile.h @@ -28,7 +28,7 @@ public: static SplashFontFile *loadType1Font(SplashT1FontEngine *engineA, SplashFontFileID *idA, - char *fileNameA, GBool deleteFileA, + SplashFontSrc *src, const char **encA); virtual ~SplashT1FontFile(); @@ -41,7 +41,7 @@ private: SplashT1FontFile(SplashT1FontEngine *engineA, SplashFontFileID *idA, - char *fileNameA, GBool deleteFileA, + SplashFontSrc *src, int t1libIDA, const char **encA, char *encStrA); SplashT1FontEngine *engine; diff --git a/xpdf/xpdf/CharCodeToUnicode.h b/xpdf/xpdf/CharCodeToUnicode.h index 04852aea8..f75f4bd75 100644 --- a/xpdf/xpdf/CharCodeToUnicode.h +++ b/xpdf/xpdf/CharCodeToUnicode.h @@ -71,6 +71,8 @@ public: // code supported by the mapping. CharCode getLength() { return mapLen; } + CharCode getMapLen() { return mapLen; } + private: void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits); diff --git a/xpdf/xpdf/GfxFont.cc b/xpdf/xpdf/GfxFont.cc index 4cd968923..9e3ccbe52 100644 --- a/xpdf/xpdf/GfxFont.cc +++ b/xpdf/xpdf/GfxFont.cc @@ -323,7 +323,7 @@ CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits, void GfxFont::findExtFontFile() { static const char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL }; - static const char *ttExts[] = { ".ttf", NULL }; + static const char *ttExts[] = { ".ttf", ".ttc", NULL }; if (name) { if (type == fontType1) { @@ -1442,6 +1442,53 @@ GString *GfxCIDFont::getCollection() { return cMap ? cMap->getCollection() : (GString *)NULL; } +Gushort *GfxCIDFont::getCodeToGIDMap(FoFiTrueType *ff, int *mapsizep) { + Gushort *map; + int cmapPlatform, cmapEncoding; + int /*unicodeCmap, macRomanCmap, msSymbolCmap, */cmap; +// GBool useMacRoman, useUnicode; +// char *charName; + Unicode u; + int /*code, */i; + int mapsize; + int cidlen; + + *mapsizep = 0; + + /* we use only unicode cmap */ + cmap = -1; + for (i = 0; i < ff->getNumCmaps(); ++i) { + cmapPlatform = ff->getCmapPlatform(i); + cmapEncoding = ff->getCmapEncoding(i); + if ((cmapPlatform == 3 && cmapEncoding == 1) || cmapPlatform == 0) + cmap = i; + } + if (cmap < 0) + return NULL; + + cidlen = 0; + mapsize = 64; + map = (Gushort *)gmalloc(mapsize * sizeof(Gushort)); + + while (cidlen < ctu->getMapLen()) { + int n; + if ((n = ctu->mapToUnicode((CharCode)cidlen, &u, 1)) == 0) { + cidlen++; + continue; + } + if (cidlen >= mapsize) { + while (cidlen >= mapsize) + mapsize *= 2; + map = (Gushort *)grealloc(map, mapsize * sizeof(Gushort)); + } + map[cidlen] = ff->mapCodeToGID(cmap, u); + cidlen++; + } + + *mapsizep = cidlen; + return map; +} + //------------------------------------------------------------------------ // GfxFontDict //------------------------------------------------------------------------ diff --git a/xpdf/xpdf/GfxFont.h b/xpdf/xpdf/GfxFont.h index db0e71b69..b50cac142 100644 --- a/xpdf/xpdf/GfxFont.h +++ b/xpdf/xpdf/GfxFont.h @@ -276,6 +276,8 @@ public: Gushort *getCIDToGID() { return cidToGID; } int getCIDToGIDLen() { return cidToGIDLen; } + Gushort *getCodeToGIDMap(FoFiTrueType *ff, int *length); + private: CMap *cMap; // char code --> CID diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index 3d3b1bd16..462c57550 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -27,6 +27,7 @@ #include #include #include +#include #if HAVE_PAPER_H #include #endif @@ -610,6 +611,7 @@ void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash, DisplayFontParamKind kind, GString *fileName, int line) { DisplayFontParam *param, *old; + struct stat statbuf; if (tokens->getLength() < 2) { goto err1; @@ -622,12 +624,24 @@ void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash, goto err2; } param->t1.fileName = ((GString *)tokens->get(2))->copy(); + if (stat((param->t1.fileName->getCString)(), &statbuf)) { + delete param; // silently ignore non-existing files + return; + } break; case displayFontTT: - if (tokens->getLength() != 3) { + if (tokens->getLength() < 3) { goto err2; } param->tt.fileName = ((GString *)tokens->get(2))->copy(); + if (stat((param->tt.fileName->getCString)(), &statbuf)) { + delete param; // silently ignore non-existing files + return; + } + if (tokens->getLength() > 3) + param->tt.faceIndex = atoi(((GString *)tokens->get(3))->getCString()); + else + param->tt.faceIndex = 0; break; } @@ -1083,7 +1097,7 @@ DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { if (res != FcResultMatch || !s) goto fin; ext = rindex((char*)s,'.'); if (!ext) goto fin; - if (!strncasecmp(ext,".ttf",4)) { + if (!strncasecmp(ext,".ttf",4) || !strncasecmp(ext,".ttc",4)) { dfp = new DisplayFontParam(fontName->copy(), displayFontTT); dfp->tt.fileName = new GString((char*)s); } else if (!strncasecmp(ext,".pfa",4) || !strncasecmp(ext,".pfb",4)) { diff --git a/xpdf/xpdf/GlobalParams.h b/xpdf/xpdf/GlobalParams.h index f06bf5318..e6be63121 100644 --- a/xpdf/xpdf/GlobalParams.h +++ b/xpdf/xpdf/GlobalParams.h @@ -60,6 +60,7 @@ public: } t1; struct { GString *fileName; + int faceIndex; } tt; }; diff --git a/xpdf/xpdf/PSOutputDev.cc b/xpdf/xpdf/PSOutputDev.cc index 5dc85d86f..595da7674 100644 --- a/xpdf/xpdf/PSOutputDev.cc +++ b/xpdf/xpdf/PSOutputDev.cc @@ -7,6 +7,7 @@ //======================================================================== #include +#include #ifdef USE_GCC_PRAGMAS #pragma implementation @@ -749,6 +750,7 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, Page *page; PDFRectangle *box; + setlocale(LC_NUMERIC,"POSIX"); // initialize ok = gTrue; outputFunc = outputFuncA; @@ -809,6 +811,7 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, fontFileNameSize = 64; fontFileNameLen = 0; fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *)); + psFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *)); nextTrueTypeNum = 0; font16EncLen = 0; font16EncSize = 0; @@ -890,6 +893,13 @@ PSOutputDev::~PSOutputDev() { } gfree(fontFileNames); } + if (psFileNames) { + for (i = 0; i < fontFileNameLen; ++i) { + if (psFileNames[i]) + delete psFileNames[i]; + } + gfree(psFileNames); + } if (font16Enc) { for (i = 0; i < font16EncLen; ++i) { delete font16Enc[i].enc; @@ -1189,6 +1199,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { double w1, w2; double *fm; int i, j; + DisplayFontParam *dfp; // check if font is already set up for (i = 0; i < fontIDLen; ++i) { @@ -1246,8 +1257,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { } else if (globalParams->getPSEmbedTrueType() && font->getType() == fontTrueType && font->getExtFontFile()) { - psName = filterPSName(font->getName()); - setupExternalTrueTypeFont(font, psName); + psName = setupExternalTrueTypeFont(font); // check for embedded CID PostScript font } else if (globalParams->getPSEmbedCIDPostScript() && @@ -1269,6 +1279,12 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { psName = new GString(type3Name); setupType3Font(font, psName, parentResDict); + // check for external CID TrueType font file + } else if (globalParams->getPSEmbedCIDTrueType() && + font->getType() == fontCIDType2 && + font->getExtFontFile()) { + psName = setupExternalCIDTrueTypeFont(font, font->getExtFontFile()); + // do 8-bit font substitution } else if (!font->isCIDFont()) { subst = gTrue; @@ -1350,6 +1366,15 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { font16Enc[font16EncLen].enc->getCString()); } + // try the display font for embedding + } else if (globalParams->getPSEmbedCIDTrueType() && + ((GfxCIDFont *)font)->getCollection() && + (dfp = globalParams-> + getDisplayCIDFont(font->getName(), + ((GfxCIDFont *)font)->getCollection())) && + dfp->kind == displayFontTT) { + psName = setupExternalCIDTrueTypeFont(font, dfp->tt.fileName, dfp->tt.faceIndex); + // give up - can't do anything with this font } else { error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)", @@ -1551,8 +1576,12 @@ void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) { fontFileNameSize += 64; fontFileNames = (GString **)grealloc(fontFileNames, fontFileNameSize * sizeof(GString *)); + psFileNames = (GString **)grealloc(psFileNames, + fontFileNameSize * sizeof(GString *)); } - fontFileNames[fontFileNameLen++] = fileName->copy(); + fontFileNames[fontFileNameLen] = fileName->copy(); + psFileNames[fontFileNameLen] = psName->copy(); + fontFileNameLen++; // beginning comment writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); @@ -1665,25 +1694,24 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, writePS("%%EndResource\n"); } -void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) { - char unique[32]; +GString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) { GString *fileName; char *fontBuf; int fontLen; FoFiTrueType *ffTT; Gushort *codeToGID; + GString *psName; int i; // check if font is already embedded fileName = font->getExtFontFile(); for (i = 0; i < fontFileNameLen; ++i) { if (!fontFileNames[i]->cmp(fileName)) { - sprintf(unique, "_%d", nextTrueTypeNum++); - psName->append(unique); - break; + return psFileNames[i]->copy(); } } + psName = filterPSName(font->getName()); // add entry to fontFileNames list if (i == fontFileNameLen) { if (fontFileNameLen >= fontFileNameSize) { @@ -1691,9 +1719,14 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) { fontFileNames = (GString **)grealloc(fontFileNames, fontFileNameSize * sizeof(GString *)); + psFileNames = + (GString **)grealloc(psFileNames, + fontFileNameSize * sizeof(GString *)); } } - fontFileNames[fontFileNameLen++] = fileName->copy(); + fontFileNames[fontFileNameLen] = fileName->copy(); + psFileNames[fontFileNameLen] = psName->copy(); + fontFileNameLen++; // beginning comment writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); @@ -1716,6 +1749,82 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) { // ending comment writePS("%%EndResource\n"); + return psName; +} + +GString *PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, int faceIndex) { +// char *fontBuf; +// int fontLen; + FoFiTrueType *ffTT; + Gushort *codeToGID; + GString *psName; + int i; + GString *myFileName; + + myFileName = fileName->copy(); + if (faceIndex > 0) { + char tmp[32]; + sprintf(tmp, ",%d", faceIndex); + myFileName->append(tmp); + } + // check if font is already embedded + for (i = 0; i < fontFileNameLen; ++i) { + if (!fontFileNames[i]->cmp(myFileName)) { + delete myFileName; + return psFileNames[i]->copy(); + } + } + + psName = filterPSName(font->getName()); + // add entry to fontFileNames list + if (i == fontFileNameLen) { + if (fontFileNameLen >= fontFileNameSize) { + fontFileNameSize += 64; + fontFileNames = + (GString **)grealloc(fontFileNames, + fontFileNameSize * sizeof(GString *)); + psFileNames = + (GString **)grealloc(psFileNames, + fontFileNameSize * sizeof(GString *)); + } + } + fontFileNames[fontFileNameLen] = myFileName; + psFileNames[fontFileNameLen] = psName->copy(); + fontFileNameLen++; + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a CID type2 font + if ((ffTT = FoFiTrueType::load(fileName->getCString(), faceIndex))) { + int n = ((GfxCIDFont *)font)->getCIDToGIDLen(); + if (n) { + codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort)); + memcpy(codeToGID, ((GfxCIDFont *)font)->getCIDToGID(), n * sizeof(Gushort)); + } else { + codeToGID = ((GfxCIDFont *)font)->getCodeToGIDMap(ffTT, &n); + } + if (globalParams->getPSLevel() >= psLevel3) { + // Level 3: use a CID font + ffTT->convertToCIDType2(psName->getCString(), + codeToGID, n, + outputFunc, outputStream); + } else { + // otherwise: use a non-CID composite font + ffTT->convertToType0(psName->getCString(), + codeToGID, n, + outputFunc, outputStream); + } + gfree(codeToGID); + delete ffTT; + } + + // ending comment + writePS("%%EndResource\n"); + return psName; } void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, diff --git a/xpdf/xpdf/PSOutputDev.h b/xpdf/xpdf/PSOutputDev.h index 7da347300..99b4583e9 100644 --- a/xpdf/xpdf/PSOutputDev.h +++ b/xpdf/xpdf/PSOutputDev.h @@ -206,9 +206,10 @@ private: void setupExternalType1Font(GString *fileName, GString *psName); void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName); void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName); - void setupExternalTrueTypeFont(GfxFont *font, GString *psName); + GString *setupExternalTrueTypeFont(GfxFont *font); void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName); void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName); + GString *setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, int faceIndex=0); void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict); void setupImages(Dict *resDict); void setupImage(Ref id, Stream *str); @@ -265,6 +266,7 @@ private: int fontFileIDLen; // number of entries in fontFileIDs array int fontFileIDSize; // size of fontFileIDs array GString **fontFileNames; // list of names of all embedded external fonts + GString **psFileNames; // list of names of all embedded external ps names int fontFileNameLen; // number of entries in fontFileNames array int fontFileNameSize; // size of fontFileNames array int nextTrueTypeNum; // next unique number to append to a TrueType diff --git a/xpdf/xpdf/SplashOutputDev.cc b/xpdf/xpdf/SplashOutputDev.cc index 10c51b116..9ccf5b883 100644 --- a/xpdf/xpdf/SplashOutputDev.cc +++ b/xpdf/xpdf/SplashOutputDev.cc @@ -490,11 +490,14 @@ void SplashOutputDev::updateFont(GfxState *state) { GfxFontType fontType; SplashOutFontFileID *id; SplashFontFile *fontFile; + SplashFontSrc *fontsrc; FoFiTrueType *ff; Ref embRef; Object refObj, strObj; - GString *tmpFileName, *fileName, *substName; - FILE *tmpFile; + GString *fileName, *substName; + char *tmpBuf; + int tmpBufLen; +// FILE *tmpFile; Gushort *codeToGID; DisplayFontParam *dfp; CharCodeToUnicode *ctu; @@ -502,11 +505,13 @@ void SplashOutputDev::updateFont(GfxState *state) { SplashCoord mat[4]; const char *name; Unicode uBuf[8]; - int c, substIdx, n, code, cmap; + int /*c, */substIdx, n, code, cmap; + int faceIndex = 0; needFontUpdate = gFalse; font = NULL; - tmpFileName = NULL; + fileName = NULL; + tmpBuf = NULL; substIdx = -1; dfp = NULL; @@ -527,22 +532,9 @@ void SplashOutputDev::updateFont(GfxState *state) { // if there is an embedded font, write it to disk if (gfxFont->getEmbeddedFontID(&embRef)) { - if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { - error(-1, "Couldn't create temporary font file"); + tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen); + if (! tmpBuf) goto err2; - } - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(xref, &strObj); - refObj.free(); - strObj.streamReset(); - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, tmpFile); - } - strObj.streamClose(); - strObj.free(); - fclose(tmpFile); - fileName = tmpFileName; - // if there is an external font file, use it } else if (!(fileName = gfxFont->getExtFontFile())) { @@ -588,6 +580,7 @@ void SplashOutputDev::updateFont(GfxState *state) { case displayFontT1: fileName = dfp->t1.fileName; fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1; + faceIndex = dfp->tt.faceIndex; break; case displayFontTT: fileName = dfp->tt.fileName; @@ -596,14 +589,18 @@ void SplashOutputDev::updateFont(GfxState *state) { } } + fontsrc = new SplashFontSrc; + if (fileName) + fontsrc->setFile(fileName, gFalse); + else + fontsrc->setBuf(tmpBuf, tmpBufLen, gFalse); + // load the font file switch (fontType) { case fontType1: - if (!(fontFile = fontEngine->loadType1Font( - id, - fileName->getCString(), - fileName == tmpFileName, - ((Gfx8BitFont *)gfxFont)->getEncoding()))) { + fontFile = fontEngine->loadType1Font(id, fontsrc, + ((Gfx8BitFont *)gfxFont)->getEncoding()); + if (! fontFile) { error(-1, "Couldn't create a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); @@ -611,11 +608,9 @@ void SplashOutputDev::updateFont(GfxState *state) { } break; case fontType1C: - if (!(fontFile = fontEngine->loadType1CFont( - id, - fileName->getCString(), - fileName == tmpFileName, - ((Gfx8BitFont *)gfxFont)->getEncoding()))) { + fontFile = fontEngine->loadType1CFont(id, fontsrc, + ((Gfx8BitFont *)gfxFont)->getEncoding()); + if (! fontFile) { error(-1, "Couldn't create a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); @@ -623,16 +618,16 @@ void SplashOutputDev::updateFont(GfxState *state) { } break; case fontTrueType: - if (!(ff = FoFiTrueType::load(fileName->getCString()))) { + if (fileName) + ff = FoFiTrueType::load(fileName->getCString()); + else + ff = new FoFiTrueType(tmpBuf, tmpBufLen, gFalse); + if (! ff) goto err2; - } codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff); delete ff; - if (!(fontFile = fontEngine->loadTrueTypeFont( - id, - fileName->getCString(), - fileName == tmpFileName, - codeToGID, 256))) { + fontFile = fontEngine->loadTrueTypeFont(id, fontsrc, codeToGID, 256); + if (! fontFile) { error(-1, "Couldn't create a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); @@ -641,10 +636,8 @@ void SplashOutputDev::updateFont(GfxState *state) { break; case fontCIDType0: case fontCIDType0C: - if (!(fontFile = fontEngine->loadCIDFont( - id, - fileName->getCString(), - fileName == tmpFileName))) { + fontFile = fontEngine->loadCIDFont(id, fontsrc); + if (! fontFile) { error(-1, "Couldn't create a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); @@ -692,13 +685,19 @@ void SplashOutputDev::updateFont(GfxState *state) { codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort)); memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), n * sizeof(Gushort)); + } else { + if (fileName) + ff = FoFiTrueType::load(fileName->getCString()); + else + ff = new FoFiTrueType(tmpBuf, tmpBufLen, gFalse); + if (! ff) + goto err2; + codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n); + delete ff; } } - if (!(fontFile = fontEngine->loadTrueTypeFont( - id, - fileName->getCString(), - fileName == tmpFileName, - codeToGID, n))) { + fontFile = fontEngine->loadTrueTypeFont(id, fontsrc, codeToGID, n, faceIndex); + if (!fontFile) { error(-1, "Couldn't create a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); @@ -746,17 +745,11 @@ void SplashOutputDev::updateFont(GfxState *state) { mat[2] = m21; mat[3] = -m22; font = fontEngine->getFont(fontFile, mat); - if (tmpFileName) { - delete tmpFileName; - } return; err2: delete id; err1: - if (tmpFileName) { - delete tmpFileName; - } return; } @@ -1374,8 +1367,9 @@ SplashFont *SplashOutputDev::getFont(GString *name, double *mat) { if (dfp->kind != displayFontT1) { return NULL; } - fontFile = fontEngine->loadType1Font(id, dfp->t1.fileName->getCString(), - gFalse, winAnsiEncoding); + SplashFontSrc *fontsrc = new SplashFontSrc; + fontsrc->setFile(dfp->t1.fileName, gFalse); + fontFile = fontEngine->loadType1Font(id, fontsrc, winAnsiEncoding); } // create the scaled font From a8e70b4374701cbbf08433a37a7206799b9beea0 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 14 Mar 2005 22:18:42 +0000 Subject: [PATCH 018/245] Make presentation widget wheel behave the same that when on scrollview, down next page, up previous page BUG: 101519 svn path=/trunk/kdegraphics/kpdf/; revision=397655 --- ui/presentationwidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index a414282af..bbf4a3c09 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -194,14 +194,14 @@ void PresentationWidget::wheelEvent( QWheelEvent * e ) if ( div > 3 ) div = 3; while ( div-- ) - slotNextPage(); + slotPrevPage(); } else if ( div < 0 ) { if ( div < -3 ) div = -3; while ( div++ ) - slotPrevPage(); + slotNextPage(); } } From d4a5bf2c231912bf4e0a51bfb71f6b19ab0daafb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 15 Mar 2005 22:26:40 +0000 Subject: [PATCH 019/245] Understand Futura-CondensedBold and Futura-CondensedLight svn path=/trunk/kdegraphics/kpdf/; revision=397924 --- xpdf/xpdf/GlobalParams.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index 462c57550..692c540d1 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -1058,7 +1058,7 @@ FILE *GlobalParams::findToUnicodeFile(GString *name) { // KPDF: parse xpdf font name into family and style // Helvetica-BoldOblique => name=Helvetica, weight=Bold, slant=Oblique -void parseStyle(QString& name, int& weight, int& slant) +void parseStyle(QString& name, int& weight, int& slant, int& width) { if (name.find("MS-") == 0) name = "MS " + name.remove(0,3); @@ -1068,28 +1068,28 @@ void parseStyle(QString& name, int& weight, int& slant) if (type.contains("Oblique")) slant=FC_SLANT_OBLIQUE; if (type.contains("Italic")) slant=FC_SLANT_ITALIC; if (type.contains("Bold")) weight=FC_WEIGHT_BOLD; + if (type.contains("Light")) weight=FC_WEIGHT_LIGHT; + if (type.contains("Condensed")) width=FC_WIDTH_CONDENSED; } - - DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { DisplayFontParam *dfp; FcPattern *p=0,*m=0; FcChar8* s; char * ext; FcResult res; - lockGlobalParams; dfp = (DisplayFontParam *)displayFonts->lookup(fontName); // KPDF: try to find font using Xft if (!dfp) { - int weight=FC_WEIGHT_MEDIUM, slant=FC_SLANT_ROMAN; + int weight=FC_WEIGHT_MEDIUM, slant=FC_SLANT_ROMAN, width=FC_WIDTH_NORMAL; QString name(fontName->getCString()); - parseStyle(name,weight,slant); + + parseStyle(name,weight,slant,width); p = FcPatternBuild(0,FC_FAMILY,FcTypeString, name.ascii(), FC_SLANT, FcTypeInteger, slant, FC_WEIGHT, FcTypeInteger, weight, - FC_LANG, FcTypeString, "xx", (char*)0); + FC_WIDTH, FcTypeInteger, width, FC_LANG, FcTypeString, "xx", (char*)0); if (!p) goto fin; m = XftFontMatch(qt_xdisplay(),qt_xscreen(),p,&res); if (!m) goto fin; From 1e8160ad99e5e567d997243cd1a3b963fddd3e2c Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 15 Mar 2005 23:31:22 +0000 Subject: [PATCH 020/245] Really use faceindex for TTC collections svn path=/trunk/kdegraphics/kpdf/; revision=397950 --- xpdf/xpdf/GlobalParams.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index 692c540d1..5b120ddda 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -1092,7 +1092,7 @@ DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { FC_WIDTH, FcTypeInteger, width, FC_LANG, FcTypeString, "xx", (char*)0); if (!p) goto fin; m = XftFontMatch(qt_xdisplay(),qt_xscreen(),p,&res); - if (!m) goto fin; + if (!m) goto fin; res = FcPatternGetString (m, FC_FILE, 0, &s); if (res != FcResultMatch || !s) goto fin; ext = rindex((char*)s,'.'); @@ -1100,6 +1100,7 @@ DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { if (!strncasecmp(ext,".ttf",4) || !strncasecmp(ext,".ttc",4)) { dfp = new DisplayFontParam(fontName->copy(), displayFontTT); dfp->tt.fileName = new GString((char*)s); + FcPatternGetInteger(m, FC_INDEX, 0, &(dfp->tt.faceIndex)); } else if (!strncasecmp(ext,".pfa",4) || !strncasecmp(ext,".pfb",4)) { dfp = new DisplayFontParam(fontName->copy(), displayFontT1); dfp->t1.fileName = new GString((char*)s); From bdfb693d3e1ea36e86d66067370d7677d1e864f5 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 16 Mar 2005 21:52:28 +0000 Subject: [PATCH 021/245] Welcome the fonts dialog, as normal the from xpdf source is our inspiration, this time pdffonts.cc Enrico, maybe you don't like the way of filling the KListView, the properties dialog asks the document if it has fonts (in the future maybe we support formats that don't have fonts), then create the KListView and pass it to the document that passes it to the generator that fills it, the "problem" is that now the generators are GUI aware. svn path=/trunk/kdegraphics/kpdf/; revision=398206 --- core/document.cpp | 10 ++ core/document.h | 3 + core/generator.h | 5 + core/generator_pdf/generator_pdf.cpp | 184 +++++++++++++++++++++++++++ core/generator_pdf/generator_pdf.h | 10 ++ ui/propertiesdialog.cpp | 16 ++- 6 files changed, 226 insertions(+), 2 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index e6093cb85..09199ab1f 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -381,6 +381,16 @@ QString KPDFDocument::getMetaData( const QString & key, const QString & option ) return generator ? generator->getMetaData( key, option ) : QString(); } +bool KPDFDocument::hasFonts() const +{ + return generator ? generator->hasFonts() : false; +} + +void KPDFDocument::putFontInfo(KListView *list) +{ + if (generator) generator->putFontInfo(list); +} + void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & requests ) { if ( !generator ) diff --git a/core/document.h b/core/document.h index e845f94db..725a5bc39 100644 --- a/core/document.h +++ b/core/document.h @@ -24,6 +24,7 @@ class DocumentInfo; class DocumentSynopsis; class Generator; class PixmapRequest; +class KListView; class KPrinter; class KURL; @@ -75,6 +76,8 @@ class KPDFDocument : public QObject bool historyAtBegin() const; bool historyAtEnd() const; QString getMetaData( const QString & key, const QString & option = QString() ) const; + bool hasFonts() const; + void putFontInfo(KListView *list); // perform actions on document / pages void setViewportPage( int page, int excludeId = -1, bool smoothMove = false ); diff --git a/core/generator.h b/core/generator.h index 9561d8b2b..4a53a0a2b 100644 --- a/core/generator.h +++ b/core/generator.h @@ -14,6 +14,7 @@ #include #include #include "core/document.h" +class KListView; class KPrinter; class KPDFPage; class KPDFLink; @@ -58,6 +59,10 @@ class Generator : public QObject virtual void generatePixmap( PixmapRequest * request ) = 0; virtual void generateSyncTextPage( KPDFPage * page ) = 0; + // font related + virtual bool hasFonts() const = 0; + virtual void putFontInfo(KListView *list) = 0; + // print document using already configured kprinter virtual bool print( KPrinter& /*printer*/ ) { return false; } // access meta data of the generator diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 330e6b557..65f882ae9 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,9 @@ #include // xpdf includes +#include "xpdf/Object.h" +#include "xpdf/Dict.h" +#include "xpdf/Annot.h" #include "xpdf/PSOutputDev.h" #include "xpdf/TextOutputDev.h" #include "xpdf/Link.h" @@ -338,6 +342,61 @@ void PDFGenerator::generateSyncTextPage( KPDFPage * page ) docLock.unlock(); } +bool PDFGenerator::hasFonts() const +{ + return true; +} + +void PDFGenerator::putFontInfo(KListView *list) +{ + Page *page; + Dict *resDict; + Annots *annots; + Object obj1, obj2; + int pg, i; + + Ref *fonts; + int fontsLen; + int fontsSize; + + list->addColumn(i18n("Name")); + list->addColumn(i18n("Type")); + list->addColumn(i18n("Embedded")); + list->addColumn(i18n("File")); + + docLock.lock(); + + fonts = NULL; + fontsLen = fontsSize = 0; + for (pg = 1; pg <= pdfdoc->getNumPages(); ++pg) + { + page = pdfdoc->getCatalog()->getPage(pg); + if ((resDict = page->getResourceDict())) + { + scanFonts(resDict, list, &fonts, fontsLen, fontsSize); + } + annots = new Annots(pdfdoc->getXRef(), page->getAnnots(&obj1)); + obj1.free(); + for (i = 0; i < annots->getNumAnnots(); ++i) + { + if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) + { + obj1.streamGetDict()->lookup("Resources", &obj2); + if (obj2.isDict()) + { + scanFonts(obj2.getDict(), list, &fonts, fontsLen, fontsSize); + } + obj2.free(); + } + obj1.free(); + } + delete annots; + } + gfree(fonts); + + docLock.unlock(); +} + bool PDFGenerator::print( KPrinter& printer ) { QString ps = printer.option("PageSize"); @@ -467,6 +526,131 @@ static QString unicodeToQString(Unicode* u, int len) { return ret; } +void PDFGenerator::scanFonts(Dict *resDict, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize) +{ + Object obj1, obj2, xObjDict, xObj, resObj; + Ref r; + GfxFontDict *gfxFontDict; + GfxFont *font; + int i; + + // scan the fonts in this resource dictionary + gfxFontDict = NULL; + resDict->lookupNF("Font", &obj1); + if (obj1.isRef()) + { + obj1.fetch(pdfdoc->getXRef(), &obj2); + if (obj2.isDict()) + { + r = obj1.getRef(); + gfxFontDict = new GfxFontDict(pdfdoc->getXRef(), &r, obj2.getDict()); + } + obj2.free(); + } + else if (obj1.isDict()) + { + gfxFontDict = new GfxFontDict(pdfdoc->getXRef(), NULL, obj1.getDict()); + } + if (gfxFontDict) + { + for (i = 0; i < gfxFontDict->getNumFonts(); ++i) + { + if ((font = gfxFontDict->getFont(i))) scanFont(font, list, fonts, fontsLen, fontsSize); + } + delete gfxFontDict; + } + obj1.free(); + + // recursively scan any resource dictionaries in objects in this + // resource dictionary + resDict->lookup("XObject", &xObjDict); + if (xObjDict.isDict()) + { + for (i = 0; i < xObjDict.dictGetLength(); ++i) + { + xObjDict.dictGetVal(i, &xObj); + if (xObj.isStream()) + { + xObj.streamGetDict()->lookup("Resources", &resObj); + if (resObj.isDict()) scanFonts(resObj.getDict(), list, fonts, fontsLen, fontsSize); + resObj.free(); + } + xObj.free(); + } + } + xObjDict.free(); +} + +void PDFGenerator::scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize) +{ + Ref fontRef, embRef; + Object fontObj, toUnicodeObj; + GString *name; + GBool emb; + int i; + + QString fontTypeNames[8] = { + i18n("unknown"), + i18n("Type 1"), + i18n("Type 1C"), + i18n("Type 3"), + i18n("TrueType"), + i18n("CID Type 0"), + i18n("CID Type 0C"), + i18n("CID TrueType") + }; + + fontRef = *font->getID(); + + // check for an already-seen font + for (i = 0; i < fontsLen; ++i) + { + if (fontRef.num == (*fonts)[i].num && fontRef.gen == (*fonts)[i].gen) + { + return; + } + } + + // font name + name = font->getOrigName(); + + // check for an embedded font + if (font->getType() == fontType3) emb = gTrue; + else emb = font->getEmbeddedFontID(&embRef); + + QString sName, sEmb, sPath; + if (name) + { + sName = name->getCString(); + if (!emb) + { + DisplayFontParam *dfp = globalParams->getDisplayFont(name); + if (dfp) + { + if (dfp -> kind == displayFontT1) sPath = dfp->t1.fileName->getCString(); + else sPath = dfp->tt.fileName->getCString(); + } + else sPath = i18n("-"); + } + else sPath = i18n("-"); + } + else + { + sName = i18n("[none]"); + sPath = i18n("-"); + } + sEmb = emb ? i18n("Yes") : i18n("No"); + new KListViewItem(list, sName, fontTypeNames[font->getType()], sEmb, sPath); + + // add this font to the list + if (fontsLen == fontsSize) + { + fontsSize += 32; + *fonts = (Ref *)grealloc(*fonts, fontsSize * sizeof(Ref)); + } + (*fonts)[fontsLen++] = *font->getID(); +} + QString PDFGenerator::getDocumentInfo( const QString & data ) const // note: MUTEX is LOCKED while calling this { diff --git a/core/generator_pdf/generator_pdf.h b/core/generator_pdf/generator_pdf.h index 5e0ab076b..0a3a4e416 100644 --- a/core/generator_pdf/generator_pdf.h +++ b/core/generator_pdf/generator_pdf.h @@ -19,6 +19,9 @@ #include "core/document.h" #include "core/link.h" +class Dict; +class GfxFont; +class Ref; class PDFDoc; class GList; class TextPage; @@ -62,6 +65,10 @@ class PDFGenerator : public Generator void generatePixmap( PixmapRequest * request ); void generateSyncTextPage( KPDFPage * page ); + // font related + bool hasFonts() const; + void putFontInfo(KListView *list); + // [INHERITED] print page using an already configured kprinter bool print( KPrinter& printer ); @@ -75,6 +82,9 @@ class PDFGenerator : public Generator // friend class to access private document related variables friend class PDFPixmapGeneratorThread; + void scanFonts(Dict *resDict, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize); + void scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize); + // private functions for accessing document informations via PDFDoc QString getDocumentInfo( const QString & data ) const; QString getDocumentDate( const QString & data ) const; diff --git a/ui/propertiesdialog.cpp b/ui/propertiesdialog.cpp index 701e7cf99..993b0682e 100644 --- a/ui/propertiesdialog.cpp +++ b/ui/propertiesdialog.cpp @@ -9,6 +9,7 @@ // qt/kde includes #include +#include #include #include @@ -17,9 +18,10 @@ #include "core/document.h" PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) - : KDialogBase( Plain, i18n( "Unknown File" ), Ok, Ok, parent, 0, true, true ) + : KDialogBase( Tabbed, i18n( "Unknown File" ), Ok, Ok, parent, 0, true, true ) { - QWidget *page = plainPage(); + // Properties + QFrame *page = addPage(i18n("Properties")); QGridLayout *layout = new QGridLayout( page, 2, 2, marginHint(), spacingHint() ); // get document info, if not present display blank data and a warning @@ -59,4 +61,14 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) layout->addWidget( key, row, 0 ); layout->addWidget( value, row, 1 ); } + + if (doc->hasFonts()) + { + // Properties + page = addPage(i18n("Fonts")); + QVBoxLayout *topLayout = new QVBoxLayout(page, 0, KDialog::spacingHint()); + KListView *lv = new KListView(page); + topLayout->add(lv); + doc->putFontInfo(lv); + } } From c3ba0f58dfade6a40e6f5e509f5cabb81da9a428 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 16 Mar 2005 22:00:28 +0000 Subject: [PATCH 022/245] As always i forget to update the TODO file svn path=/trunk/kdegraphics/kpdf/; revision=398209 --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 96e83d65d..ffb997b33 100644 --- a/TODO +++ b/TODO @@ -73,6 +73,7 @@ More items (first items will enter 'In progress list' first): Done (newest features come first): -- merging from kdpf_annotations branch -- +-> ADD: Put fonts used by the document on the properties dialog -> ADD: partial implementation of XYZ links -> ADD: google-like search on thumbnails -> ADD: use kde wallet for storing passwords of protected files From 0649174a87ef08e4e466b146614b6564b907cb44 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 16 Mar 2005 22:26:28 +0000 Subject: [PATCH 023/245] Fix bug 101648, thanks a lot for reporting Mikolaj Do not assume that there can be only one objectrect in a given point, remove const ObjectRect * KPDFPage::getObjectRect( double x, double y ) const and add const ObjectRect * KPDFPage::hasObject( ObjectRect::ObjectType type, double x, double y ) const instead BUGS:101648 svn path=/trunk/kdegraphics/kpdf/; revision=398214 --- core/page.cpp | 4 +- core/page.h | 104 ++++++++++++++++++++++++------------------------ ui/pageview.cpp | 28 ++++++------- 3 files changed, 67 insertions(+), 69 deletions(-) diff --git a/core/page.cpp b/core/page.cpp index 0cf955511..4fe607888 100644 --- a/core/page.cpp +++ b/core/page.cpp @@ -173,12 +173,12 @@ const QString KPDFPage::getText( const NormalizedRect & rect ) const return result; } -const ObjectRect * KPDFPage::getObjectRect( double x, double y ) const +const ObjectRect * KPDFPage::hasObject( ObjectRect::ObjectType type, double x, double y ) const { QValueList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end(); for ( ; it != end; ++it ) if ( (*it)->contains( x, y ) ) - return *it; + if ((*it)->objectType() == type) return *it; return 0; } diff --git a/core/page.h b/core/page.h index 596a3a23f..ebd6e5224 100644 --- a/core/page.h +++ b/core/page.h @@ -17,11 +17,59 @@ class QPixmap; class QRect; class TextPage; class KPDFPageTransition; -class NormalizedRect; -class ObjectRect; class HighlightRect; class Annotation; +/** + * @short A rect in normalized [0,1] coordinates. + */ +class NormalizedRect +{ + public: + double left, top, right, bottom; + + NormalizedRect(); + NormalizedRect( double l, double t, double r, double b ); + NormalizedRect( const QRect & r, double xScale, double yScale ); + + bool contains( double x, double y ) const; + bool intersects( const NormalizedRect & normRect ) const; + bool intersects( double l, double t, double r, double b ) const; + + QRect geometry( int xScale, int yScale ) const; +}; + +/** + * @short NormalizedRect that contains a reference to an object. + * + * These rects contains a pointer to a kpdf object (such as a link or something + * like that). The pointer is read and stored as 'void pointer' so cast is + * performed by accessors based on the value returned by objectType(). Objects + * are reparented to this class. + * + * Type / Class correspondency tab: + * - Link : class KPDFLink : description of a link + * - Image : class KPDFImage : description of an image (n/a) + */ +class ObjectRect : public NormalizedRect +{ + public: + // definition of the types of storable objects + enum ObjectType { Link, Image }; + + // default constructor: initialize all parameters + ObjectRect( double l, double t, double r, double b, ObjectType typ, void * obj ); + ~ObjectRect(); + + // query type and get a const pointer to the stored object + inline ObjectType objectType() const { return m_objectType; } + inline const void * pointer() const { return m_pointer; } + + private: + ObjectType m_objectType; + void * m_pointer; +}; + /** * @short Collector for all the data belonging to a page. * @@ -56,7 +104,7 @@ class KPDFPage NormalizedRect * findText( const QString & text, bool keepCase, NormalizedRect * last = 0 ) const; const QString getText( const NormalizedRect & rect ) const; - const ObjectRect * getObjectRect( double x, double y ) const; + const ObjectRect * hasObject( ObjectRect::ObjectType type, double x, double y ) const; //const Annotation * getAnnotation( double x, double y ) const; const KPDFPageTransition * getTransition() const; @@ -87,56 +135,6 @@ class KPDFPage }; -/** - * @short A rect in normalized [0,1] coordinates. - */ -class NormalizedRect -{ - public: - double left, top, right, bottom; - - NormalizedRect(); - NormalizedRect( double l, double t, double r, double b ); - NormalizedRect( const QRect & r, double xScale, double yScale ); - - bool contains( double x, double y ) const; - bool intersects( const NormalizedRect & normRect ) const; - bool intersects( double l, double t, double r, double b ) const; - - QRect geometry( int xScale, int yScale ) const; -}; - -/** - * @short NormalizedRect that contains a reference to an object. - * - * These rects contains a pointer to a kpdf object (such as a link or something - * like that). The pointer is read and stored as 'void pointer' so cast is - * performed by accessors based on the value returned by objectType(). Objects - * are reparented to this class. - * - * Type / Class correspondency tab: - * - Link : class KPDFLink : description of a link - * - Image : class KPDFImage : description of an image (n/a) - */ -class ObjectRect : public NormalizedRect -{ - public: - // definition of the types of storable objects - enum ObjectType { Link, Image }; - - // default constructor: initialize all parameters - ObjectRect( double l, double t, double r, double b, ObjectType typ, void * obj ); - ~ObjectRect(); - - // query type and get a const pointer to the stored object - inline ObjectType objectType() const { return m_objectType; } - inline const void * pointer() const { return m_pointer; } - - private: - ObjectType m_objectType; - void * m_pointer; -}; - /** * Internal Storage: normalized colored highlight owned by id */ diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 667270a38..765de84b7 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -887,21 +887,22 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) { double nX = (double)(e->x() - pageItem->geometry().left()) / (double)pageItem->width(), nY = (double)(e->y() - pageItem->geometry().top()) / (double)pageItem->height(); - const ObjectRect * rect = pageItem->page()->getObjectRect( nX, nY ); + const ObjectRect * rect; + rect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY ); if ( rect ) { - // handle click over a link/image - switch ( rect->objectType() ) - { - case ObjectRect::Link:{ - const KPDFLink * link = static_cast< const KPDFLink * >( rect->pointer() ); - d->document->processLink( link ); - }break; - case ObjectRect::Image: - break; - } + // handle click over a link + const KPDFLink * link = static_cast< const KPDFLink * >( rect->pointer() ); + d->document->processLink( link ); } - else + + rect = pageItem->page()->hasObject( ObjectRect::Image, nX, nY ); + if ( rect ) + { + // handle click over a image + } + + if (!rect) { // if not on a rect, the click selects the page d->document->setViewportPage( pageItem->pageNumber(), PAGEVIEW_ID ); @@ -1470,8 +1471,7 @@ void PageView::updateCursor( const QPoint &p ) nY = (double)(p.y() - pageItem->geometry().top()) / (double)pageItem->height(); // if over a ObjectRect (of type Link) change cursor to hand - const ObjectRect * r = pageItem->page()->getObjectRect( nX, nY ); - d->mouseOnRect = r && r->objectType() == ObjectRect::Link; + d->mouseOnRect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY ); if ( d->mouseOnRect ) setCursor( pointingHandCursor ); else From 148f8606f6f3dc7594e641769452c68aa9f501b6 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 17 Mar 2005 21:07:02 +0000 Subject: [PATCH 024/245] Save zoom setting on exit Thanks Fred for the patch FEATURE: 97307 svn path=/trunk/kdegraphics/kpdf/; revision=398502 --- TODO | 1 + conf/kpdf.kcfg | 10 ++++++++++ ui/pageview.cpp | 8 ++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index ffb997b33..d94cc189c 100644 --- a/TODO +++ b/TODO @@ -73,6 +73,7 @@ More items (first items will enter 'In progress list' first): Done (newest features come first): -- merging from kdpf_annotations branch -- +-> ADD: Save zoom setting on exit -> ADD: Put fonts used by the document on the properties dialog -> ADD: partial implementation of XYZ links -> ADD: google-like search on thumbnails diff --git a/conf/kpdf.kcfg b/conf/kpdf.kcfg index 64d343250..757cf8de4 100644 --- a/conf/kpdf.kcfg +++ b/conf/kpdf.kcfg @@ -78,6 +78,16 @@ 1 8 + + 0 + 0 + 2 + + + 1.0 + 0.1 + 4.0 + diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 765de84b7..e300c795a 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -127,8 +127,8 @@ PageView::PageView( QWidget *parent, KPDFDocument *document ) // create and initialize private storage structure d = new PageViewPrivate(); d->document = document; - d->zoomMode = ZoomFixed; - d->zoomFactor = 1.0; + d->zoomMode = (PageView::ZoomMode)Settings::zoomMode(); + d->zoomFactor = Settings::zoomFactor(); d->mouseMode = MouseNormal; d->mouseMidStartY = -1; d->mouseOnRect = false; @@ -1413,6 +1413,10 @@ void PageView::updateZoom( ZoomMode newZoomMode ) d->aZoomFitWidth->setChecked( checkedZoomAction == d->aZoomFitWidth ); d->aZoomFitPage->setChecked( checkedZoomAction == d->aZoomFitPage ); d->aZoomFitText->setChecked( checkedZoomAction == d->aZoomFitText ); + + // save selected zoom factor + Settings::setZoomMode(newZoomMode); + Settings::setZoomFactor(newFactor); } } From 8834a83f9053749fbc5f71b0412775f8465f65e8 Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Sat, 19 Mar 2005 13:05:51 +0000 Subject: [PATCH 025/245] compile (gcc 4.1) svn path=/trunk/kdegraphics/kpdf/; revision=398947 --- xpdf/xpdf/TextOutputDev.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/xpdf/xpdf/TextOutputDev.h b/xpdf/xpdf/TextOutputDev.h index 2c622376f..80f692273 100644 --- a/xpdf/xpdf/TextOutputDev.h +++ b/xpdf/xpdf/TextOutputDev.h @@ -25,6 +25,7 @@ class GList; class GfxFont; class GfxState; class UnicodeMap; +class TextLineFrag; //------------------------------------------------------------------------ @@ -166,6 +167,8 @@ private: // TextLine //------------------------------------------------------------------------ +class TextBlock; + class TextLine { public: @@ -223,6 +226,8 @@ private: // TextBlock //------------------------------------------------------------------------ +class TextPage; + class TextBlock { public: From 631458353d026a1c56f554574c275abe3717205e Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 21 Mar 2005 20:57:29 +0000 Subject: [PATCH 026/245] Fix compile problem due to the non-standard location of Xft2 header files. svn path=/trunk/kdegraphics/kpdf/; revision=399553 --- configure.in.in | 2 ++ xpdf/xpdf/Makefile.am | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.in.in b/configure.in.in index 924ffc57b..8d510f1df 100644 --- a/configure.in.in +++ b/configure.in.in @@ -39,9 +39,11 @@ AC_SUBST(LIBFREETYPE_RPATH) KDE_FIND_PATH(xft-config, XFT_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],) if test -n "$XFT_CONFIG"; then + XFT_CFLAGS="`$XFT_CONFIG --cflags`" XFT_LIBS="`$XFT_CONFIG --libs`" fi +AC_SUBST(XFT_CFLAGS) AC_SUBST(XFT_LIBS) if test -z "$XFT_LIBS"; then diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am index 1c135bdc3..7209f2d72 100644 --- a/xpdf/xpdf/Makefile.am +++ b/xpdf/xpdf/Makefile.am @@ -1,4 +1,4 @@ -INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../fofi -I$(srcdir)/../splash -I$(srcdir)/../goo $(all_includes) $(LIBFREETYPE_CFLAGS) $(X_INCLUDES) $(QT_INCLUDES) +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../fofi -I$(srcdir)/../splash -I$(srcdir)/../goo $(all_includes) $(LIBFREETYPE_CFLAGS) $(XFT_CFLAGS) $(X_INCLUDES) $(QT_INCLUDES) libxpdf_la_LDFLAGS = $(all_libraries) libxpdf_la_LIBADD = $(LIB_X11) $(LIBFREETYPE_LIBS) $(LIBPAPER_LIBS) $(XFT_LIBS) ../goo/libgoo.la ../fofi/libfofi.la ../splash/libsplash.la From 9d0f01feeffc27b7fb3e723d4520b0c8750e3d3a Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 23 Mar 2005 00:33:28 +0000 Subject: [PATCH 027/245] Optimize lookup of named dests, as example index pages of the pdf 1.6 reference that previously took ~10 seconds to render now render in ~2 seconds Taken from poppler svn path=/trunk/kdegraphics/kpdf/; revision=399871 --- xpdf/xpdf/Array.cc | 15 +++++ xpdf/xpdf/Array.h | 1 + xpdf/xpdf/Catalog.cc | 144 ++++++++++++++++++++++++++++--------------- xpdf/xpdf/Catalog.h | 32 +++++++++- 4 files changed, 140 insertions(+), 52 deletions(-) diff --git a/xpdf/xpdf/Array.cc b/xpdf/xpdf/Array.cc index a6c6db192..fd9a548b1 100644 --- a/xpdf/xpdf/Array.cc +++ b/xpdf/xpdf/Array.cc @@ -71,3 +71,18 @@ Object *Array::getNF(int i, Object *obj) { } return elems[i].copy(obj); } + +GBool Array::getString(int i, GString *string) +{ + Object obj; + + if (getNF(i, &obj)->isString()) { + string->clear(); + string->append(obj.getString()); + obj.free(); + return gTrue; + } else { + obj.free(); + return gFalse; + } +} diff --git a/xpdf/xpdf/Array.h b/xpdf/xpdf/Array.h index 20ae05f29..1ef65dba2 100644 --- a/xpdf/xpdf/Array.h +++ b/xpdf/xpdf/Array.h @@ -45,6 +45,7 @@ public: // Accessors. Object *get(int i, Object *obj); Object *getNF(int i, Object *obj); + GBool getString(int i, GString *string); private: diff --git a/xpdf/xpdf/Catalog.cc b/xpdf/xpdf/Catalog.cc index cb721cf63..ed0306049 100644 --- a/xpdf/xpdf/Catalog.cc +++ b/xpdf/xpdf/Catalog.cc @@ -14,6 +14,7 @@ #include #include +#include #include "gmem.h" #include "Object.h" #include "XRef.h" @@ -91,10 +92,11 @@ Catalog::Catalog(XRef *xrefA) { catDict.dictLookup("Dests", &dests); // read root of named destination tree - if (catDict.dictLookup("Names", &obj)->isDict()) - obj.dictLookup("Dests", &nameTree); - else - nameTree.initNull(); + if (catDict.dictLookup("Names", &obj)->isDict()) { + obj.dictLookup("Dests", &obj2); + destNameTree.init(xref, &obj2); + obj2.free(); + } obj.free(); // read base URI @@ -142,7 +144,6 @@ Catalog::Catalog(XRef *xrefA) { err1: catDict.free(); dests.initNull(); - nameTree.initNull(); ok = gFalse; } @@ -159,7 +160,7 @@ Catalog::~Catalog() { gfree(pageRefs); } dests.free(); - nameTree.free(); + destNameTree.free(); if (baseURI) { delete baseURI; } @@ -290,8 +291,8 @@ LinkDest *Catalog::findDest(GString *name) { else obj1.free(); } - if (!found && nameTree.isDict()) { - if (!findDestInTree(&nameTree, name, &obj1)->isNull()) + if (!found) { + if (destNameTree.lookup(name, &obj1)) found = gTrue; else obj1.free(); @@ -321,62 +322,103 @@ LinkDest *Catalog::findDest(GString *name) { return dest; } -Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) { - Object names, name1; - Object kids, kid, limits, low, high; - GBool done, found; - int cmp, i; +NameTree::NameTree(void) +{ + size = 0; + length = 0; + entries = NULL; +} + +NameTree::Entry::Entry(Array *array, int index) { + if (!array->getString(index, &name) || !array->getNF(index + 1, &value)) + error(-1, "Invalid page tree"); +} + +NameTree::Entry::~Entry() { + value.free(); +} + +void NameTree::addEntry(Entry *entry) +{ + if (length == size) { + if (length == 0) { + size = 8; + } else { + size *= 2; + } + entries = (Entry **) grealloc (entries, sizeof (Entry *) * size); + } + + entries[length] = entry; + ++length; +} + +void NameTree::init(XRef *xrefA, Object *tree) { + xref = xrefA; + parse(tree); +} + +void NameTree::parse(Object *tree) { + Object names; + Object kids, kid; + int i; + + if (!tree->isDict()) + return; // leaf node if (tree->dictLookup("Names", &names)->isArray()) { - done = found = gFalse; - for (i = 0; !done && i < names.arrayGetLength(); i += 2) { - if (names.arrayGet(i, &name1)->isString()) { - cmp = name->cmp(name1.getString()); - if (cmp == 0) { - names.arrayGet(i+1, obj); - found = gTrue; - done = gTrue; - } else if (cmp < 0) { - done = gTrue; - } - } - name1.free(); + for (i = 0; i < names.arrayGetLength(); i += 2) { + NameTree::Entry *entry; + + entry = new Entry(names.getArray(), i); + addEntry(entry); } - names.free(); - if (!found) - obj->initNull(); - return obj; } - names.free(); // root or intermediate node - done = gFalse; if (tree->dictLookup("Kids", &kids)->isArray()) { - for (i = 0; !done && i < kids.arrayGetLength(); ++i) { - if (kids.arrayGet(i, &kid)->isDict()) { - if (kid.dictLookup("Limits", &limits)->isArray()) { - if (limits.arrayGet(0, &low)->isString() && - name->cmp(low.getString()) >= 0) { - if (limits.arrayGet(1, &high)->isString() && - name->cmp(high.getString()) <= 0) { - findDestInTree(&kid, name, obj); - done = gTrue; - } - high.free(); - } - low.free(); - } - limits.free(); - } + for (i = 0; i < kids.arrayGetLength(); ++i) { + if (kids.arrayGet(i, &kid)->isDict()) + parse(&kid); kid.free(); } } kids.free(); +} + +int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry) +{ + GString *key = (GString *) voidKey; + Entry *entry = *(NameTree::Entry **) voidEntry; + + return key->cmp(&entry->name); +} + +GBool NameTree::lookup(GString *name, Object *obj) +{ + Entry *entry; + + entry = *(Entry **) bsearch(name, entries, + length, sizeof(Entry *), Entry::cmp); + if (entry != NULL) { + entry->value.fetch(xref, obj); + return gTrue; + } else { + printf("failed to look up %s\n", name->getCString()); - // name was outside of ranges of all kids - if (!done) obj->initNull(); - return obj; + return gFalse; + } +} + +void NameTree::free() +{ + int i; + + for (i = 0; i < length; i++) + delete entries[i]; + + gfree(entries); } diff --git a/xpdf/xpdf/Catalog.h b/xpdf/xpdf/Catalog.h index d7c324795..d8db44802 100644 --- a/xpdf/xpdf/Catalog.h +++ b/xpdf/xpdf/Catalog.h @@ -22,6 +22,36 @@ class PageAttrs; struct Ref; class LinkDest; +//------------------------------------------------------------------------ +// NameTree +//------------------------------------------------------------------------ + +class NameTree { +public: + NameTree(); + void init(XRef *xref, Object *tree); + void parse(Object *tree); + GBool lookup(GString *name, Object *obj); + void free(); + +private: + struct Entry { + Entry(Array *array, int index); + ~Entry(); + GString name; + Object value; + void free(); + static int cmp(const void *key, const void *entry); + }; + + void addEntry(Entry *entry); + + XRef *xref; + Object *root; + Entry **entries; + int size, length; +}; + //------------------------------------------------------------------------ // Catalog //------------------------------------------------------------------------ @@ -86,7 +116,7 @@ private: int numPages; // number of pages int pagesSize; // size of pages array Object dests; // named destination dictionary - Object nameTree; // name tree + NameTree destNameTree; // name tree GString *baseURI; // base URI for URI-type links PageMode pageMode; // page mode Object metadata; // metadata stream From 87687f7e5014b834d1dc16c7eba9c6be1120682d Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 23 Mar 2005 20:08:15 +0000 Subject: [PATCH 028/245] Update d->zoomFactor when resizing the view and we are on fitpage or fitwidth so that when we click Zoom+ or Zoom- the zoom updates acordingly svn path=/trunk/kdegraphics/kpdf/; revision=400073 --- ui/pageview.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index e300c795a..5b57b2b08 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -1270,6 +1270,7 @@ void PageView::updateItemSize( PageViewItem * item, int colWidth, int rowHeight { height = kpdfPage->ratio() * colWidth; item->setWHZ( colWidth, (int)height, (double)colWidth / width ); + d->zoomFactor = (double)colWidth / width; } else if ( d->zoomMode == ZoomFitPage ) { @@ -1277,6 +1278,7 @@ void PageView::updateItemSize( PageViewItem * item, int colWidth, int rowHeight double scaleH = (double)rowHeight / (double)height; zoom = QMIN( scaleW, scaleH ); item->setWHZ( (int)(zoom * width), (int)(zoom * height), zoom ); + d->zoomFactor = zoom; } #ifndef NDEBUG else From e8681f8c323a2233eafce92d3b2811a03f856cf3 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 24 Mar 2005 19:26:41 +0000 Subject: [PATCH 029/245] Compile on Solaris BUGS: 102337 svn path=/trunk/kdegraphics/kpdf/; revision=400299 --- xpdf/xpdf/GlobalParams.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index 5b120ddda..5b8828a6d 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -23,6 +23,7 @@ #include #include FT_FREETYPE_H // -- ---------------------------------------------------------- -- +#include #include #include #include From aa5ef294be4dd1e2e1450d9f593752b3b8c79f34 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 24 Mar 2005 20:10:08 +0000 Subject: [PATCH 030/245] When saving a file ask if we are going to overwrite a existing file BUG: 102332 svn path=/trunk/kdegraphics/kpdf/; revision=400315 --- part.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/part.cpp b/part.cpp index 6a21c25c9..846a1f818 100644 --- a/part.cpp +++ b/part.cpp @@ -556,6 +556,12 @@ void Part::slotSaveFileAs() KURL saveURL = KFileDialog::getSaveURL( url().isLocalFile() ? url().url() : url().fileName(), QString::null, widget() ); if ( saveURL.isValid() && !saveURL.isEmpty() ) { + if ( KIO::NetAccess::exists( saveURL, false, widget() ) ) + { + if (KMessageBox::questionYesNo( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.filename())) != KMessageBox::Yes) + return; + } + if ( !KIO::NetAccess::file_copy( url(), saveURL, -1, true ) ) KMessageBox::information( 0, i18n("File could not be saved in '%1'. Try to save it to another location.").arg( saveURL.prettyURL() ) ); } From 9f55f72131483f452f30c8f828594ce4ab712164 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 24 Mar 2005 22:53:56 +0000 Subject: [PATCH 031/245] Adapt fix for 102117 to HEAD version of the properties dialog svn path=/trunk/kdegraphics/kpdf/; revision=400353 --- ui/propertiesdialog.cpp | 48 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/ui/propertiesdialog.cpp b/ui/propertiesdialog.cpp index 993b0682e..d5810a07b 100644 --- a/ui/propertiesdialog.cpp +++ b/ui/propertiesdialog.cpp @@ -8,10 +8,12 @@ ***************************************************************************/ // qt/kde includes -#include -#include #include #include +#include +#include +#include +#include // local includes #include "propertiesdialog.h" @@ -38,18 +40,24 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) QDomElement docElement = info->documentElement(); int row = 0; + int valMaxWidth = 100; for ( QDomNode node = docElement.firstChild(); !node.isNull(); node = node.nextSibling() ) { QDomElement element = node.toElement(); - if ( !element.attribute( "title" ).isEmpty() ) { - QLabel *key = new QLabel( i18n( "%1:" ).arg( element.attribute( "title" ) ), page ); - QLabel *value = new QLabel( element.attribute( "value" ), page ); + QString titleString = element.attribute( "title" ); + QString valueString = element.attribute( "value" ); + if ( titleString.isEmpty() || valueString.isEmpty() ) + continue; - layout->addWidget( key, row, 0, AlignRight ); - layout->addWidget( value, row, 1 ); + // create labels and layout them + QLabel *key = new QLabel( i18n( "%1:" ).arg( titleString ), page ); + QLabel *value = new KSqueezedTextLabel( valueString, page ); + layout->addWidget( key, row, 0, AlignRight ); + layout->addWidget( value, row, 1 ); + row++; - row++; - } + // refine maximum width of 'value' labels + valMaxWidth = QMAX( valMaxWidth, fontMetrics().width( valueString ) ); } // add the number of pages if the generator hasn't done it already @@ -62,13 +70,25 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) layout->addWidget( value, row, 1 ); } + // Fonts + QVBoxLayout *page2Layout = 0; if (doc->hasFonts()) { - // Properties - page = addPage(i18n("Fonts")); - QVBoxLayout *topLayout = new QVBoxLayout(page, 0, KDialog::spacingHint()); - KListView *lv = new KListView(page); - topLayout->add(lv); + QFrame *page2 = addPage(i18n("Fonts")); + page2Layout = new QVBoxLayout(page2, 0, KDialog::spacingHint()); + KListView *lv = new KListView(page2); + page2Layout->add(lv); doc->putFontInfo(lv); } + + // current width: left column + right column + dialog borders + int width = layout->minimumSize().width() + valMaxWidth + marginHint() + spacingHint() + marginHint() + 30; + if (page2Layout) + { + width = QMAX( width, page2Layout->sizeHint().width() + marginHint() + spacingHint() + 31 ); + } + // stay inside the 2/3 of the screen width + QRect screenContainer = KGlobalSettings::desktopGeometry( this ); + width = QMIN( width, 2*screenContainer.width()/3 ); + resize(width, 1); } From 6502d700043e6cd109a7ea23c33a14cfa6f3a29d Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 25 Mar 2005 12:57:51 +0000 Subject: [PATCH 032/245] Unneeded svn path=/trunk/kdegraphics/kpdf/; revision=400494 --- shell/shell.cpp | 1 - shell/shell.h | 1 - 2 files changed, 2 deletions(-) diff --git a/shell/shell.cpp b/shell/shell.cpp index a18c2e137..6a32a5442 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/shell/shell.h b/shell/shell.h index e7c815089..391db6726 100644 --- a/shell/shell.h +++ b/shell/shell.h @@ -21,7 +21,6 @@ #endif #include -class KPopupMenu; namespace KPDF { From 35b710deac928e9b9052dfa0b6d2a2d4109c5730 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 25 Mar 2005 16:20:29 +0000 Subject: [PATCH 033/245] Remove warning about not able to compare a uint with < 0 svn path=/trunk/kdegraphics/kpdf/; revision=400552 --- conf/kpdf.kcfg | 1 - 1 file changed, 1 deletion(-) diff --git a/conf/kpdf.kcfg b/conf/kpdf.kcfg index 757cf8de4..d980fd95f 100644 --- a/conf/kpdf.kcfg +++ b/conf/kpdf.kcfg @@ -80,7 +80,6 @@ 0 - 0 2 From 246509e16ceaca8a13a6a443a769bd71afbde418 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 25 Mar 2005 16:35:43 +0000 Subject: [PATCH 034/245] Not used anymore, don't give a warning svn path=/trunk/kdegraphics/kpdf/; revision=400559 --- xpdf/splash/SplashFTFontEngine.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xpdf/splash/SplashFTFontEngine.cc b/xpdf/splash/SplashFTFontEngine.cc index d6c078f04..b47ba24e2 100644 --- a/xpdf/splash/SplashFTFontEngine.cc +++ b/xpdf/splash/SplashFTFontEngine.cc @@ -31,9 +31,11 @@ extern "C" int unlink(char *filename); //------------------------------------------------------------------------ +#if 0 static void FT_fileWrite(void *stream, const char *data, int len) { fwrite(data, 1, len, (FILE *)stream); } +#endif //------------------------------------------------------------------------ // SplashFTFontEngine From 08d23c5231eba590613f642c63f80897bd23d0af Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 25 Mar 2005 22:02:05 +0000 Subject: [PATCH 035/245] Proof of concept PNG generator, to use if do kpdf foo.png as open only shows pdf, it crashes when doing Search as you type and Presentation does not works but it only has 10 lines of code and it was done to show how "easy" is adding new generators svn path=/trunk/kdegraphics/kpdf/; revision=400632 --- core/Makefile.am | 4 +- core/document.cpp | 10 +++++ core/document.h | 1 + core/generator.h | 5 ++- core/generator_pdf/generator_pdf.cpp | 5 +++ core/generator_pdf/generator_pdf.h | 5 ++- core/generator_png/Makefile.am | 6 +++ core/generator_png/generator_png.cpp | 62 ++++++++++++++++++++++++++++ core/generator_png/generator_png.h | 40 ++++++++++++++++++ part.cpp | 4 +- 10 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 core/generator_png/Makefile.am create mode 100644 core/generator_png/generator_png.cpp create mode 100644 core/generator_png/generator_png.h diff --git a/core/Makefile.am b/core/Makefile.am index 6f1360f2f..c39037c24 100644 --- a/core/Makefile.am +++ b/core/Makefile.am @@ -1,10 +1,10 @@ -SUBDIRS = generator_pdf +SUBDIRS = generator_pdf generator_png INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(srcdir)/../xpdf -I$(srcdir)/../xpdf/goo -I$(top_builddir)/kpdf $(all_includes) METASOURCES = AUTO -libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la +libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la ./generator_png/libgeneratorpng.la libkpdfcore_la_SOURCES = document.cpp link.cpp page.cpp pagetransition.cpp noinst_LTLIBRARIES = libkpdfcore.la diff --git a/core/document.cpp b/core/document.cpp index 09199ab1f..6e9f4beb9 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -32,6 +32,7 @@ #include "page.h" #include "link.h" #include "generator_pdf/generator_pdf.h" // PDF generator +#include "generator_png/generator_png.h" // PDF generator #include "conf/settings.h" // structures used internally by KPDFDocument for local variables storage @@ -142,6 +143,10 @@ bool KPDFDocument::openDocument( const QString & docFile, const KURL & url ) generator = new PDFGenerator( this ); // else if ( mimeName == "application/postscript" ) // kdError() << "PS generator not available" << endl; + else if ( mimeName == "image/png" ) + { + generator = new PNGGenerator( this ); + } else { kdWarning() << "Unknown mimetype '" << mimeName << "'." << endl; @@ -381,6 +386,11 @@ QString KPDFDocument::getMetaData( const QString & key, const QString & option ) return generator ? generator->getMetaData( key, option ) : QString(); } +bool KPDFDocument::supportsSearching() const +{ + return generator ? generator->supportsSearching() : false; +} + bool KPDFDocument::hasFonts() const { return generator ? generator->hasFonts() : false; diff --git a/core/document.h b/core/document.h index 725a5bc39..16f52240a 100644 --- a/core/document.h +++ b/core/document.h @@ -76,6 +76,7 @@ class KPDFDocument : public QObject bool historyAtBegin() const; bool historyAtEnd() const; QString getMetaData( const QString & key, const QString & option = QString() ) const; + bool supportsSearching() const; bool hasFonts() const; void putFontInfo(KListView *list); diff --git a/core/generator.h b/core/generator.h index 4a53a0a2b..39d272d96 100644 --- a/core/generator.h +++ b/core/generator.h @@ -59,8 +59,11 @@ class Generator : public QObject virtual void generatePixmap( PixmapRequest * request ) = 0; virtual void generateSyncTextPage( KPDFPage * page ) = 0; - // font related + // capability querying + virtual bool supportsSearching() const = 0; virtual bool hasFonts() const = 0; + + // font related virtual void putFontInfo(KListView *list) = 0; // print document using already configured kprinter diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 65f882ae9..1497d71a6 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -342,6 +342,11 @@ void PDFGenerator::generateSyncTextPage( KPDFPage * page ) docLock.unlock(); } +bool PDFGenerator::supportsSearching() const +{ + return true; +} + bool PDFGenerator::hasFonts() const { return true; diff --git a/core/generator_pdf/generator_pdf.h b/core/generator_pdf/generator_pdf.h index 0a3a4e416..9459231c8 100644 --- a/core/generator_pdf/generator_pdf.h +++ b/core/generator_pdf/generator_pdf.h @@ -65,8 +65,11 @@ class PDFGenerator : public Generator void generatePixmap( PixmapRequest * request ); void generateSyncTextPage( KPDFPage * page ); - // font related + // [INHERITED] capability querying + bool supportsSearching() const; bool hasFonts() const; + + // [INHERITED] font related void putFontInfo(KListView *list); // [INHERITED] print page using an already configured kprinter diff --git a/core/generator_png/Makefile.am b/core/generator_png/Makefile.am new file mode 100644 index 000000000..2c23f4bed --- /dev/null +++ b/core/generator_png/Makefile.am @@ -0,0 +1,6 @@ +INCLUDES = -I$(srcdir)/../../ $(all_includes) + +libgeneratorpng_la_LDFLAGS = $(all_libraries) +libgeneratorpng_la_SOURCES = generator_png.cpp + +noinst_LTLIBRARIES = libgeneratorpng.la diff --git a/core/generator_png/generator_png.cpp b/core/generator_png/generator_png.cpp new file mode 100644 index 000000000..0fdbf6da3 --- /dev/null +++ b/core/generator_png/generator_png.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2005 by Albert Astals Cid * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include + +#include "core/page.h" +#include "generator_png.h" + +PNGGenerator::PNGGenerator( KPDFDocument * document ) : Generator( document ) +{ +} + +PNGGenerator::~PNGGenerator() +{ +} + +bool PNGGenerator::loadDocument( const QString & fileName, QValueVector & pagesVector ) +{ + m_pix = new QPixmap(fileName); + + pagesVector.resize( 1 ); + + KPDFPage * page = new KPDFPage( 0, m_pix->width(), m_pix->height(), 0 ); + pagesVector[0] = page; + + return true; +} + +bool PNGGenerator::canGeneratePixmap() +{ + return true; +} + +void PNGGenerator::generatePixmap( PixmapRequest * request ) +{ + QPixmap *p = new QPixmap(*m_pix); + request->page->setPixmap(request->id, p); +} + +void PNGGenerator::generateSyncTextPage( KPDFPage * ) +{ +} + +bool PNGGenerator::supportsSearching() const +{ + return false; +} + +bool PNGGenerator::hasFonts() const +{ + return false; +} + +void PNGGenerator::putFontInfo( KListView * ) +{ +} diff --git a/core/generator_png/generator_png.h b/core/generator_png/generator_png.h new file mode 100644 index 000000000..b732ac838 --- /dev/null +++ b/core/generator_png/generator_png.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2005 by Albert Astals Cid * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef _KPDF_GENERATOR_PNG_H_ +#define _KPDF_GENERATOR_PNG_H_ + +#include "core/generator.h" + +class PNGGenerator : public Generator +{ + public: + PNGGenerator( KPDFDocument * document ); + virtual ~PNGGenerator(); + + // [INHERITED] load a document and fill up the pagesVector + bool loadDocument( const QString & fileName, QValueVector & pagesVector ); + + // [INHERITED] perform actions on document / pages + bool canGeneratePixmap(); + void generatePixmap( PixmapRequest * request ); + void generateSyncTextPage( KPDFPage * page ); + + // [INHERITED] capability querying + bool supportsSearching() const; + bool hasFonts() const; + + // font related + void putFontInfo(KListView *list); + + private: + QPixmap *m_pix; +}; + +#endif diff --git a/part.cpp b/part.cpp index 846a1f818..8214ef051 100644 --- a/part.cpp +++ b/part.cpp @@ -320,8 +320,8 @@ bool Part::openFile() bool ok = m_document->openDocument( m_file, url() ); // update one-time actions - m_find->setEnabled( ok ); - m_findNext->setEnabled( ok ); + m_find->setEnabled( ok && m_document-> supportsSearching()); + m_findNext->setEnabled( ok && m_document-> supportsSearching()); m_saveAs->setEnabled( ok ); m_printPreview->setEnabled( ok ); m_showProperties->setEnabled( ok ); From 60a53c21ea51783103d6d98a8269b6583f5409e5 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 25 Mar 2005 22:07:17 +0000 Subject: [PATCH 036/245] Only start search has you type if the document supports it svn path=/trunk/kdegraphics/kpdf/; revision=400639 --- ui/pageview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 5b57b2b08..e9f4db604 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -613,7 +613,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) } return; } - else if( e->key() == '/' && d->document->isOpened() ) + else if( e->key() == '/' && d->document->isOpened() && d->document->supportsSearching() ) { // stop scrolling the page (if doing it) if ( d->autoScrollTimer ) From 7b0fb391172ab2e59075a1d1d64b5b8eba35f9b1 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 27 Mar 2005 19:15:26 +0000 Subject: [PATCH 037/245] Obey page up and page down keys in presentation mode For the 'b' key thing open another wish report; remember 1 issue per bug report. BUGS: 102565 svn path=/trunk/kdegraphics/kpdf/; revision=401062 --- ui/presentationwidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index bbf4a3c09..a9aca25c3 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -172,9 +172,9 @@ void PresentationWidget::keyPressEvent( QKeyEvent * e ) { if (m_width == -1) return; - if ( e->key() == Key_Left || e->key() == Key_Backspace ) + if ( e->key() == Key_Left || e->key() == Key_Backspace || e->key() == Key_Prior ) slotPrevPage(); - else if ( e->key() == Key_Right || e->key() == Key_Space ) + else if ( e->key() == Key_Right || e->key() == Key_Space || e->key() == Key_Next ) slotNextPage(); else if ( e->key() == Key_Escape ) { From d1dd22b280825ed4c58cbb4cbcff8a1f1a1a9057 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 27 Mar 2005 20:55:30 +0000 Subject: [PATCH 038/245] Implement bare-bones printing for the png generator, leak-- svn path=/trunk/kdegraphics/kpdf/; revision=401093 --- core/generator_png/generator_png.cpp | 9 +++++++++ core/generator_png/generator_png.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/core/generator_png/generator_png.cpp b/core/generator_png/generator_png.cpp index 0fdbf6da3..391697928 100644 --- a/core/generator_png/generator_png.cpp +++ b/core/generator_png/generator_png.cpp @@ -7,7 +7,9 @@ * (at your option) any later version. * ***************************************************************************/ +#include #include +#include #include "core/page.h" #include "generator_png.h" @@ -18,6 +20,7 @@ PNGGenerator::PNGGenerator( KPDFDocument * document ) : Generator( document ) PNGGenerator::~PNGGenerator() { + delete m_pix; } bool PNGGenerator::loadDocument( const QString & fileName, QValueVector & pagesVector ) @@ -60,3 +63,9 @@ bool PNGGenerator::hasFonts() const void PNGGenerator::putFontInfo( KListView * ) { } + +bool PNGGenerator::print( KPrinter& printer ) +{ + QPainter p(&printer); + p.drawPixmap(0, 0, *m_pix); +} diff --git a/core/generator_png/generator_png.h b/core/generator_png/generator_png.h index b732ac838..7a85db3c8 100644 --- a/core/generator_png/generator_png.h +++ b/core/generator_png/generator_png.h @@ -33,6 +33,9 @@ class PNGGenerator : public Generator // font related void putFontInfo(KListView *list); + // [INHERITED] print document using already configured kprinter + bool print( KPrinter& printer ); + private: QPixmap *m_pix; }; From 19e41ac483317c11f67036a27ba4f4913d0567de Mon Sep 17 00:00:00 2001 From: Tobias Koenig Date: Mon, 11 Apr 2005 17:38:40 +0000 Subject: [PATCH 039/245] Add 'Home' and 'End' key support to jump to the beginning/end of the presentation. Don't create the presentation view on every external change. svn path=/trunk/kdegraphics/kpdf/; revision=404850 --- part.cpp | 6 ++---- ui/presentationwidget.cpp | 14 ++++++++++++++ ui/presentationwidget.h | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/part.cpp b/part.cpp index 8214ef051..adc4dbe23 100644 --- a/part.cpp +++ b/part.cpp @@ -741,10 +741,8 @@ void Part::slotShowProperties() void Part::slotShowPresentation() { - if ( m_presentationWidget ) - delete (PresentationWidget*) m_presentationWidget; - - m_presentationWidget = new PresentationWidget( m_document ); + if ( !m_presentationWidget ) + m_presentationWidget = new PresentationWidget( m_document ); } void Part::slotPrint() diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index a9aca25c3..04e86e0fe 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -176,6 +176,10 @@ void PresentationWidget::keyPressEvent( QKeyEvent * e ) slotPrevPage(); else if ( e->key() == Key_Right || e->key() == Key_Space || e->key() == Key_Next ) slotNextPage(); + else if ( e->key() == Key_Home ) + slotFirstPage(); + else if ( e->key() == Key_End ) + slotLastPage(); else if ( e->key() == Key_Escape ) { if ( m_topBar->isShown() ) @@ -584,6 +588,16 @@ void PresentationWidget::slotPrevPage() } } +void PresentationWidget::slotFirstPage() +{ + changePage( 0 ); +} + +void PresentationWidget::slotLastPage() +{ + changePage( (int)m_frames.count() - 1 ); +} + void PresentationWidget::slotHideOverlay() { QRect geom( m_overlayGeometry ); diff --git a/ui/presentationwidget.h b/ui/presentationwidget.h index 3bfc8be84..48c87b355 100644 --- a/ui/presentationwidget.h +++ b/ui/presentationwidget.h @@ -86,6 +86,8 @@ class PresentationWidget : public QWidget, public DocumentObserver private slots: void slotNextPage(); void slotPrevPage(); + void slotFirstPage(); + void slotLastPage(); void slotHideOverlay(); void slotTransitionStep(); }; From b3ea24bb0d906cf8b26953e22df2c918fbe63346 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 12 Apr 2005 23:20:41 +0000 Subject: [PATCH 040/245] Presentation is now a dialog child of part so that get get only 1 entry on taskbar To fix presentationwidget wanting to be always on top, even when it does not has the focus, we drop the staysontop on windowdeactivation and get it again on actiovation BUGS: 103718 svn path=/trunk/kdegraphics/kpdf/; revision=405195 --- part.cpp | 2 +- ui/presentationwidget.cpp | 13 ++++++++++--- ui/presentationwidget.h | 7 ++++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/part.cpp b/part.cpp index adc4dbe23..d95fe0ada 100644 --- a/part.cpp +++ b/part.cpp @@ -742,7 +742,7 @@ void Part::slotShowProperties() void Part::slotShowPresentation() { if ( !m_presentationWidget ) - m_presentationWidget = new PresentationWidget( m_document ); + m_presentationWidget = new PresentationWidget( widget(), m_document ); } void Part::slotPrint() diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index 04e86e0fe..2d29515e2 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -20,6 +20,7 @@ #include #include #include +#include // system includes #include @@ -46,9 +47,8 @@ struct PresentationFrame }; -PresentationWidget::PresentationWidget( KPDFDocument * doc ) - : QWidget( 0, "presentationWidget", WDestructiveClose | WStyle_NoBorder | - WStyle_StaysOnTop | WShowModal ), m_document( doc ), m_frameIndex( -1 ) +PresentationWidget::PresentationWidget( QWidget * parent, KPDFDocument * doc ) + : QDialog( parent, "presentationWidget", true, WDestructiveClose | WStyle_NoBorder), m_document( doc ), m_frameIndex( -1 ) { // set look and geometry setBackgroundMode( Qt::NoBackground ); @@ -168,6 +168,13 @@ bool PresentationWidget::canUnloadPixmap( int pageNumber ) // +bool PresentationWidget::event ( QEvent * e ) +{ + if (e -> type() == QEvent::WindowDeactivate) KWin::clearState(winId(), NET::StaysOnTop); + else if (e -> type() == QEvent::WindowActivate) KWin::setState(winId(), NET::StaysOnTop); + return QDialog::event(e); +} + void PresentationWidget::keyPressEvent( QKeyEvent * e ) { if (m_width == -1) return; diff --git a/ui/presentationwidget.h b/ui/presentationwidget.h index 48c87b355..fd59855fa 100644 --- a/ui/presentationwidget.h +++ b/ui/presentationwidget.h @@ -10,7 +10,7 @@ #ifndef _KPDF_PRESENTATIONWIDGET_H_ #define _KPDF_PRESENTATIONWIDGET_H_ -#include +#include #include #include #include @@ -29,11 +29,11 @@ class PresentationFrame; * * This is a fullscreen widget that displays */ -class PresentationWidget : public QWidget, public DocumentObserver +class PresentationWidget : public QDialog, public DocumentObserver { Q_OBJECT public: - PresentationWidget( KPDFDocument * doc ); + PresentationWidget( QWidget * parent, KPDFDocument * doc ); ~PresentationWidget(); // inherited from DocumentObserver @@ -45,6 +45,7 @@ class PresentationWidget : public QWidget, public DocumentObserver protected: // widget events + bool event( QEvent * e ); void keyPressEvent( QKeyEvent * e ); void wheelEvent( QWheelEvent * e ); void mousePressEvent( QMouseEvent * e ); From debbaff9381e1b6d0f184cf2b37882726331f178 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 13 Apr 2005 19:16:52 +0000 Subject: [PATCH 041/245] messageboxes explaining how to get of the presentation mode and why the document is going to be launched on presentation mode, of couse they have the typical "don't show again". Checking of the wording from a good english speaker would be cool svn path=/trunk/kdegraphics/kpdf/; revision=405407 --- part.cpp | 3 +++ ui/presentationwidget.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/part.cpp b/part.cpp index d95fe0ada..f9bbe00c8 100644 --- a/part.cpp +++ b/part.cpp @@ -344,7 +344,10 @@ bool Part::openFile() // if the 'StartFullScreen' flag is set, start presentation if ( m_document->getMetaData( "StartFullScreen" ) == "yes" ) + { + KMessageBox::information(m_presentationWidget, i18n("The document is going to be launched on presentation mode because the file requested it."), QString::null, "autoPresentationWarning"); slotShowPresentation(); + } return true; } diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index 2d29515e2..50097f976 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include // system includes @@ -279,6 +280,8 @@ void PresentationWidget::paintEvent( QPaintEvent * pe ) // show summary if requested if ( Settings::slidesShowSummary() ) generatePage(); + + KMessageBox::information(this, i18n("There are two ways of exiting presentation mode, you can press either ESC key or click with the quit button that appears when placing the mouse in the top-right corner. Of course you can cycle windows (Alt+TAB by default)"), QString::null, "presentationInfo"); } // check painting rect consistancy From 57da7dbcd4c1d086a1d0e07cd724275feecd43e8 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 14 Apr 2005 18:50:07 +0000 Subject: [PATCH 042/245] Use libjpeg for dct streams, libjpeg has probably had more attention that xpdf code and also it makes a pdf work that previously was not working so this is a god change TM, just wondering if i should backport or not. BUGS: 87766 svn path=/trunk/kdegraphics/kpdf/; revision=405580 --- configure.in.in | 16 ++++++ xpdf/xpdf/DCTStream.cc | 110 +++++++++++++++++++++++++++++++++++++++++ xpdf/xpdf/DCTStream.h | 71 ++++++++++++++++++++++++++ xpdf/xpdf/Makefile.am | 4 +- xpdf/xpdf/Stream.cc | 4 +- xpdf/xpdf/Stream.h | 4 ++ 6 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 xpdf/xpdf/DCTStream.cc create mode 100644 xpdf/xpdf/DCTStream.h diff --git a/configure.in.in b/configure.in.in index 8d510f1df..660b5f4a2 100644 --- a/configure.in.in +++ b/configure.in.in @@ -27,7 +27,10 @@ if test -n "$FREETYPE_CONFIG"; then else AC_MSG_WARN([You need at least libfreetype 2.0.5]) + DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" fi +else + DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" fi AC_SUBST(LIBFREETYPE_LIBS) @@ -50,6 +53,19 @@ if test -z "$XFT_LIBS"; then DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" fi +dnl ##### Check for libjpeg +AC_CHECK_LIB([jpeg], [jpeg_destroy_decompress],HAVE_LIBJPEG=yes,HAVE_LIBJPEG=no) +if test HAVE_LIBJPEG = yes; then + AC_CHECK_HEADERS([jpeglib.h],,HAVE_LIBJPEG=no) +fi + +if test HAVE_LIBJPEG = yes; then + LIBJPEG_LIBS="-ljpeg" + AC_SUBST(LIBJPEG_LIBS) +else + DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" +fi + dnl ##### Check for libpaper (Debian). LIBPAPER_LIBS= diff --git a/xpdf/xpdf/DCTStream.cc b/xpdf/xpdf/DCTStream.cc new file mode 100644 index 000000000..936ff63bd --- /dev/null +++ b/xpdf/xpdf/DCTStream.cc @@ -0,0 +1,110 @@ +//======================================================================== +// +// DCTStream.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include "DCTStream.h" + +static void str_init_source(j_decompress_ptr /*cinfo*/) +{ +} + +static boolean str_fill_input_buffer(j_decompress_ptr cinfo) +{ + struct str_src_mgr * src = (struct str_src_mgr *)cinfo->src; + src->buffer = src->str->getChar(); + src->pub.next_input_byte = &src->buffer; + src->pub.bytes_in_buffer = 1; + return TRUE; +} + +static void str_skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + struct str_src_mgr * src = (struct str_src_mgr *)cinfo->src; + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + str_fill_input_buffer(cinfo); + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +static void str_term_source(j_decompress_ptr /*cinfo*/) +{ +} + +DCTStream::DCTStream(Stream *strA): + FilterStream(strA) { + + jpeg_create_decompress(&cinfo); + src.pub.init_source = str_init_source; + src.pub.fill_input_buffer = str_fill_input_buffer; + src.pub.skip_input_data = str_skip_input_data; + src.pub.resync_to_restart = jpeg_resync_to_restart; + src.pub.term_source = str_term_source; + src.pub.bytes_in_buffer = 0; + src.pub.next_input_byte = NULL; + src.str = str; + cinfo.src = (jpeg_source_mgr *)&src; + cinfo.err = jpeg_std_error(&jerr); + x = 0; +} + +DCTStream::~DCTStream() { + jpeg_destroy_decompress(&cinfo); + delete str; +} + +void DCTStream::reset() { + int row_stride; + + str->reset(); + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + row_stride = cinfo.output_width * cinfo.output_components; + row_buffer = cinfo.mem->alloc_sarray((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); +} + +int DCTStream::getChar() { + int c; + + if (x == 0) { + if (cinfo.output_scanline < cinfo.output_height) + jpeg_read_scanlines(&cinfo, row_buffer, 1); + else return EOF; + } + c = row_buffer[0][x]; + x++; + if (x == cinfo.output_width * cinfo.output_components) + x = 0; + return c; +} + +int DCTStream::lookChar() { + int c; + c = row_buffer[0][x]; + return c; +} + +GString *DCTStream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("<< >> /DCTDecode filter\n"); + return s; +} + +GBool DCTStream::isBinary(GBool /*last*/) { + return str->isBinary(gTrue); +} diff --git a/xpdf/xpdf/DCTStream.h b/xpdf/xpdf/DCTStream.h new file mode 100644 index 000000000..ed7537b35 --- /dev/null +++ b/xpdf/xpdf/DCTStream.h @@ -0,0 +1,71 @@ +//======================================================================== +// +// DCTStream.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef DCTSTREAM_H +#define DCTSTREAM_H +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#ifndef WIN32 +#include +#endif +#include +#include +#include "goo/gmem.h" +#include "goo/gfile.h" +#include "Error.h" +#include "Object.h" +#ifndef NO_DECRYPTION +#include "Decrypt.h" +#endif +#include "Stream.h" + +extern "C" { +#include +} + +struct str_src_mgr { + struct jpeg_source_mgr pub; + JOCTET buffer; + Stream *str; +}; + + +class DCTStream: public FilterStream { +public: + + DCTStream(Stream *strA); + virtual ~DCTStream(); + virtual StreamKind getKind() { return strDCT; } + virtual void reset(); + virtual int getChar(); + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + Stream *getRawStream() { return str; } + +private: + unsigned int x; + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + struct str_src_mgr src; + JSAMPARRAY row_buffer; +}; + +#endif diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am index 7209f2d72..936711014 100644 --- a/xpdf/xpdf/Makefile.am +++ b/xpdf/xpdf/Makefile.am @@ -1,9 +1,9 @@ INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../fofi -I$(srcdir)/../splash -I$(srcdir)/../goo $(all_includes) $(LIBFREETYPE_CFLAGS) $(XFT_CFLAGS) $(X_INCLUDES) $(QT_INCLUDES) libxpdf_la_LDFLAGS = $(all_libraries) -libxpdf_la_LIBADD = $(LIB_X11) $(LIBFREETYPE_LIBS) $(LIBPAPER_LIBS) $(XFT_LIBS) ../goo/libgoo.la ../fofi/libfofi.la ../splash/libsplash.la +libxpdf_la_LIBADD = $(LIB_X11) $(LIBFREETYPE_LIBS) $(LIBPAPER_LIBS) $(XFT_LIBS) $(LIBJPEG_LIBS) ../goo/libgoo.la ../fofi/libfofi.la ../splash/libsplash.la libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ - Catalog.cc CharCodeToUnicode.cc CMap.cc Decrypt.cc Dict.cc \ + Catalog.cc CharCodeToUnicode.cc CMap.cc Decrypt.cc Dict.cc DCTStream.cc \ FontEncodingTables.cc Function.cc Gfx.cc \ GfxFont.cc GfxState.cc GlobalParams.cc JArithmeticDecoder.cc \ JBIG2Stream.cc Lexer.cc Link.cc NameToCharCode.cc Object.cc Outline.cc \ diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc index 14fd9af2c..249e4282e 100644 --- a/xpdf/xpdf/Stream.cc +++ b/xpdf/xpdf/Stream.cc @@ -32,6 +32,7 @@ #include "JBIG2Stream.h" #include "JPXStream.h" #include "Stream-CCITT.h" +#include "DCTStream.h" #ifdef __DJGPP__ static GBool setDJSYSFLAGS = gFalse; @@ -1786,6 +1787,7 @@ GBool CCITTFaxStream::isBinary(GBool /*last*/) { return str->isBinary(gTrue); } +#if 0 //------------------------------------------------------------------------ // DCTStream //------------------------------------------------------------------------ @@ -3176,7 +3178,7 @@ GString *DCTStream::getPSFilter(int psLevel, const char *indent) { GBool DCTStream::isBinary(GBool /*last*/) { return str->isBinary(gTrue); } - +#endif //------------------------------------------------------------------------ // FlateStream //------------------------------------------------------------------------ diff --git a/xpdf/xpdf/Stream.h b/xpdf/xpdf/Stream.h index 04715ee04..bc1e077c8 100644 --- a/xpdf/xpdf/Stream.h +++ b/xpdf/xpdf/Stream.h @@ -534,6 +534,9 @@ private: void eatBits(int n) { inputBits -= n; } }; + +#if 0 + //------------------------------------------------------------------------ // DCTStream //------------------------------------------------------------------------ @@ -634,6 +637,7 @@ private: int readMarker(); int read16(); }; +#endif //------------------------------------------------------------------------ // FlateStream From d552cbf559344df1218965d9ef9609aa819056e1 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 14 Apr 2005 19:04:44 +0000 Subject: [PATCH 043/245] Add another path to search the default gs fonts, we have to improve, but for now i'm closing the bug, thanks for reporting BUGS: 103891 svn path=/trunk/kdegraphics/kpdf/; revision=405583 --- xpdf/xpdf/GlobalParams.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index 5b8828a6d..19cc8ad07 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -100,6 +100,7 @@ static const char *displayFontDirs[] = { "/usr/share/fonts/default/Type1", "/usr/share/fonts/type1/gsfonts", "/usr/share/fonts/default/ghostscript/", + "/usr/share/fonts/Type1", NULL }; From 50a53164564320166af54551f7fab4f4da67190f Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 16 Apr 2005 19:13:44 +0000 Subject: [PATCH 044/245] Correct configure.in.in fixes 104012, thanks for reporting BUGS: 104012 svn path=/trunk/kdegraphics/kpdf/; revision=405956 --- configure.in.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in.in b/configure.in.in index 660b5f4a2..ced9fc038 100644 --- a/configure.in.in +++ b/configure.in.in @@ -55,11 +55,11 @@ fi dnl ##### Check for libjpeg AC_CHECK_LIB([jpeg], [jpeg_destroy_decompress],HAVE_LIBJPEG=yes,HAVE_LIBJPEG=no) -if test HAVE_LIBJPEG = yes; then +if test "$HAVE_LIBJPEG" = "yes"; then AC_CHECK_HEADERS([jpeglib.h],,HAVE_LIBJPEG=no) fi -if test HAVE_LIBJPEG = yes; then +if test "$HAVE_LIBJPEG" = "yes"; then LIBJPEG_LIBS="-ljpeg" AC_SUBST(LIBJPEG_LIBS) else From 9f12ab9634cefb306fe40de9cdcaf594c9223043 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 17 Apr 2005 21:53:50 +0000 Subject: [PATCH 045/245] remove warning svn path=/trunk/kdegraphics/kpdf/; revision=406202 --- core/generator_png/generator_png.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/generator_png/generator_png.cpp b/core/generator_png/generator_png.cpp index 391697928..775ff8e00 100644 --- a/core/generator_png/generator_png.cpp +++ b/core/generator_png/generator_png.cpp @@ -68,4 +68,5 @@ bool PNGGenerator::print( KPrinter& printer ) { QPainter p(&printer); p.drawPixmap(0, 0, *m_pix); + return true; } From a7338e2c030cb701d7d2130bf4577a45b9b2dadf Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 22 Apr 2005 21:38:52 +0000 Subject: [PATCH 046/245] =?UTF-8?q?Wrap=20completely=20the=20selected=20th?= =?UTF-8?q?umbnai=20with=20the=20select=20color.=20G=C3=B6rkem=20this=20wi?= =?UTF-8?q?ll=20come=20with=20KDE=203.5=20Florian,=20can=20you=20check=20t?= =?UTF-8?q?hat=20fixes=20issue=201.1=20=3F=20FEATURE:=20103660=20CCMAIL:?= =?UTF-8?q?=20holehan@gmx.de?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit svn path=/trunk/kdegraphics/kpdf/; revision=407243 --- ui/thumbnaillist.cpp | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/ui/thumbnaillist.cpp b/ui/thumbnaillist.cpp index 7c8443706..878c81ed0 100644 --- a/ui/thumbnaillist.cpp +++ b/ui/thumbnaillist.cpp @@ -38,7 +38,7 @@ class ThumbnailWidget : public QWidget void setSelected( bool selected ); // query methods - int heightHint() const { return m_pixmapHeight + m_labelHeight + 4; } + int heightHint() const { return m_pixmapHeight + m_labelHeight + m_margin; } int pixmapWidth() const { return m_pixmapWidth; } int pixmapHeight() const { return m_pixmapHeight; } int pageNumber() const { return m_page->number(); } @@ -49,6 +49,9 @@ class ThumbnailWidget : public QWidget void paintEvent(QPaintEvent *); private: + // the margin around the widget + static int const m_margin = 16; + // used to access 'forwardRightClick( .. )' and 'getBookmarkOverlay()' ThumbnailList * m_tl; const KPDFPage * m_page; @@ -444,7 +447,7 @@ ThumbnailWidget::ThumbnailWidget( QWidget * parent, const KPDFPage * kp, Thumbna void ThumbnailWidget::resizeFitWidth( int width ) { - m_pixmapWidth = width - 4; + m_pixmapWidth = width - m_margin; m_pixmapHeight = (int)(m_page->ratio() * m_pixmapWidth); resize( width, heightHint() ); } @@ -455,7 +458,7 @@ void ThumbnailWidget::setSelected( bool selected ) if ( m_selected != selected ) { m_selected = selected; - update( 0, m_pixmapHeight + 4, width(), m_labelHeight ); + update( 0, 0, width(), height() ); } } @@ -469,42 +472,44 @@ void ThumbnailWidget::mouseReleaseEvent( QMouseEvent * e ) void ThumbnailWidget::paintEvent( QPaintEvent * e ) { - int width = m_pixmapWidth + 4; + int width = m_pixmapWidth + m_margin; + int height = m_pixmapHeight + m_margin + m_labelHeight; QRect clipRect = e->rect(); if ( !clipRect.isValid() ) return; QPainter p( this ); - // draw the bottom label - if ( clipRect.bottom() > m_pixmapHeight + 3 ) - { - QColor fillColor = m_selected ? palette().active().highlight() : palette().active().base(); - p.fillRect( 0, m_pixmapHeight + 4, width, m_labelHeight, fillColor ); - p.drawText( 0, m_pixmapHeight + 4, width, m_labelHeight, Qt::AlignCenter, QString::number( m_labelNumber ) ); - } + // draw the bottom label + highlight mark + QColor fillColor = m_selected ? palette().active().highlight() : palette().active().base(); + p.fillRect( 0, 0, width, height, fillColor ); + p.drawText( 0, m_pixmapHeight + m_margin, width, m_labelHeight, Qt::AlignCenter, QString::number( m_labelNumber ) ); // draw page outline and pixmap - if ( clipRect.top() < m_pixmapHeight + 4 ) + if ( clipRect.top() < m_pixmapHeight + m_margin ) { // if page is bookmarked draw a colored border bool isBookmarked = m_page->hasBookmark(); // draw the inner rect p.setPen( isBookmarked ? QColor( 0xFF8000 ) : Qt::black ); - p.drawRect( 1, 1, m_pixmapWidth + 2, m_pixmapHeight + 2 ); + p.drawRect( m_margin/2 - 1, m_margin/2 - 1, m_pixmapWidth + 2, m_pixmapHeight + 2 ); // draw the clear rect p.setPen( isBookmarked ? QColor( 0x804000 ) : palette().active().base() ); - p.drawRect( 0, 0, m_pixmapWidth + 4, m_pixmapHeight + 4 ); // draw the bottom and right shadow edges if ( !isBookmarked ) { + int left, right, bottom, top; + left = m_margin/2 + 1; + right = m_margin/2 + m_pixmapWidth + 1; + bottom = m_pixmapHeight + m_margin/2 + 1; + top = m_margin/2 + 1; p.setPen( Qt::gray ); - p.drawLine( 5, m_pixmapHeight + 3, m_pixmapWidth + 3, m_pixmapHeight + 3 ); - p.drawLine( m_pixmapWidth + 3, 5, m_pixmapWidth + 3, m_pixmapHeight + 3 ); + p.drawLine( left, bottom, right, bottom ); + p.drawLine( right, top, right, bottom ); } // draw the page using the shared PagePainter class - p.translate( 2, 2 ); - clipRect.moveBy( -2, -2 ); + p.translate( m_margin/2, m_margin/2 ); + clipRect.moveBy( -m_margin/2, -m_margin/2 ); clipRect = clipRect.intersect( QRect( 0, 0, m_pixmapWidth, m_pixmapHeight ) ); if ( clipRect.isValid() ) { From 5d2ed914f757555c7998ca247eae9c1833f5ac2e Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 22 Apr 2005 22:23:23 +0000 Subject: [PATCH 047/245] - Use correct text color for highlighted thumbnails - Use a fixed color on presentation mode for the overlay numbers as the background we use is always black there's no point in obeying the pallette as that can make the overlay invisible. Fixes issue 1.2 from http://www.openusability.org/forum/forum.php?thread_id=325&forum_id=304 Florian can you check CCMAIL: holehan@gmx.de svn path=/trunk/kdegraphics/kpdf/; revision=407256 --- ui/presentationwidget.cpp | 8 +------- ui/thumbnaillist.cpp | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index 50097f976..d8303cda4 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -537,13 +537,7 @@ void PresentationWidget::generateOverlay() QImage image( doublePixmap.convertToImage().smoothScale( side, side ) ); image.setAlphaBuffer( true ); - // generate a monochrome pixmap using grey level as alpha channel and - // a saturated hilight color as base color - int hue, sat, val; - palette().active().highlight().getHsv( &hue, &sat, &val ); - sat = (sat + 255) / 2; - const QColor & color = QColor( hue, sat, val, QColor::Hsv ); - int red = color.red(), green = color.green(), blue = color.blue(), + int red = 52, green = 115, blue = 178, pixels = image.width() * image.height(); unsigned int * data = (unsigned int *)image.bits(); for( int i = 0; i < pixels; ++i ) diff --git a/ui/thumbnaillist.cpp b/ui/thumbnaillist.cpp index 878c81ed0..247e17588 100644 --- a/ui/thumbnaillist.cpp +++ b/ui/thumbnaillist.cpp @@ -482,6 +482,7 @@ void ThumbnailWidget::paintEvent( QPaintEvent * e ) // draw the bottom label + highlight mark QColor fillColor = m_selected ? palette().active().highlight() : palette().active().base(); p.fillRect( 0, 0, width, height, fillColor ); + p.setPen( m_selected ? palette().active().highlightedText() : palette().active().text() ); p.drawText( 0, m_pixmapHeight + m_margin, width, m_labelHeight, Qt::AlignCenter, QString::number( m_labelNumber ) ); // draw page outline and pixmap From 3b53efc6cdd27714f5c5f904aa653b0ce1c3e1f5 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 23 Apr 2005 11:32:48 +0000 Subject: [PATCH 048/245] Fix issue 1.4 svn path=/trunk/kdegraphics/kpdf/; revision=407337 --- part.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/part.cpp b/part.cpp index f9bbe00c8..7f1f3b28f 100644 --- a/part.cpp +++ b/part.cpp @@ -131,10 +131,12 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_toolBox = new QToolBox( m_leftPanel ); leftPanelLayout->addWidget( m_toolBox ); + int index; // [left toolbox: Table of Contents] | [] TOC * tocFrame = new TOC( m_toolBox, m_document ); connect(tocFrame, SIGNAL(hasTOC(bool)), this, SLOT(enableTOC(bool))); - m_toolBox->addItem( tocFrame, QIconSet(SmallIcon("text_left")), i18n("Contents") ); + index = m_toolBox->addItem( tocFrame, QIconSet(SmallIcon("text_left")), i18n("Contents") ); + m_toolBox->setItemToolTip(index, i18n("Contents")); enableTOC( false ); // [left toolbox: Thumbnails and Bookmarks] | [] @@ -148,7 +150,8 @@ Part::Part(QWidget *parentWidget, const char *widgetName, thumbsBox->setStretchFactor( m_searchWidget, 100 ); thumbsBox->setStretchFactor( m_thumbnailList, 100 ); // thumbsBox->setStretchFactor( m_tc, 1 ); - m_toolBox->addItem( thumbsBox, QIconSet(SmallIcon("thumbnail")), i18n("Thumbnails") ); + index = m_toolBox->addItem( thumbsBox, QIconSet(SmallIcon("thumbnail")), i18n("Thumbnails") ); + m_toolBox->setItemToolTip(index, i18n("Thumbnails")); m_toolBox->setCurrentItem( thumbsBox ); slotShowLeftPanel(); From 1aecd53f192cc40c8d7d0bead3c07f9223638cc3 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 24 Apr 2005 21:13:38 +0000 Subject: [PATCH 049/245] adding a configure.in.bot to give some warnings svn path=/trunk/kdegraphics/kpdf/; revision=407624 --- configure.in.bot | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 configure.in.bot diff --git a/configure.in.bot b/configure.in.bot new file mode 100644 index 000000000..48cf5b52d --- /dev/null +++ b/configure.in.bot @@ -0,0 +1,20 @@ +if test -z "$FREETYPE_CONFIG"; then + echo "" + echo "You're missing freetype development libs." + echo "KPDF will not be build without them" + echo "" +fi + +if test -z "$XFT_LIBS"; then + echo "" + echo "You're missing XFT development libs." + echo "KPDF will not be build without them" + echo "" +fi + +if test "$HAVE_LIBJPEG" = "no"; then + echo "" + echo "You're missing libjpeg development libs." + echo "KPDF will not be build without them" + echo "" +fi From b44ac6e5f812741ca5deac17ef1da651b1faca0f Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 25 Apr 2005 17:27:19 +0000 Subject: [PATCH 050/245] implement dcop currentPage() Based on a patch from bernhard@schiffner-limbach.de Will be in KDE 3.5 svn path=/trunk/kdegraphics/kpdf/; revision=407816 --- dcop.h | 1 + part.cpp | 6 ++++++ part.h | 1 + 3 files changed, 8 insertions(+) diff --git a/dcop.h b/dcop.h index 40db09b89..778687f23 100644 --- a/dcop.h +++ b/dcop.h @@ -20,6 +20,7 @@ K_DCOP virtual ASYNC goToPage(uint page) = 0; virtual ASYNC openDocument(KURL doc) = 0; virtual uint pages() = 0; + virtual uint currentPage() = 0; virtual void slotPreferences() = 0; virtual void slotFind() = 0; virtual void slotPrintPreview() = 0; diff --git a/part.cpp b/part.cpp index 7f1f3b28f..21cde396b 100644 --- a/part.cpp +++ b/part.cpp @@ -307,6 +307,12 @@ uint Part::pages() return m_document->pages(); } +uint Part::currentPage() +{ + if ( m_document->pages() == 0 ) return 0; + else return m_document->currentPage()+1; +} + //this don't go anywhere but is required by genericfactory.h KAboutData* Part::createAboutData() { diff --git a/part.h b/part.h index b0127a753..1361d77ef 100644 --- a/part.h +++ b/part.h @@ -75,6 +75,7 @@ public: ASYNC goToPage(uint page); ASYNC openDocument(KURL doc); uint pages(); + uint currentPage(); protected: // reimplemented from KParts::ReadOnlyPart From 1452bec703fc63e0730c15145a5199f59347dfcf Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 26 Apr 2005 20:40:51 +0000 Subject: [PATCH 051/245] fix gnome's unability to understand that if there is no %u, %U or %F implies that the program takes %f Add %U as we can accept a full list of url's Backporting in a moment BUG: 104471 svn path=/trunk/kdegraphics/kpdf/; revision=408033 --- shell/kpdf.desktop | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/kpdf.desktop b/shell/kpdf.desktop index 5dddc5013..c0fd505c8 100644 --- a/shell/kpdf.desktop +++ b/shell/kpdf.desktop @@ -21,6 +21,7 @@ GenericName[el]=ΠÏοβολέας PDF GenericName[eo]=PDF-rigardilo GenericName[es]=Visor de PDF GenericName[et]=PDF failide vaataja +GenericName[eu]=PDF ikustailua GenericName[fi]=PDF-näytin GenericName[fr]=Afficheur PDF GenericName[ga]=Amharcán PDF @@ -63,7 +64,7 @@ GenericName[xh]=Umboniseli we PDF GenericName[xx]=xxPDF Viewerxx GenericName[zh_CN]=PDF 查看器 GenericName[zu]=Umboniseli we PDF -Exec=kpdf %i %m -caption "%c" +Exec=kpdf %U %i %m -caption "%c" Icon=kpdf Type=Application DocPath=kpdf/index.html From 1e1eeb8e65efb470da01eb617830efb7bfdc69f8 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 27 Apr 2005 08:19:32 +0000 Subject: [PATCH 052/245] Don't crash on malformed documents that have links to unexistant places, for example in smli_tr-2005-143.pdf link [3] from page 4 does not point anywhere (Acrobat Reader confirms it) BUGS: 104626 svn path=/trunk/kdegraphics/kpdf/; revision=408111 --- core/document.cpp | 1 + xpdf/xpdf/Catalog.cc | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 6e9f4beb9..ddde53480 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -898,6 +898,7 @@ void KPDFDocument::processLink( const KPDFLink * link ) case KPDFLink::Goto: { const KPDFLinkGoto * go = static_cast< const KPDFLinkGoto * >( link ); d->nextDocumentViewport = go->destViewport(); + if (d->nextDocumentViewport.pageNumber == -1) return; // Explanation of why d->nextDocumentViewport is needed // all openRelativeFile does is launch a signal telling we diff --git a/xpdf/xpdf/Catalog.cc b/xpdf/xpdf/Catalog.cc index ed0306049..f1547c85d 100644 --- a/xpdf/xpdf/Catalog.cc +++ b/xpdf/xpdf/Catalog.cc @@ -399,13 +399,20 @@ GBool NameTree::lookup(GString *name, Object *obj) { Entry *entry; - entry = *(Entry **) bsearch(name, entries, + Entry **e = (Entry **) bsearch(name, entries, length, sizeof(Entry *), Entry::cmp); + if (e) entry = *e; + else + { + error(-1, "failed to look up %s\n", name->getCString()); + obj->initNull(); + return gFalse; + } if (entry != NULL) { entry->value.fetch(xref, obj); return gTrue; } else { - printf("failed to look up %s\n", name->getCString()); + error(-1, "failed to look up %s\n", name->getCString()); obj->initNull(); From 56f6f83fb9e5ace9b95f0f5fd8b504ee17ce2daf Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 27 Apr 2005 08:27:58 +0000 Subject: [PATCH 053/245] Accept "invalid" viewports when the link is to an external pdf svn path=/trunk/kdegraphics/kpdf/; revision=408113 --- core/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/document.cpp b/core/document.cpp index ddde53480..c463e491d 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -898,7 +898,6 @@ void KPDFDocument::processLink( const KPDFLink * link ) case KPDFLink::Goto: { const KPDFLinkGoto * go = static_cast< const KPDFLinkGoto * >( link ); d->nextDocumentViewport = go->destViewport(); - if (d->nextDocumentViewport.pageNumber == -1) return; // Explanation of why d->nextDocumentViewport is needed // all openRelativeFile does is launch a signal telling we @@ -916,6 +915,7 @@ void KPDFDocument::processLink( const KPDFLink * link ) } else { + if (d->nextDocumentViewport.pageNumber == -1) return; setViewport( d->nextDocumentViewport, -1, true ); d->nextDocumentViewport = DocumentViewport(); } From 2cdbab1736d2d089eeac2b162399108441d60b67 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 30 Apr 2005 14:34:53 +0000 Subject: [PATCH 054/245] Don't assume Encoding array of Type1 fonts end in "foo def". http://partners.adobe.com/public/developer/en/font/T1_SPEC.PDF says "This sequence of assignments must be followed by an instance of the token def or readonly; such a token may not occur within the sequence of assignments." so it must end with "readonly" "def" "readonly def" (That is what most fonts are using and this is why it was not crashing" BUG: 104786 svn path=/trunk/kdegraphics/kpdf/; revision=408796 --- xpdf/fofi/FoFiType1.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/xpdf/fofi/FoFiType1.cc b/xpdf/fofi/FoFiType1.cc index 2f767766d..1ee5175f7 100644 --- a/xpdf/fofi/FoFiType1.cc +++ b/xpdf/fofi/FoFiType1.cc @@ -187,9 +187,14 @@ void FoFiType1::parse() { } } } else { - if (strtok(buf, " \t") && - (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { - break; + p = strtok(buf, " \t\n\r"); + if (p) + { + if (!strcmp(p, "def")) break; + if (!strcmp(p, "readonly")) break; + // the spec does not says this but i'm mantaining old xpdf behaviour that accepts "foo def" as end of the encoding array + p = strtok(buf, " \t\n\r"); + if (p && !strcmp(p, "def")) break; } } line = line1; From 2f384e0c2bae5b9861dbeb558746634d59db537b Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 1 May 2005 14:04:04 +0000 Subject: [PATCH 055/245] dcop KURL currentDocument() Based on a patch by Bernhard Schiffner CCMAIL: bernhard@schiffner-limbach.de svn path=/trunk/kdegraphics/kpdf/; revision=409036 --- core/document.cpp | 7 +++++++ core/document.h | 1 + dcop.h | 1 + part.cpp | 5 +++++ part.h | 1 + 5 files changed, 15 insertions(+) diff --git a/core/document.cpp b/core/document.cpp index c463e491d..e02fb68ff 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -219,6 +219,8 @@ void KPDFDocument::closeDocument() delete generator; generator = 0; + d->url = KURL(); + // remove requests left in queue QValueList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(); QValueList< PixmapRequest * >::iterator sEnd = d->pixmapRequestsStack.end(); @@ -366,6 +368,11 @@ uint KPDFDocument::pages() const return pages_vector.size(); } +KURL KPDFDocument::currentDocument() const +{ + return d->url; +} + bool KPDFDocument::isAllowed( int flags ) const { return generator ? generator->isAllowed( flags ) : false; diff --git a/core/document.h b/core/document.h index 16f52240a..5feebf38a 100644 --- a/core/document.h +++ b/core/document.h @@ -72,6 +72,7 @@ class KPDFDocument : public QObject const DocumentViewport & viewport() const; uint currentPage() const; uint pages() const; + KURL currentDocument() const; bool isAllowed( int /*Document::Permisison(s)*/ ) const; bool historyAtBegin() const; bool historyAtEnd() const; diff --git a/dcop.h b/dcop.h index 778687f23..322b1cc24 100644 --- a/dcop.h +++ b/dcop.h @@ -21,6 +21,7 @@ K_DCOP virtual ASYNC openDocument(KURL doc) = 0; virtual uint pages() = 0; virtual uint currentPage() = 0; + virtual KURL currentDocument() = 0; virtual void slotPreferences() = 0; virtual void slotFind() = 0; virtual void slotPrintPreview() = 0; diff --git a/part.cpp b/part.cpp index 21cde396b..6fe708b3c 100644 --- a/part.cpp +++ b/part.cpp @@ -313,6 +313,11 @@ uint Part::currentPage() else return m_document->currentPage()+1; } +KURL Part::currentDocument() +{ + return m_document->currentDocument(); +} + //this don't go anywhere but is required by genericfactory.h KAboutData* Part::createAboutData() { diff --git a/part.h b/part.h index 1361d77ef..74e221101 100644 --- a/part.h +++ b/part.h @@ -76,6 +76,7 @@ public: ASYNC openDocument(KURL doc); uint pages(); uint currentPage(); + KURL currentDocument(); protected: // reimplemented from KParts::ReadOnlyPart From 560868e9dde202518271c6036075347492317d61 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 1 May 2005 18:48:10 +0000 Subject: [PATCH 056/245] fix bug 104900. Enrico i tried to see if that was needed for some corner case but could not find it, please review if this change breaks something else and tell me if it does not and i'll backport to the stable branch BUGS: 104900 svn path=/trunk/kdegraphics/kpdf/; revision=409086 --- ui/pageview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index e9f4db604..5e3864847 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -774,7 +774,7 @@ void PageView::contentsMouseMoveEvent( QMouseEvent * e ) case MouseZoom: case MouseSelect: // set second corner of selection - if ( (leftButton || d->aPrevAction) && !d->mouseSelectionRect.isNull() ) + if ( (leftButton || d->aPrevAction) ) selectionEndPoint( e->x(), e->y() ); break; From 4c5ee1aafc4c10e3592b8be262ee0c764c071e7e Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 1 May 2005 18:49:25 +0000 Subject: [PATCH 057/245] remove extra ( ) svn path=/trunk/kdegraphics/kpdf/; revision=409088 --- ui/pageview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 5e3864847..170e663af 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -774,7 +774,7 @@ void PageView::contentsMouseMoveEvent( QMouseEvent * e ) case MouseZoom: case MouseSelect: // set second corner of selection - if ( (leftButton || d->aPrevAction) ) + if ( leftButton || d->aPrevAction ) selectionEndPoint( e->x(), e->y() ); break; From 247c86d946244a88fcc1dcbc40345e4c4496220c Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 1 May 2005 21:49:18 +0000 Subject: [PATCH 058/245] Try to make size saving work, can you guys check (need to update to cvs version or apply this patch to 3.4 branch) and tell me if it works for you too? CCBUGS: 94851 svn path=/trunk/kdegraphics/kpdf/; revision=409128 --- shell/main.cpp | 3 +-- shell/shell.cpp | 24 +++++++++++++++++++++--- shell/shell.h | 14 +++++++++++--- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/shell/main.cpp b/shell/main.cpp index de73825a8..4684a2291 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -69,9 +69,8 @@ int main(int argc, char** argv) { for (int i = 0; i < args->count(); ++i) { - KPDF::Shell* widget = new KPDF::Shell; + KPDF::Shell* widget = new KPDF::Shell(args->url(i)); widget->show(); - widget->openURL(args->url(i)); } } args->clear(); diff --git a/shell/shell.cpp b/shell/shell.cpp index 6a32a5442..7398e7057 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -19,6 +19,7 @@ // qt/kde includes #include +#include #include #include #include @@ -41,6 +42,17 @@ using namespace KPDF; Shell::Shell() : KParts::MainWindow(0, "KPDF::Shell"), m_menuBarWasShown(true), m_toolBarWasShown(true) +{ + init(); +} + +Shell::Shell(const KURL &url) +{ + m_openUrl = url; + init(); +} + +void Shell::init() { // set the shell's ui resource file setXMLFile("shell.rc"); @@ -76,13 +88,21 @@ Shell::Shell() } connect( this, SIGNAL( restoreDocument(const KURL &, int) ),m_part, SLOT( restoreDocument(const KURL &, int))); connect( this, SIGNAL( saveDocumentRestoreInfo(KConfig*) ), m_part, SLOT( saveDocumentRestoreInfo(KConfig*))); - + readSettings(); if (!KGlobal::config()->hasGroup("MainWindow")) { KMainWindowInterface kmwi(this); kmwi.maximize(); } + setAutoSaveSettings(); + + if (m_openUrl.isValid()) QTimer::singleShot(0, this, SLOT(delayedOpen())); +} + +void Shell::delayedOpen() +{ + openURL(m_openUrl); } Shell::~Shell() @@ -140,7 +160,6 @@ void Shell::readSettings() void Shell::writeSettings() { - saveMainWindowSettings(KGlobal::config(), "MainWindow"); m_recent->saveEntries( KGlobal::config() ); KGlobal::config()->setDesktopGroup(); KGlobal::config()->writeEntry( "FullScreen", m_fullScreenAction->isChecked()); @@ -200,7 +219,6 @@ Shell::fileOpen() void Shell::optionsConfigureToolbars() { - saveMainWindowSettings(KGlobal::config(), "MainWindow"); KEditToolbar dlg(factory()); connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(applyNewToolbarConfig())); dlg.exec(); diff --git a/shell/shell.h b/shell/shell.h index 391db6726..a3dabe79b 100644 --- a/shell/shell.h +++ b/shell/shell.h @@ -43,6 +43,11 @@ namespace KPDF */ Shell(); + /** + * Open an url + */ + Shell(const KURL &url); + /** * Default Destructor */ @@ -75,16 +80,18 @@ namespace KPDF void slotUpdateFullScreen(); void slotShowMenubar(); - public slots: - void openURL( const KURL & url ); + void openURL( const KURL & url ); + void delayedOpen(); signals: void restoreDocument(const KURL &url, int page); void saveDocumentRestoreInfo(KConfig* config); - + + private: void setupAccel(); void setupActions(); + void init(); private: KParts::ReadOnlyPart* m_part; @@ -94,6 +101,7 @@ namespace KPDF KToggleAction* m_showMenuBarAction; KToggleAction* m_showToolBarAction; bool m_menuBarWasShown, m_toolBarWasShown; + KURL m_openUrl; }; } From a7531593312130ab7dabdbd2b1e3186c0ac6b0b3 Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Fri, 6 May 2005 12:00:28 +0000 Subject: [PATCH 059/245] fix disabled icons svn path=/trunk/KDE/kdegraphics/kpdf/; revision=410001 --- ui/minibar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/minibar.cpp b/ui/minibar.cpp index 8f7f92c54..3cf8a8a56 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -98,7 +98,7 @@ MiniBar::MiniBar( QWidget * parent, KPDFDocument * document ) gridLayout->addMultiCellWidget( m_progressWidget, 0, 0, 0, 4 ); // bottom: left prev_page button m_prevButton = new HoverButton( this ); - m_prevButton->setPixmap( SmallIcon("1leftarrow") ); + m_prevButton->setIconSet( SmallIconSet("1leftarrow") ); gridLayout->addWidget( m_prevButton, 1, 0 ); // bottom: left lineEdit (current page box) m_pagesEdit = new PagesEdit( this ); @@ -110,7 +110,7 @@ MiniBar::MiniBar( QWidget * parent, KPDFDocument * document ) gridLayout->addWidget( m_pagesButton, 1, 3 ); // bottom: right next_page button m_nextButton = new HoverButton( this ); - m_nextButton->setPixmap( SmallIcon("1rightarrow") ); + m_nextButton->setIconSet( SmallIconSet("1rightarrow") ); gridLayout->addWidget( m_nextButton, 1, 4 ); horLayout->addLayout( gridLayout ); From 79b438183b4ff98ae270743d1c3331c5d13455b5 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 7 May 2005 11:32:31 +0000 Subject: [PATCH 060/245] Fix usability issues 2.1, 2.2 and 2.3 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=410271 --- part.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/part.cpp b/part.cpp index 6fe708b3c..728543a83 100644 --- a/part.cpp +++ b/part.cpp @@ -117,7 +117,8 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_splitter->setOpaqueResize( true ); setWidget( m_splitter ); - m_showLeftPanel = new KToggleAction( i18n( "Show &left panel"), 0, this, SLOT( slotShowLeftPanel() ), actionCollection(), "show_leftpanel" ); + m_showLeftPanel = new KToggleAction( i18n( "Show &Navigation Panel"), 0, this, SLOT( slotShowLeftPanel() ), actionCollection(), "show_leftpanel" ); + m_showLeftPanel->setCheckedState( i18n( "Hide &Navigation Panel") ); m_showLeftPanel->setShortcut( "CTRL+L" ); m_showLeftPanel->setChecked( Settings::showLeftPanel() ); @@ -229,7 +230,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_saveAs = KStdAction::saveAs( this, SLOT( slotSaveFileAs() ), ac, "save" ); m_saveAs->setEnabled( false ); KAction * prefs = KStdAction::preferences( this, SLOT( slotPreferences() ), ac, "preferences" ); - prefs->setText( i18n( "Configure PDF Viewer..." ) ); + prefs->setText( i18n( "Configure KPDF..." ) ); m_printPreview = KStdAction::printPreview( this, SLOT( slotPrintPreview() ), ac ); m_printPreview->setEnabled( false ); From 9946534b1d4daf58a41842ad8c92748850ee67f7 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 7 May 2005 16:45:56 +0000 Subject: [PATCH 061/245] generator_png -> generator_kimgio svn path=/trunk/KDE/kdegraphics/kpdf/; revision=410352 --- core/Makefile.am | 2 +- core/document.cpp | 40 ++++++++++++++----- .../Makefile.am | 0 .../generator_png.cpp | 0 .../generator_png.h | 0 5 files changed, 32 insertions(+), 10 deletions(-) rename core/{generator_png => generator_kimgio}/Makefile.am (100%) rename core/{generator_png => generator_kimgio}/generator_png.cpp (100%) rename core/{generator_png => generator_kimgio}/generator_png.h (100%) diff --git a/core/Makefile.am b/core/Makefile.am index c39037c24..36779322e 100644 --- a/core/Makefile.am +++ b/core/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = generator_pdf generator_png +SUBDIRS = generator_pdf generator_kimgio INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(srcdir)/../xpdf -I$(srcdir)/../xpdf/goo -I$(top_builddir)/kpdf $(all_includes) diff --git a/core/document.cpp b/core/document.cpp index e02fb68ff..379aaf377 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -12,11 +12,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -32,7 +34,7 @@ #include "page.h" #include "link.h" #include "generator_pdf/generator_pdf.h" // PDF generator -#include "generator_png/generator_png.h" // PDF generator +#include "generator_kimgio/generator_kimgio.h" // KIMGIO generator #include "conf/settings.h" // structures used internally by KPDFDocument for local variables storage @@ -52,6 +54,9 @@ class KPDFDocumentPrivate QString docFileName; QString xmlFileName; + // a list of the mimetypes qimage can understand + QStringList kimgioMimes; + // viewport stuff QValueList< DocumentViewport > viewportHistory; QValueList< DocumentViewport >::iterator viewportIterator; @@ -107,6 +112,14 @@ KPDFDocument::KPDFDocument() d->allocatedPixmapsTotalMemory = 0; d->memCheckTimer = 0; d->saveBookmarksTimer = 0; + KImageIO::registerFormats(); + QStringList list = QImage::inputFormatList(); + QStringList::Iterator it = list.begin(); + while( it != list.end() ) + { + d->kimgioMimes << KMimeType::findByPath(QString("foo.%1").arg(*it), 0, true)->name(); + ++it; + } } KPDFDocument::~KPDFDocument() @@ -138,19 +151,28 @@ bool KPDFDocument::openDocument( const QString & docFile, const KURL & url ) // create the generator based on the file's mimetype KMimeType::Ptr mime = KMimeType::findByPath( docFile ); - QString mimeName = mime->name(); - if ( mimeName == "application/pdf" ) + if ( (*mime).is( "application/pdf" ) ) generator = new PDFGenerator( this ); // else if ( mimeName == "application/postscript" ) // kdError() << "PS generator not available" << endl; - else if ( mimeName == "image/png" ) - { - generator = new PNGGenerator( this ); - } else { - kdWarning() << "Unknown mimetype '" << mimeName << "'." << endl; - return false; + QStringList::Iterator it = d->kimgioMimes.begin(); + while( it != d->kimgioMimes.end() ) + { + kdDebug() << *it << endl; + if ( (*mime).is( *it ) ) + { + generator = new PNGGenerator( this ); + break; + } + ++it; + } + if ( it == d->kimgioMimes.end() ) + { + kdWarning() << "Unknown mimetype '" << mime->name() << "'." << endl; + return false; + } } // 1. load Document (and set busy cursor while loading) diff --git a/core/generator_png/Makefile.am b/core/generator_kimgio/Makefile.am similarity index 100% rename from core/generator_png/Makefile.am rename to core/generator_kimgio/Makefile.am diff --git a/core/generator_png/generator_png.cpp b/core/generator_kimgio/generator_png.cpp similarity index 100% rename from core/generator_png/generator_png.cpp rename to core/generator_kimgio/generator_png.cpp diff --git a/core/generator_png/generator_png.h b/core/generator_kimgio/generator_png.h similarity index 100% rename from core/generator_png/generator_png.h rename to core/generator_kimgio/generator_png.h From c8a96f9fd22d86b48559c95747e4edfbb6356ace Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 7 May 2005 16:54:38 +0000 Subject: [PATCH 062/245] more generator_png -> generator_kimgio renaming svn path=/trunk/KDE/kdegraphics/kpdf/; revision=410354 --- core/Makefile.am | 2 +- core/document.cpp | 2 +- core/generator_kimgio/Makefile.am | 6 ++--- ...generator_png.cpp => generator_kimgio.cpp} | 22 +++++++++---------- .../{generator_png.h => generator_kimgio.h} | 6 ++--- 5 files changed, 19 insertions(+), 19 deletions(-) rename core/generator_kimgio/{generator_png.cpp => generator_kimgio.cpp} (66%) rename core/generator_kimgio/{generator_png.h => generator_kimgio.h} (91%) diff --git a/core/Makefile.am b/core/Makefile.am index 36779322e..74c774855 100644 --- a/core/Makefile.am +++ b/core/Makefile.am @@ -4,7 +4,7 @@ INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(srcdir)/../xpdf -I$(srcd METASOURCES = AUTO -libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la ./generator_png/libgeneratorpng.la +libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la ./generator_kimgio/libgeneratorkimgio.la libkpdfcore_la_SOURCES = document.cpp link.cpp page.cpp pagetransition.cpp noinst_LTLIBRARIES = libkpdfcore.la diff --git a/core/document.cpp b/core/document.cpp index 379aaf377..5d5a4e5cd 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -163,7 +163,7 @@ bool KPDFDocument::openDocument( const QString & docFile, const KURL & url ) kdDebug() << *it << endl; if ( (*mime).is( *it ) ) { - generator = new PNGGenerator( this ); + generator = new KIMGIOGenerator( this ); break; } ++it; diff --git a/core/generator_kimgio/Makefile.am b/core/generator_kimgio/Makefile.am index 2c23f4bed..5a93221d1 100644 --- a/core/generator_kimgio/Makefile.am +++ b/core/generator_kimgio/Makefile.am @@ -1,6 +1,6 @@ INCLUDES = -I$(srcdir)/../../ $(all_includes) -libgeneratorpng_la_LDFLAGS = $(all_libraries) -libgeneratorpng_la_SOURCES = generator_png.cpp +libgeneratorkimgio_la_LDFLAGS = $(all_libraries) +libgeneratorkimgio_la_SOURCES = generator_kimgio.cpp -noinst_LTLIBRARIES = libgeneratorpng.la +noinst_LTLIBRARIES = libgeneratorkimgio.la diff --git a/core/generator_kimgio/generator_png.cpp b/core/generator_kimgio/generator_kimgio.cpp similarity index 66% rename from core/generator_kimgio/generator_png.cpp rename to core/generator_kimgio/generator_kimgio.cpp index 775ff8e00..bb7546868 100644 --- a/core/generator_kimgio/generator_png.cpp +++ b/core/generator_kimgio/generator_kimgio.cpp @@ -12,18 +12,18 @@ #include #include "core/page.h" -#include "generator_png.h" +#include "generator_kimgio.h" -PNGGenerator::PNGGenerator( KPDFDocument * document ) : Generator( document ) +KIMGIOGenerator::KIMGIOGenerator( KPDFDocument * document ) : Generator( document ) { } -PNGGenerator::~PNGGenerator() +KIMGIOGenerator::~KIMGIOGenerator() { delete m_pix; } -bool PNGGenerator::loadDocument( const QString & fileName, QValueVector & pagesVector ) +bool KIMGIOGenerator::loadDocument( const QString & fileName, QValueVector & pagesVector ) { m_pix = new QPixmap(fileName); @@ -35,36 +35,36 @@ bool PNGGenerator::loadDocument( const QString & fileName, QValueVectorpage->setPixmap(request->id, p); } -void PNGGenerator::generateSyncTextPage( KPDFPage * ) +void KIMGIOGenerator::generateSyncTextPage( KPDFPage * ) { } -bool PNGGenerator::supportsSearching() const +bool KIMGIOGenerator::supportsSearching() const { return false; } -bool PNGGenerator::hasFonts() const +bool KIMGIOGenerator::hasFonts() const { return false; } -void PNGGenerator::putFontInfo( KListView * ) +void KIMGIOGenerator::putFontInfo( KListView * ) { } -bool PNGGenerator::print( KPrinter& printer ) +bool KIMGIOGenerator::print( KPrinter& printer ) { QPainter p(&printer); p.drawPixmap(0, 0, *m_pix); diff --git a/core/generator_kimgio/generator_png.h b/core/generator_kimgio/generator_kimgio.h similarity index 91% rename from core/generator_kimgio/generator_png.h rename to core/generator_kimgio/generator_kimgio.h index 7a85db3c8..bda411f2d 100644 --- a/core/generator_kimgio/generator_png.h +++ b/core/generator_kimgio/generator_kimgio.h @@ -12,11 +12,11 @@ #include "core/generator.h" -class PNGGenerator : public Generator +class KIMGIOGenerator : public Generator { public: - PNGGenerator( KPDFDocument * document ); - virtual ~PNGGenerator(); + KIMGIOGenerator( KPDFDocument * document ); + virtual ~KIMGIOGenerator(); // [INHERITED] load a document and fill up the pagesVector bool loadDocument( const QString & fileName, QValueVector & pagesVector ); From ed0b6640398e998492e10b467916efe7505b13f7 Mon Sep 17 00:00:00 2001 From: Jonathan Riddell Date: Tue, 10 May 2005 21:47:53 +0000 Subject: [PATCH 063/245] Move application icons to global theme svn path=/trunk/KDE/kdegraphics/kpdf/; revision=412178 --- cr128-app-kpdf.png => hi128-app-kpdf.png | Bin cr16-app-kpdf.png => hi16-app-kpdf.png | Bin cr22-app-kpdf.png => hi22-app-kpdf.png | Bin cr32-app-kpdf.png => hi32-app-kpdf.png | Bin cr48-app-kpdf.png => hi48-app-kpdf.png | Bin cr64-app-kpdf.png => hi64-app-kpdf.png | Bin kpdf.svgz => hisc-app-kpdf.svgz | Bin 7 files changed, 0 insertions(+), 0 deletions(-) rename cr128-app-kpdf.png => hi128-app-kpdf.png (100%) rename cr16-app-kpdf.png => hi16-app-kpdf.png (100%) rename cr22-app-kpdf.png => hi22-app-kpdf.png (100%) rename cr32-app-kpdf.png => hi32-app-kpdf.png (100%) rename cr48-app-kpdf.png => hi48-app-kpdf.png (100%) rename cr64-app-kpdf.png => hi64-app-kpdf.png (100%) rename kpdf.svgz => hisc-app-kpdf.svgz (100%) diff --git a/cr128-app-kpdf.png b/hi128-app-kpdf.png similarity index 100% rename from cr128-app-kpdf.png rename to hi128-app-kpdf.png diff --git a/cr16-app-kpdf.png b/hi16-app-kpdf.png similarity index 100% rename from cr16-app-kpdf.png rename to hi16-app-kpdf.png diff --git a/cr22-app-kpdf.png b/hi22-app-kpdf.png similarity index 100% rename from cr22-app-kpdf.png rename to hi22-app-kpdf.png diff --git a/cr32-app-kpdf.png b/hi32-app-kpdf.png similarity index 100% rename from cr32-app-kpdf.png rename to hi32-app-kpdf.png diff --git a/cr48-app-kpdf.png b/hi48-app-kpdf.png similarity index 100% rename from cr48-app-kpdf.png rename to hi48-app-kpdf.png diff --git a/cr64-app-kpdf.png b/hi64-app-kpdf.png similarity index 100% rename from cr64-app-kpdf.png rename to hi64-app-kpdf.png diff --git a/kpdf.svgz b/hisc-app-kpdf.svgz similarity index 100% rename from kpdf.svgz rename to hisc-app-kpdf.svgz From 9047a879bd5db63223625155e51d5115a383a11f Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 12 May 2005 10:17:45 +0000 Subject: [PATCH 064/245] Fordward port fix for bug 105454 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=412670 --- ui/pageview.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 170e663af..854d79ec2 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -887,22 +887,22 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) { double nX = (double)(e->x() - pageItem->geometry().left()) / (double)pageItem->width(), nY = (double)(e->y() - pageItem->geometry().top()) / (double)pageItem->height(); - const ObjectRect * rect; - rect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY ); - if ( rect ) + const ObjectRect * linkRect, * imageRect; + linkRect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY ); + if ( linkRect ) { // handle click over a link - const KPDFLink * link = static_cast< const KPDFLink * >( rect->pointer() ); + const KPDFLink * link = static_cast< const KPDFLink * >( linkRect->pointer() ); d->document->processLink( link ); } - rect = pageItem->page()->hasObject( ObjectRect::Image, nX, nY ); - if ( rect ) + imageRect = pageItem->page()->hasObject( ObjectRect::Image, nX, nY ); + if ( imageRect ) { // handle click over a image } - if (!rect) + if (!linkRect && !imageRect) { // if not on a rect, the click selects the page d->document->setViewportPage( pageItem->pageNumber(), PAGEVIEW_ID ); From 0fba2aceca3169a57d173f38c60cd3341821808f Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 17 May 2005 16:44:05 +0000 Subject: [PATCH 065/245] Use zlib for decoding FlateStreams adds 100 lines and removes 500, zlib has probably had more sevurity reviews and is faster. Taken from poppler svn path=/trunk/KDE/kdegraphics/kpdf/; revision=415052 --- xpdf/xpdf/FlateStream.cc | 107 +++++++++++++++++++++++++++++++++++++++ xpdf/xpdf/FlateStream.h | 67 ++++++++++++++++++++++++ xpdf/xpdf/Makefile.am | 2 +- xpdf/xpdf/Stream.cc | 4 +- xpdf/xpdf/Stream.h | 2 +- 5 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 xpdf/xpdf/FlateStream.cc create mode 100644 xpdf/xpdf/FlateStream.h diff --git a/xpdf/xpdf/FlateStream.cc b/xpdf/xpdf/FlateStream.cc new file mode 100644 index 000000000..cfdd6fdd6 --- /dev/null +++ b/xpdf/xpdf/FlateStream.cc @@ -0,0 +1,107 @@ +//======================================================================== +// +// FlateStream.cc +// +// Copyright (C) 2005, Jeff Muizelaar +// +//======================================================================== +#include "FlateStream.h" +FlateStream::FlateStream(Stream *strA, int predictor, int columns, int colors, int bits) : + FilterStream(strA) +{ + if (predictor != 1) { + pred = new StreamPredictor(this, predictor, columns, colors, bits); + } else { + pred = NULL; + } + out_pos = 0; + memset(&d_stream, 0, sizeof(d_stream)); +} + +FlateStream::~FlateStream() { + inflateEnd(&d_stream); + delete str; +} + +void FlateStream::reset() { + //FIXME: what are the semantics of reset? + //i.e. how much intialization has to happen in the constructor? + str->reset(); + memset(&d_stream, 0, sizeof(d_stream)); + inflateInit(&d_stream); + d_stream.avail_in = 0; + status = Z_OK; + out_pos = 0; + out_buf_len = 0; +} + +int FlateStream::getRawChar() { + if (fill_buffer()) + return EOF; + + return out_buf[out_pos++]; +} + +int FlateStream::getChar() { + if (pred) + return pred->getChar(); + else + return getRawChar(); +} + +int FlateStream::lookChar() { + if (pred) + return pred->lookChar(); + + if (fill_buffer()) + return EOF; + + return out_buf[out_pos]; +} + +int FlateStream::fill_buffer() { + if (out_pos >= out_buf_len) { + if (status == Z_STREAM_END) { + return -1; + } + d_stream.avail_out = sizeof(out_buf); + d_stream.next_out = out_buf; + out_pos = 0; + /* buffer is empty so we need to fill it */ + if (d_stream.avail_in == 0) { + int c; + /* read from the source stream */ + while (d_stream.avail_in < sizeof(in_buf) && (c = str->getChar()) != EOF) { + in_buf[d_stream.avail_in++] = c; + } + d_stream.next_in = in_buf; + } + while (d_stream.avail_out && d_stream.avail_in && (status == Z_OK || status == Z_BUF_ERROR)) { + status = inflate(&d_stream, Z_SYNC_FLUSH); + } + out_buf_len = sizeof(out_buf) - d_stream.avail_out; + if (status != Z_OK && status != Z_STREAM_END) + return -1; + if (!out_buf_len) + return -1; + } + + return 0; +} + +GString *FlateStream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 3 || pred) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("<< >> /FlateDecode filter\n"); + return s; +} + +GBool FlateStream::isBinary(GBool /*last*/) { + return str->isBinary(gTrue); +} diff --git a/xpdf/xpdf/FlateStream.h b/xpdf/xpdf/FlateStream.h new file mode 100644 index 000000000..6f00b5b14 --- /dev/null +++ b/xpdf/xpdf/FlateStream.h @@ -0,0 +1,67 @@ +//======================================================================== +// +// FlateStream.h +// +// Copyright (C) 2005, Jeff Muizelaar +// +//======================================================================== + +#ifndef FLATESTREAM_H +#define FLATESTREAM_H +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#ifndef WIN32 +#include +#endif +#include +#include +#include "goo/gmem.h" +#include "goo/gfile.h" +#include "Error.h" +#include "Object.h" +#ifndef NO_DECRYPTION +#include "Decrypt.h" +#endif +#include "Stream.h" + +extern "C" { +#include +} + +class FlateStream: public FilterStream { +public: + + FlateStream(Stream *strA, int predictor, int columns, int colors, int bits); + virtual ~FlateStream(); + virtual StreamKind getKind() { return strFlate; } + virtual void reset(); + virtual int getChar(); + virtual int lookChar(); + virtual int getRawChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + int fill_buffer(void); + z_stream d_stream; + StreamPredictor *pred; + int status; + unsigned char in_buf[4096]; + unsigned char out_buf[4096]; + int out_pos; + int out_buf_len; +}; + +#endif diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am index 936711014..b71cf7612 100644 --- a/xpdf/xpdf/Makefile.am +++ b/xpdf/xpdf/Makefile.am @@ -4,7 +4,7 @@ libxpdf_la_LDFLAGS = $(all_libraries) libxpdf_la_LIBADD = $(LIB_X11) $(LIBFREETYPE_LIBS) $(LIBPAPER_LIBS) $(XFT_LIBS) $(LIBJPEG_LIBS) ../goo/libgoo.la ../fofi/libfofi.la ../splash/libsplash.la libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ Catalog.cc CharCodeToUnicode.cc CMap.cc Decrypt.cc Dict.cc DCTStream.cc \ - FontEncodingTables.cc Function.cc Gfx.cc \ + FontEncodingTables.cc FlateStream.cc Function.cc Gfx.cc \ GfxFont.cc GfxState.cc GlobalParams.cc JArithmeticDecoder.cc \ JBIG2Stream.cc Lexer.cc Link.cc NameToCharCode.cc Object.cc Outline.cc \ OutputDev.cc PDFDoc.cc PDFDocEncoding.cc PSTokenizer.cc \ diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc index 249e4282e..ba2552047 100644 --- a/xpdf/xpdf/Stream.cc +++ b/xpdf/xpdf/Stream.cc @@ -33,6 +33,7 @@ #include "JPXStream.h" #include "Stream-CCITT.h" #include "DCTStream.h" +#include "FlateStream.h" #ifdef __DJGPP__ static GBool setDJSYSFLAGS = gFalse; @@ -3178,7 +3179,7 @@ GString *DCTStream::getPSFilter(int psLevel, const char *indent) { GBool DCTStream::isBinary(GBool /*last*/) { return str->isBinary(gTrue); } -#endif + //------------------------------------------------------------------------ // FlateStream //------------------------------------------------------------------------ @@ -3709,6 +3710,7 @@ int FlateStream::getCodeWord(int bits) { codeSize -= bits; return c; } +#endif //------------------------------------------------------------------------ // EOFStream diff --git a/xpdf/xpdf/Stream.h b/xpdf/xpdf/Stream.h index bc1e077c8..cca65c65c 100644 --- a/xpdf/xpdf/Stream.h +++ b/xpdf/xpdf/Stream.h @@ -637,7 +637,6 @@ private: int readMarker(); int read16(); }; -#endif //------------------------------------------------------------------------ // FlateStream @@ -713,6 +712,7 @@ private: int getHuffmanCodeWord(FlateHuffmanTab *tab); int getCodeWord(int bits); }; +#endif //------------------------------------------------------------------------ // EOFStream From f51205f3c52b5bb85c1c0cb550090fee229ad42c Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 17 May 2005 20:24:37 +0000 Subject: [PATCH 066/245] Call m_text->endPage() on KPDFOutputDev::endPage() when generating text Fixes bug 105630 BUGS: 105630 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=415187 --- core/generator_pdf/gp_outputdev.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/generator_pdf/gp_outputdev.cpp b/core/generator_pdf/gp_outputdev.cpp index 38d8e904c..88ccd07d3 100644 --- a/core/generator_pdf/gp_outputdev.cpp +++ b/core/generator_pdf/gp_outputdev.cpp @@ -112,7 +112,10 @@ void KPDFOutputDev::endPage() { SplashOutputDev::endPage(); if ( m_generateText ) + { + m_text->endPage(); m_text->coalesce( gTrue ); + } int bh = getBitmap()->getHeight(), bw = getBitmap()->getWidth(); From 44772a5c843f12bd5b4c890b514772b7a33a5ce8 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 21 May 2005 20:44:48 +0000 Subject: [PATCH 067/245] Fix problem introduced by improper merging of the libjpeg patch BUG: 106057 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=416536 --- xpdf/xpdf/DCTStream.cc | 2 +- xpdf/xpdf/DCTStream.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xpdf/xpdf/DCTStream.cc b/xpdf/xpdf/DCTStream.cc index 936ff63bd..868065114 100644 --- a/xpdf/xpdf/DCTStream.cc +++ b/xpdf/xpdf/DCTStream.cc @@ -92,7 +92,7 @@ int DCTStream::lookChar() { return c; } -GString *DCTStream::getPSFilter(int psLevel, char *indent) { +GString *DCTStream::getPSFilter(int psLevel, const char *indent) { GString *s; if (psLevel < 2) { diff --git a/xpdf/xpdf/DCTStream.h b/xpdf/xpdf/DCTStream.h index ed7537b35..064e690ef 100644 --- a/xpdf/xpdf/DCTStream.h +++ b/xpdf/xpdf/DCTStream.h @@ -56,7 +56,7 @@ public: virtual void reset(); virtual int getChar(); virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); Stream *getRawStream() { return str; } From eaa3fdf2def294e44f9e7a4976cc0b1473cfc871 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 22 May 2005 10:05:19 +0000 Subject: [PATCH 068/245] fix inheritance for zlib too svn path=/trunk/KDE/kdegraphics/kpdf/; revision=416697 --- xpdf/xpdf/FlateStream.cc | 2 +- xpdf/xpdf/FlateStream.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xpdf/xpdf/FlateStream.cc b/xpdf/xpdf/FlateStream.cc index cfdd6fdd6..0e6b06e9b 100644 --- a/xpdf/xpdf/FlateStream.cc +++ b/xpdf/xpdf/FlateStream.cc @@ -89,7 +89,7 @@ int FlateStream::fill_buffer() { return 0; } -GString *FlateStream::getPSFilter(int psLevel, char *indent) { +GString *FlateStream::getPSFilter(int psLevel, const char *indent) { GString *s; if (psLevel < 3 || pred) { diff --git a/xpdf/xpdf/FlateStream.h b/xpdf/xpdf/FlateStream.h index 6f00b5b14..357f5714e 100644 --- a/xpdf/xpdf/FlateStream.h +++ b/xpdf/xpdf/FlateStream.h @@ -50,7 +50,7 @@ public: virtual int getChar(); virtual int lookChar(); virtual int getRawChar(); - virtual GString *getPSFilter(int psLevel, char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); private: From 5fd54ac100fb2838c7788f0289e8490f9a40256a Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 23 May 2005 17:02:26 +0000 Subject: [PATCH 069/245] use kde's check for libjpeg, thanks Lauri for telling mine sucked :-D svn path=/trunk/KDE/kdegraphics/kpdf/; revision=417432 --- configure.in.in | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/configure.in.in b/configure.in.in index ced9fc038..9aec65c15 100644 --- a/configure.in.in +++ b/configure.in.in @@ -53,20 +53,6 @@ if test -z "$XFT_LIBS"; then DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" fi -dnl ##### Check for libjpeg -AC_CHECK_LIB([jpeg], [jpeg_destroy_decompress],HAVE_LIBJPEG=yes,HAVE_LIBJPEG=no) -if test "$HAVE_LIBJPEG" = "yes"; then - AC_CHECK_HEADERS([jpeglib.h],,HAVE_LIBJPEG=no) -fi - -if test "$HAVE_LIBJPEG" = "yes"; then - LIBJPEG_LIBS="-ljpeg" - AC_SUBST(LIBJPEG_LIBS) -else - DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" -fi - - dnl ##### Check for libpaper (Debian). LIBPAPER_LIBS= KDE_CHECK_HEADER(paper.h, [ From 4bca6a614667655fa0c28a341617a6d5a47ece50 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 25 May 2005 07:57:46 +0000 Subject: [PATCH 070/245] fix usage of kde standard jpeg check BUG: 106252 Oh, and btw i'm not called 'aacid', it's just my username. svn path=/trunk/KDE/kdegraphics/kpdf/; revision=417981 --- xpdf/xpdf/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am index b71cf7612..1271b746f 100644 --- a/xpdf/xpdf/Makefile.am +++ b/xpdf/xpdf/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../fofi -I$(srcdir)/../splash -I$(srcdir)/../goo $(all_includes) $(LIBFREETYPE_CFLAGS) $(XFT_CFLAGS) $(X_INCLUDES) $(QT_INCLUDES) libxpdf_la_LDFLAGS = $(all_libraries) -libxpdf_la_LIBADD = $(LIB_X11) $(LIBFREETYPE_LIBS) $(LIBPAPER_LIBS) $(XFT_LIBS) $(LIBJPEG_LIBS) ../goo/libgoo.la ../fofi/libfofi.la ../splash/libsplash.la +libxpdf_la_LIBADD = $(LIB_X11) $(LIBFREETYPE_LIBS) $(LIBPAPER_LIBS) $(XFT_LIBS) $(LIBJPEG) ../goo/libgoo.la ../fofi/libfofi.la ../splash/libsplash.la libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ Catalog.cc CharCodeToUnicode.cc CMap.cc Decrypt.cc Dict.cc DCTStream.cc \ FontEncodingTables.cc FlateStream.cc Function.cc Gfx.cc \ From be052853fa3e6c21f5c3b9c453584fb23e651047 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 28 May 2005 11:55:47 +0000 Subject: [PATCH 071/245] Fix usability problem with toc. Thanks for the patch BUGS: 106323 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=419033 --- ui/toc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/toc.cpp b/ui/toc.cpp index e2ea86bde..bcebe78c5 100644 --- a/ui/toc.cpp +++ b/ui/toc.cpp @@ -62,6 +62,7 @@ TOC::TOC(QWidget *parent, KPDFDocument *document) : KListView(parent), m_documen setSorting(-1); setRootIsDecorated(true); setResizeMode(AllColumns); + setAllColumnsShowFocus(true); connect(this, SIGNAL(executed(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *))); } From 888b0c05a9c77c979fccd44943e5d865263067d3 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 31 May 2005 19:23:52 +0000 Subject: [PATCH 072/245] link, crashes on startup and has some commented things i need to port later on svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=420319 --- conf/dlgaccessibility.ui | 6 -- conf/dlggeneral.ui | 2 +- conf/dlgperformance.ui | 2 +- core/Makefile.am | 4 +- core/document.cpp | 101 ++++++++++---------- core/document.h | 10 +- core/generator.h | 4 +- core/generator_pdf/generator_pdf.cpp | 29 +++--- core/generator_pdf/generator_pdf.h | 7 +- core/generator_pdf/gp_outputdev.cpp | 6 +- core/generator_pdf/gp_outputdev.h | 6 +- core/observer.h | 4 +- core/page.cpp | 17 ++-- core/page.h | 10 +- part.cpp | 24 ++--- part.h | 4 +- ui/minibar.cpp | 19 ++-- ui/minibar.h | 2 +- ui/pagepainter.cpp | 6 +- ui/pageview.cpp | 134 ++++++++++++++------------- ui/pageview.h | 8 +- ui/pageviewutils.cpp | 5 +- ui/presentationwidget.cpp | 43 +++++---- ui/presentationwidget.h | 8 +- ui/propertiesdialog.cpp | 2 +- ui/thumbnaillist.cpp | 45 ++++----- ui/thumbnaillist.h | 18 ++-- ui/toc.cpp | 8 +- ui/toc.h | 4 +- xpdf/xpdf/GlobalParams.cc | 4 +- 30 files changed, 280 insertions(+), 262 deletions(-) diff --git a/conf/dlgaccessibility.ui b/conf/dlgaccessibility.ui index a9f6495dd..ec86fdb35 100644 --- a/conf/dlgaccessibility.ui +++ b/conf/dlgaccessibility.ui @@ -101,12 +101,6 @@ 0 - - NoFrame - - - 0 - diff --git a/conf/dlggeneral.ui b/conf/dlggeneral.ui index be381b593..89278e9ec 100644 --- a/conf/dlggeneral.ui +++ b/conf/dlggeneral.ui @@ -160,7 +160,7 @@ kdialog.h - kiconloader.h + kiconloader.h dlggeneral.ui.h diff --git a/conf/dlgperformance.ui b/conf/dlgperformance.ui index 3ebb055b6..b1d0641ef 100644 --- a/conf/dlgperformance.ui +++ b/conf/dlgperformance.ui @@ -262,7 +262,7 @@ kdialog.h - kiconloader.h + kiconloader.h dlgperformance.ui.h diff --git a/core/Makefile.am b/core/Makefile.am index 74c774855..c49b58eec 100644 --- a/core/Makefile.am +++ b/core/Makefile.am @@ -1,10 +1,10 @@ -SUBDIRS = generator_pdf generator_kimgio +SUBDIRS = generator_pdf # generator_kimgio INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(srcdir)/../xpdf -I$(srcdir)/../xpdf/goo -I$(top_builddir)/kpdf $(all_includes) METASOURCES = AUTO -libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la ./generator_kimgio/libgeneratorkimgio.la +libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la # ./generator_kimgio/libgeneratorkimgio.la libkpdfcore_la_SOURCES = document.cpp link.cpp page.cpp pagetransition.cpp noinst_LTLIBRARIES = libkpdfcore.la diff --git a/core/document.cpp b/core/document.cpp index 5d5a4e5cd..ea754f296 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -34,7 +34,7 @@ #include "page.h" #include "link.h" #include "generator_pdf/generator_pdf.h" // PDF generator -#include "generator_kimgio/generator_kimgio.h" // KIMGIO generator +//#include "generator_kimgio/generator_kimgio.h" // KIMGIO generator #include "conf/settings.h" // structures used internally by KPDFDocument for local variables storage @@ -58,14 +58,14 @@ class KPDFDocumentPrivate QStringList kimgioMimes; // viewport stuff - QValueList< DocumentViewport > viewportHistory; - QValueList< DocumentViewport >::iterator viewportIterator; + QList< DocumentViewport > viewportHistory; + QList< DocumentViewport >::iterator viewportIterator; DocumentViewport nextDocumentViewport; // see KPDFLink::Goto for an explanation // observers / requests / allocator stuff QMap< int, DocumentObserver * > observers; - QValueList< PixmapRequest * > pixmapRequestsStack; - QValueList< AllocatedPixmap * > allocatedPixmapsFifo; + QList< PixmapRequest * > pixmapRequestsStack; + QList< AllocatedPixmap * > allocatedPixmapsFifo; int allocatedPixmapsTotalMemory; // timers (memory checking / info saver) @@ -88,7 +88,7 @@ struct RunningSearch // store search properties int continueOnPage; NormalizedRect continueOnMatch; - QValueList< int > highlightedPages; + QList< int > highlightedPages; // fields related to previous searches (used for 'continueSearch') QString cachedString; @@ -112,14 +112,15 @@ KPDFDocument::KPDFDocument() d->allocatedPixmapsTotalMemory = 0; d->memCheckTimer = 0; d->saveBookmarksTimer = 0; - KImageIO::registerFormats(); +#warning kimgio generator disabled ATM +/* KImageIO::registerFormats(); QStringList list = QImage::inputFormatList(); QStringList::Iterator it = list.begin(); while( it != list.end() ) { d->kimgioMimes << KMimeType::findByPath(QString("foo.%1").arg(*it), 0, true)->name(); ++it; - } + }*/ } KPDFDocument::~KPDFDocument() @@ -155,7 +156,7 @@ bool KPDFDocument::openDocument( const QString & docFile, const KURL & url ) generator = new PDFGenerator( this ); // else if ( mimeName == "application/postscript" ) // kdError() << "PS generator not available" << endl; - else +/* else { QStringList::Iterator it = d->kimgioMimes.begin(); while( it != d->kimgioMimes.end() ) @@ -173,10 +174,10 @@ bool KPDFDocument::openDocument( const QString & docFile, const KURL & url ) kdWarning() << "Unknown mimetype '" << mime->name() << "'." << endl; return false; } - } + }*/ // 1. load Document (and set busy cursor while loading) - QApplication::setOverrideCursor( waitCursor ); + QApplication::setOverrideCursor( Qt::waitCursor ); bool openOk = generator->loadDocument( docFile, pages_vector ); QApplication::restoreOverrideCursor(); if ( !openOk || pages_vector.size() <= 0 ) @@ -244,25 +245,25 @@ void KPDFDocument::closeDocument() d->url = KURL(); // remove requests left in queue - QValueList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(); - QValueList< PixmapRequest * >::iterator sEnd = d->pixmapRequestsStack.end(); + QList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(); + QList< PixmapRequest * >::iterator sEnd = d->pixmapRequestsStack.end(); for ( ; sIt != sEnd; ++sIt ) delete *sIt; d->pixmapRequestsStack.clear(); // send an empty list to observers (to free their data) - foreachObserver( notifySetup( QValueVector< KPDFPage * >(), true ) ); + foreachObserver( notifySetup( QVector< KPDFPage * >(), true ) ); // delete pages and clear 'pages_vector' container - QValueVector< KPDFPage * >::iterator pIt = pages_vector.begin(); - QValueVector< KPDFPage * >::iterator pEnd = pages_vector.end(); + QVector< KPDFPage * >::iterator pIt = pages_vector.begin(); + QVector< KPDFPage * >::iterator pEnd = pages_vector.end(); for ( ; pIt != pEnd; ++pIt ) delete *pIt; pages_vector.clear(); // clear 'memory allocation' descriptors - QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); - QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + QList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); for ( ; aIt != aEnd; ++aIt ) delete *aIt; d->allocatedPixmapsFifo.clear(); @@ -302,13 +303,13 @@ void KPDFDocument::removeObserver( DocumentObserver * pObserver ) { // free observer's pixmap data int observerId = pObserver->observerId(); - QValueVector::iterator it = pages_vector.begin(), end = pages_vector.end(); + QVector::iterator it = pages_vector.begin(), end = pages_vector.end(); for ( ; it != end; ++it ) (*it)->deletePixmap( observerId ); // [MEM] free observer's allocation descriptors - QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); - QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + QList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); while ( aIt != aEnd ) { AllocatedPixmap * p = *aIt; @@ -332,13 +333,13 @@ void KPDFDocument::reparseConfig() if ( generator && generator->reparseConfig() ) { // invalidate pixmaps - QValueVector::iterator it = pages_vector.begin(), end = pages_vector.end(); + QVector::iterator it = pages_vector.begin(), end = pages_vector.end(); for ( ; it != end; ++it ) (*it)->deletePixmapsAndRects(); // [MEM] remove allocation descriptors - QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); - QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + QList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); for ( ; aIt != aEnd; ++aIt ) delete *aIt; d->allocatedPixmapsFifo.clear(); @@ -370,7 +371,7 @@ const DocumentSynopsis * KPDFDocument::documentSynopsis() const return generator ? generator->generateDocumentSynopsis() : NULL; } -const KPDFPage * KPDFDocument::page( uint n ) const +const KPDFPage * KPDFDocument::page( int n ) const { return ( n < pages_vector.count() ) ? pages_vector[n] : 0; } @@ -430,12 +431,12 @@ void KPDFDocument::putFontInfo(KListView *list) if (generator) generator->putFontInfo(list); } -void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & requests ) +void KPDFDocument::requestPixmaps( const QList< PixmapRequest * > & requests ) { if ( !generator ) { // delete requests.. - QValueList< PixmapRequest * >::const_iterator rIt = requests.begin(), rEnd = requests.end(); + QList< PixmapRequest * >::const_iterator rIt = requests.begin(), rEnd = requests.end(); for ( ; rIt != rEnd; ++rIt ) delete *rIt; // ..and return @@ -444,7 +445,7 @@ void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & request // 1. [CLEAN STACK] remove previous requests of requesterID int requesterID = requests.first()->id; - QValueList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(), sEnd = d->pixmapRequestsStack.end(); + QList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(), sEnd = d->pixmapRequestsStack.end(); while ( sIt != sEnd ) { if ( (*sIt)->id == requesterID ) @@ -459,7 +460,7 @@ void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & request // 2. [ADD TO STACK] add requests to stack bool threadingDisabled = !Settings::enableThreading(); - QValueList< PixmapRequest * >::const_iterator rIt = requests.begin(), rEnd = requests.end(); + QList< PixmapRequest * >::const_iterator rIt = requests.begin(), rEnd = requests.end(); for ( ; rIt != rEnd; ++rIt ) { // set the 'page field' (see PixmapRequest) and check if it is valid @@ -559,7 +560,7 @@ void KPDFDocument::setViewport( const DocumentViewport & viewport, int excludeId d->viewportHistory.pop_front(); // add the item at the end of the queue - d->viewportIterator = d->viewportHistory.append( viewport ); + d->viewportIterator = d->viewportHistory.insert( d->viewportHistory.end(), viewport ); } // notify change to all other (different from id) observers @@ -572,9 +573,9 @@ void KPDFDocument::setViewport( const DocumentViewport & viewport, int excludeId if ( d->allocatedPixmapsFifo.count() > 1 ) { const int page = viewport.pageNumber; - QValueList< AllocatedPixmap * > viewportPixmaps; - QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); - QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + QList< AllocatedPixmap * > viewportPixmaps; + QList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); while ( aIt != aEnd ) { if ( (*aIt)->page == page ) @@ -604,7 +605,7 @@ void KPDFDocument::setPrevViewport() void KPDFDocument::setNextViewport() // restore next viewport from the history { - QValueList< DocumentViewport >::iterator nextIterator = d->viewportIterator; + QList< DocumentViewport >::iterator nextIterator = d->viewportIterator; ++nextIterator; if ( nextIterator != d->viewportHistory.end() ) { @@ -642,23 +643,23 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar // global data for search bool foundAMatch = false; - QValueList< int > pagesToNotify; + QList< int > pagesToNotify; // remove highlights from pages and queue them for notifying changes pagesToNotify += s->highlightedPages; - QValueList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end(); + QList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end(); for ( ; it != end; ++it ) pages_vector[ *it ]->deleteHighlights( searchID ); s->highlightedPages.clear(); // set hourglass cursor - QApplication::setOverrideCursor( waitCursor ); + QApplication::setOverrideCursor( Qt::waitCursor ); // 1. ALLDOC - proces all document marking pages if ( type == AllDoc ) { // search and highlight text on all pages - QValueVector< KPDFPage * >::iterator it = pages_vector.begin(), end = pages_vector.end(); + QVector< KPDFPage * >::iterator it = pages_vector.begin(), end = pages_vector.end(); for ( ; it != end; ++it ) { // get page (from the first to the last) @@ -794,7 +795,7 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar hueStep = (wordsCount > 1) ? (60 / (wordsCount - 1)) : 60, baseHue, baseSat, baseVal; color.getHsv( &baseHue, &baseSat, &baseVal ); - QValueVector< KPDFPage * >::iterator it = pages_vector.begin(), end = pages_vector.end(); + QVector< KPDFPage * >::iterator it = pages_vector.begin(), end = pages_vector.end(); for ( ; it != end; ++it ) { // get page (from the first to the last) @@ -858,7 +859,7 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar } // notify observers about highlights changes - QValueList< int >::iterator nIt = pagesToNotify.begin(), nEnd = pagesToNotify.end(); + QList< int >::iterator nIt = pagesToNotify.begin(), nEnd = pagesToNotify.end(); for ( ; nIt != nEnd; ++nIt ) foreachObserver( notifyPageChanged( *nIt, DocumentObserver::Highlights ) ); @@ -889,7 +890,7 @@ void KPDFDocument::resetSearch( int searchID ) RunningSearch * s = d->searches[ searchID ]; // unhighlight pages and inform observers about that - QValueList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end(); + QList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end(); for ( ; it != end; ++it ) { int pageNumber = *it; @@ -1081,8 +1082,8 @@ void KPDFDocument::requestDone( PixmapRequest * req ) #endif // [MEM] 1.1 find and remove a previous entry for the same page and id - QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); - QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + QList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); for ( ; aIt != aEnd; ++aIt ) if ( (*aIt)->page == req->pageNumber && (*aIt)->id == req->id ) { @@ -1167,8 +1168,8 @@ void KPDFDocument::cleanupPixmapMemory( int /*sure? bytesOffset*/ ) { // [MEM] free memory starting from older pixmaps int pagesFreed = 0; - QValueList< AllocatedPixmap * >::iterator pIt = d->allocatedPixmapsFifo.begin(); - QValueList< AllocatedPixmap * >::iterator pEnd = d->allocatedPixmapsFifo.end(); + QList< AllocatedPixmap * >::iterator pIt = d->allocatedPixmapsFifo.begin(); + QList< AllocatedPixmap * >::iterator pEnd = d->allocatedPixmapsFifo.end(); while ( (pIt != pEnd) && (memoryToFree > 0) ) { AllocatedPixmap * p = *pIt; @@ -1323,14 +1324,14 @@ void KPDFDocument::loadDocumentInfo() if ( historyElement.hasAttribute( "viewport" ) ) { QString vpString = historyElement.attribute( "viewport" ); - d->viewportIterator = d->viewportHistory.append( + d->viewportIterator = d->viewportHistory.insert( d->viewportHistory.end(), DocumentViewport( vpString ) ); } historyNode = historyNode.nextSibling(); } // consistancy check if ( d->viewportHistory.isEmpty() ) - d->viewportIterator = d->viewportHistory.append( DocumentViewport() ); + d->viewportIterator = d->viewportHistory.insert( d->viewportHistory.end(), DocumentViewport() ); } infoNode = infoNode.nextSibling(); } @@ -1393,7 +1394,7 @@ void KPDFDocument::saveDocumentInfo() const root.appendChild( generalInfo ); // ... saves history up to 10 viewports - QValueList< DocumentViewport >::iterator backIterator = d->viewportIterator; + QList< DocumentViewport >::iterator backIterator = d->viewportIterator; if ( backIterator != d->viewportHistory.end() ) { // go back up to 10 steps from the current viewportIterator @@ -1406,7 +1407,7 @@ void KPDFDocument::saveDocumentInfo() const generalInfo.appendChild( historyNode ); // add old[backIterator] and present[viewportIterator] items - QValueList< DocumentViewport >::iterator endIt = d->viewportIterator; + QList< DocumentViewport >::iterator endIt = d->viewportIterator; ++endIt; while ( backIterator != endIt ) { diff --git a/core/document.h b/core/document.h index 5feebf38a..9b847a3a1 100644 --- a/core/document.h +++ b/core/document.h @@ -12,10 +12,12 @@ #define _KPDF_DOCUMENT_H_ #include -#include +#include #include #include +class QColor; + class KPDFPage; class KPDFLink; class DocumentObserver; @@ -68,7 +70,7 @@ class KPDFDocument : public QObject bool isOpened() const; const DocumentInfo * documentInfo() const; const DocumentSynopsis * documentSynopsis() const; - const KPDFPage * page( uint page ) const; + const KPDFPage * page( int page ) const; const DocumentViewport & viewport() const; uint currentPage() const; uint pages() const; @@ -86,7 +88,7 @@ class KPDFDocument : public QObject void setViewport( const DocumentViewport & viewport, int excludeId = -1, bool smoothMove = false ); void setPrevViewport(); void setNextViewport(); - void requestPixmaps( const QValueList< PixmapRequest * > & requests ); + void requestPixmaps( const QList< PixmapRequest * > & requests ); void requestTextPage( uint page ); enum SearchType { NextMatch, PrevMatch, AllDoc, GoogleAll, GoogleAny }; @@ -118,7 +120,7 @@ class KPDFDocument : public QObject bool openRelativeFile( const QString & fileName ); Generator * generator; - QValueVector< KPDFPage * > pages_vector; + QVector< KPDFPage * > pages_vector; class KPDFDocumentPrivate * d; private slots: diff --git a/core/generator.h b/core/generator.h index 39d272d96..d0a5af779 100644 --- a/core/generator.h +++ b/core/generator.h @@ -11,7 +11,7 @@ #define _KPDF_GENERATOR_H_ #include -#include +#include #include #include "core/document.h" class KListView; @@ -45,7 +45,7 @@ class Generator : public QObject public: /** virtual methods to reimplement **/ // load a document and fill up the pagesVector - virtual bool loadDocument( const QString & fileName, QValueVector< KPDFPage * > & pagesVector ) = 0; + virtual bool loadDocument( const QString & fileName, QVector< KPDFPage * > & pagesVector ) = 0; // Document description and Table of contents virtual const DocumentInfo * generateDocumentInfo() { return 0L; } diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 1497d71a6..654cf77d9 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -92,7 +92,7 @@ PDFGenerator::~PDFGenerator() //BEGIN Generator inherited functions -bool PDFGenerator::loadDocument( const QString & filePath, QValueVector & pagesVector ) +bool PDFGenerator::loadDocument( const QString & filePath, QVector & pagesVector ) { #ifndef NDEBUG if ( pdfdoc ) @@ -110,7 +110,7 @@ bool PDFGenerator::loadDocument( const QString & filePath, QValueVectorisOk() && pdfdoc->getErrorCode() == errEncrypted ) { - QCString password; + Q3CString password; // 1.A. try to retrieve the first password from the kde wallet system if ( !triedWallet ) @@ -421,7 +421,7 @@ bool PDFGenerator::print( KPrinter& printer ) dummy.setFullPage(true); dummy.setPageSize((QPrinter::PageSize)(ps.isEmpty() ? KGlobal::locale()->pageSize() : pageNameToPageSize(ps))); - QPaintDeviceMetrics metrics(&dummy); + Q3PaintDeviceMetrics metrics(&dummy); globalParams->setPSPaperWidth(metrics.width()); globalParams->setPSPaperHeight(metrics.height()); } @@ -435,8 +435,8 @@ bool PDFGenerator::print( KPrinter& printer ) if (!printer.previewOnly()) { - QValueList pageList = printer.pageList(); - QValueList::const_iterator it; + QList pageList = printer.pageList(); + QList::const_iterator it; for(it = pageList.begin(); it != pageList.end(); ++it) pages.push_back(*it); } @@ -452,7 +452,8 @@ bool PDFGenerator::print( KPrinter& printer ) // needs to be here so that the file is flushed, do not merge with the one // in the else delete psOut; - printer.printFiles(tf.name(), true); +#warning K/QPrinter changed + //printer.printFiles(tf.name(), true); return true; } else @@ -893,7 +894,7 @@ void PDFGenerator::addTransition( int pageNumber, KPDFPage * page ) } - +/* void PDFGenerator::customEvent( QCustomEvent * event ) { // catch generator 'ready events' only @@ -905,7 +906,7 @@ void PDFGenerator::customEvent( QCustomEvent * event ) if ( generatorThread->running() ) { // if so, wait for effective thread termination - if ( !generatorThread->wait( 9999 /*10s timeout*/ ) ) + if ( !generatorThread->wait( 9999 /*10s timeout*/ /*) ) { kdWarning() << "PDFGenerator: thread sent 'data available' " << "signal but had problems ending." << endl; @@ -928,7 +929,7 @@ void PDFGenerator::customEvent( QCustomEvent * event ) PixmapRequest * request = static_cast< PixmapRequest * >( event->data() ); QImage * outImage = generatorThread->takeImage(); TextPage * outTextPage = generatorThread->takeTextPage(); - QValueList< ObjectRect * > outRects = generatorThread->takeObjectRects(); + QList< ObjectRect * > outRects = generatorThread->takeObjectRects(); request->page->setPixmap( request->id, new QPixmap( *outImage ) ); delete outImage; @@ -944,7 +945,7 @@ void PDFGenerator::customEvent( QCustomEvent * event ) ready = true; // notify the new generation signalRequestDone( request ); -} +}*/ @@ -959,7 +960,7 @@ struct PPGThreadPrivate // internal temp stored items. don't delete this. QImage * m_image; TextPage * m_textPage; - QValueList< ObjectRect * > m_rects; + QList< ObjectRect * > m_rects; bool m_rectsTaken; }; @@ -981,7 +982,7 @@ PDFPixmapGeneratorThread::~PDFPixmapGeneratorThread() delete d->m_textPage; if ( !d->m_rectsTaken && d->m_rects.count() ) { - QValueList< ObjectRect * >::iterator it = d->m_rects.begin(), end = d->m_rects.end(); + QList< ObjectRect * >::iterator it = d->m_rects.begin(), end = d->m_rects.end(); for ( ; it != end; ++it ) delete *it; } @@ -1045,7 +1046,7 @@ TextPage * PDFPixmapGeneratorThread::takeTextPage() const return tp; } -QValueList< ObjectRect * > PDFPixmapGeneratorThread::takeObjectRects() const +QList< ObjectRect * > PDFPixmapGeneratorThread::takeObjectRects() const { d->m_rectsTaken = true; return d->m_rects; diff --git a/core/generator_pdf/generator_pdf.h b/core/generator_pdf/generator_pdf.h index 9459231c8..e5be98f54 100644 --- a/core/generator_pdf/generator_pdf.h +++ b/core/generator_pdf/generator_pdf.h @@ -51,7 +51,7 @@ class PDFGenerator : public Generator virtual ~PDFGenerator(); // [INHERITED] load a document and fill up the pagesVector - bool loadDocument( const QString & fileName, QValueVector & pagesVector ); + bool loadDocument( const QString & fileName, QVector & pagesVector ); // [INHERITED] document informations const DocumentInfo * generateDocumentInfo(); @@ -96,7 +96,8 @@ class PDFGenerator : public Generator // private function for creating the transition information void addTransition( int pageNumber, KPDFPage * page ); // (async related) receive data from the generator thread - void customEvent( QCustomEvent * ); +#warning QCustomEvent is gone :-/ +// void customEvent( QCustomEvent * ); // xpdf dependant stuff QMutex docLock; @@ -135,7 +136,7 @@ class PDFPixmapGeneratorThread : public QThread // methods for getting contents from the GUI thread QImage * takeImage() const; TextPage * takeTextPage() const; - QValueList< ObjectRect * > takeObjectRects() const; + QList< ObjectRect * > takeObjectRects() const; private: // can't be called from the outside (but from startGeneration) diff --git a/core/generator_pdf/gp_outputdev.cpp b/core/generator_pdf/gp_outputdev.cpp index 88ccd07d3..9da6692a2 100644 --- a/core/generator_pdf/gp_outputdev.cpp +++ b/core/generator_pdf/gp_outputdev.cpp @@ -91,11 +91,11 @@ TextPage * KPDFOutputDev::takeTextPage() return text; } -QValueList< ObjectRect * > KPDFOutputDev::takeObjectRects() +QList< ObjectRect * > KPDFOutputDev::takeObjectRects() { if ( m_rects.isEmpty() ) return m_rects; - QValueList< ObjectRect * > rectsCopy( m_rects ); + QList< ObjectRect * > rectsCopy( m_rects ); m_rects.clear(); return rectsCopy; } @@ -247,7 +247,7 @@ void KPDFOutputDev::clear() // delete rects if ( m_rects.count() ) { - QValueList< ObjectRect * >::iterator it = m_rects.begin(), end = m_rects.end(); + QList< ObjectRect * >::iterator it = m_rects.begin(), end = m_rects.end(); for ( ; it != end; ++it ) delete *it; m_rects.clear(); diff --git a/core/generator_pdf/gp_outputdev.h b/core/generator_pdf/gp_outputdev.h index 0b176b325..738d60c5d 100644 --- a/core/generator_pdf/gp_outputdev.h +++ b/core/generator_pdf/gp_outputdev.h @@ -19,7 +19,7 @@ #pragma interface #endif -#include +#include #include "xpdf/PDFDoc.h" // for 'Object' #include "xpdf/SplashOutputDev.h" @@ -56,7 +56,7 @@ class KPDFOutputDev : public SplashOutputDev QPixmap * takePixmap(); QImage * takeImage(); TextPage * takeTextPage(); - QValueList< ObjectRect * > takeObjectRects(); + QList< ObjectRect * > takeObjectRects(); /** inherited from OutputDev */ // Start a page. @@ -95,7 +95,7 @@ class KPDFOutputDev : public SplashOutputDev QPixmap * m_pixmap; QImage * m_image; TextPage * m_text; // text page generated on demand - QValueList< ObjectRect * > m_rects; // objectRects (links/images) + QList< ObjectRect * > m_rects; // objectRects (links/images) }; diff --git a/core/observer.h b/core/observer.h index fabe4ff7d..39d54582d 100644 --- a/core/observer.h +++ b/core/observer.h @@ -11,7 +11,7 @@ #ifndef _KPDF_DOCUMENTOBSERVER_H_ #define _KPDF_DOCUMENTOBSERVER_H_ -#include +#include #include /** IDs for observers. Globally defined here. **/ @@ -45,7 +45,7 @@ class DocumentObserver // commands from the Document to all observers enum ChangedFlags { Pixmap = 1, Bookmark = 2, Highlights = 4 }; - virtual void notifySetup( const QValueVector< KPDFPage * > & /*pages*/, bool /*documentChanged*/ ) {}; + virtual void notifySetup( const QVector< KPDFPage * > & /*pages*/, bool /*documentChanged*/ ) {}; virtual void notifyViewportChanged( bool /*smoothMove*/ ) {}; virtual void notifyPageChanged( int /*pageNumber*/, int /*changedFlags*/ ) {}; virtual void notifyContentsCleared( int /*changedFlags*/ ) {}; diff --git a/core/page.cpp b/core/page.cpp index 4fe607888..8d0da0953 100644 --- a/core/page.cpp +++ b/core/page.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include // local includes @@ -73,7 +74,7 @@ bool KPDFPage::hasObjectRect( double x, double y ) const { if ( m_rects.count() < 1 ) return false; - QValueList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end(); + QList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end(); for ( ; it != end; ++it ) if ( (*it)->contains( x, y ) ) return true; @@ -89,7 +90,7 @@ bool KPDFPage::hasHighlights( int s_id ) const if ( s_id == -1 ) return true; // iterate on the highlights list to find an entry by id - QValueList< HighlightRect * >::const_iterator it = m_highlights.begin(), end = m_highlights.end(); + QList< HighlightRect * >::const_iterator it = m_highlights.begin(), end = m_highlights.end(); for ( ; it != end; ++it ) if ( (*it)->s_id == s_id ) return true; @@ -110,7 +111,7 @@ NormalizedRect * KPDFPage::findText( const QString & text, bool strictCase, Norm // create a xpf's Unicode (unsigned int) array for the given text const QChar * str = text.unicode(); int len = text.length(); - QMemArray u(len); + Q3MemArray u(len); for (int i = 0; i < len; ++i) u[i] = str[i].unicode(); @@ -175,7 +176,7 @@ const QString KPDFPage::getText( const NormalizedRect & rect ) const const ObjectRect * KPDFPage::hasObject( ObjectRect::ObjectType type, double x, double y ) const { - QValueList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end(); + QList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end(); for ( ; it != end; ++it ) if ( (*it)->contains( x, y ) ) if ((*it)->objectType() == type) return *it; @@ -206,9 +207,9 @@ void KPDFPage::setBookmark( bool state ) m_bookmarked = state; } -void KPDFPage::setObjectRects( const QValueList< ObjectRect * > rects ) +void KPDFPage::setObjectRects( const QList< ObjectRect * > rects ) { - QValueList< ObjectRect * >::iterator it = m_rects.begin(), end = m_rects.end(); + QList< ObjectRect * >::iterator it = m_rects.begin(), end = m_rects.end(); for ( ; it != end; ++it ) delete *it; m_rects = rects; @@ -254,7 +255,7 @@ void KPDFPage::deletePixmapsAndRects() delete *it; m_pixmaps.clear(); // delete ObjectRects - QValueList< ObjectRect * >::iterator rIt = m_rects.begin(), rEnd = m_rects.end(); + QList< ObjectRect * >::iterator rIt = m_rects.begin(), rEnd = m_rects.end(); for ( ; rIt != rEnd; ++rIt ) delete *rIt; m_rects.clear(); @@ -263,7 +264,7 @@ void KPDFPage::deletePixmapsAndRects() void KPDFPage::deleteHighlights( int s_id ) { // delete highlights by ID - QValueList< HighlightRect * >::iterator it = m_highlights.begin(), end = m_highlights.end(); + QList< HighlightRect * >::iterator it = m_highlights.begin(), end = m_highlights.end(); while ( it != end ) { HighlightRect * highlight = *it; diff --git a/core/page.h b/core/page.h index ebd6e5224..bd73f67a3 100644 --- a/core/page.h +++ b/core/page.h @@ -11,7 +11,7 @@ #define _KPDF_PAGE_H_ #include -#include +#include class QPixmap; class QRect; @@ -112,7 +112,7 @@ class KPDFPage void setPixmap( int p_id, QPixmap * pixmap ); void setSearchPage( TextPage * text ); void setBookmark( bool state ); - void setObjectRects( const QValueList< ObjectRect * > rects ); + void setObjectRects( const QList< ObjectRect * > rects ); void setHighlight( int s_id, NormalizedRect * &r, const QColor & color ); //void setAnnotation( Annotation * annotation ); void setTransition( KPDFPageTransition * transition ); @@ -128,9 +128,9 @@ class KPDFPage QMap< int, QPixmap * > m_pixmaps; TextPage * m_text; - QValueList< ObjectRect * > m_rects; - QValueList< HighlightRect * > m_highlights; - //QValueList< Annotation * > m_annotations; + QList< ObjectRect * > m_rects; + QList< HighlightRect * > m_highlights; + //QList< Annotation * > m_annotations; KPDFPageTransition * m_transition; }; diff --git a/part.cpp b/part.cpp index 728543a83..c3a739443 100644 --- a/part.cpp +++ b/part.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -141,7 +141,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, enableTOC( false ); // [left toolbox: Thumbnails and Bookmarks] | [] - QVBox * thumbsBox = new ThumbnailsBox( m_toolBox ); + Q3VBox * thumbsBox = new ThumbnailsBox( m_toolBox ); m_searchWidget = new SearchWidget( thumbsBox, m_document ); m_thumbnailList = new ThumbnailList( thumbsBox, m_document ); // ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList ); @@ -244,7 +244,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_pageView->setupActions( ac ); // apply configuration (both internal settings and GUI configured items) - QValueList splitterSizes = Settings::splitterSizes(); + QList splitterSizes = Settings::splitterSizes(); if ( !splitterSizes.count() ) { // the first time use 1/10 for the panel and 9/10 for the pageView @@ -620,8 +620,8 @@ void Part::slotNewConfig() m_searchWidget->setShown( showSearch ); // Main View (pageView) - QScrollView::ScrollBarMode scrollBarMode = Settings::showScrollBars() ? - QScrollView::AlwaysOn : QScrollView::AlwaysOff; + Q3ScrollView::ScrollBarMode scrollBarMode = Settings::showScrollBars() ? + Q3ScrollView::AlwaysOn : Q3ScrollView::AlwaysOff; if ( m_pageView->hScrollBarMode() != scrollBarMode ) { m_pageView->setHScrollBarMode( scrollBarMode ); @@ -682,8 +682,8 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) if (factory()) { - QPtrList clients(factory()->clients()); - QPtrListIterator clientsIt( clients ); + Q3PtrList clients(factory()->clients()); + Q3PtrListIterator clientsIt( clients ); for( ; (!m_showMenuBarAction || !m_showFullScreenAction) && clientsIt.current(); ++clientsIt) { client = clientsIt.current(); @@ -707,11 +707,11 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) { popup->insertTitle( i18n( "Page %1" ).arg( page->number() + 1 ) ); if ( page->hasBookmark() ) - popup->insertItem( SmallIcon("bookmark"), i18n("Remove Bookmark"), 1 ); + popup->insertItem( QIcon(SmallIcon("bookmark")), i18n("Remove Bookmark"), 1 ); else - popup->insertItem( SmallIcon("bookmark_add"), i18n("Add Bookmark"), 1 ); + popup->insertItem( QIcon(SmallIcon("bookmark_add")), i18n("Add Bookmark"), 1 ); if ( m_pageView->canFitPageWidth() ) - popup->insertItem( SmallIcon("viewmagfit"), i18n("Fit Width"), 2 ); + popup->insertItem( QIcon(SmallIcon("viewmagfit")), i18n("Fit Width"), 2 ); //popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 ); //popup->setItemEnabled( 3, false ); reallyShow = true; @@ -790,7 +790,9 @@ void Part::slotPrint() if (width > height) landscape++; else portrait++; } - if (landscape > portrait) printer.setOrientation(KPrinter::Landscape); +#warning whoever ported Kprinter messed, setOrientation is QPrinted::Orientation not Qt::Orientation +#warning change it +// if (landscape > portrait) printer.setOrientation(KPrinter::Landscape); if (printer.setup(widget())) doPrint( printer ); } diff --git a/part.h b/part.h index 74e221101..f5f6953a3 100644 --- a/part.h +++ b/part.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include "core/document.h" #include "core/observer.h" #include "dcop.h" @@ -128,7 +128,7 @@ private: SearchWidget *m_searchWidget; ThumbnailList *m_thumbnailList; PageView *m_pageView; - QGuardedPtr m_presentationWidget; + QPointer m_presentationWidget; // static instances counter static unsigned int m_count; diff --git a/ui/minibar.cpp b/ui/minibar.cpp index 3cf8a8a56..524784d9f 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -8,6 +8,7 @@ ***************************************************************************/ // qt / kde includes +#include #include #include #include @@ -131,7 +132,7 @@ MiniBar::MiniBar( QWidget * parent, KPDFDocument * document ) parent->hide(); } -void MiniBar::notifySetup( const QValueVector< KPDFPage * > & pageVector, bool changed ) +void MiniBar::notifySetup( const QVector< KPDFPage * > & pageVector, bool changed ) { // only process data when document changes if ( !changed ) @@ -257,7 +258,7 @@ void MiniBar::slotEmitPrevPage() /** ProgressWidget **/ ProgressWidget::ProgressWidget( MiniBar * parent ) - : QWidget( parent, "progress", WNoAutoErase ), + : QWidget( parent, "progress", Qt::WNoAutoErase ), m_miniBar( parent ), m_progressPercentage( -1 ) { setFixedHeight( 4 ); @@ -325,7 +326,8 @@ PagesEdit::PagesEdit( MiniBar * parent ) : QLineEdit( parent ), m_miniBar( parent ), m_eatClick( false ) { // customize look - setFrameShadow( QFrame::Raised ); +#warning setFrameShadow does not exists in Qt4 + //setFrameShadow( QFrame::Raised ); focusOutEvent( 0 ); // use an integer validator @@ -355,10 +357,11 @@ void PagesEdit::focusInEvent( QFocusEvent * e ) { // select all text selectAll(); - if ( e->reason() == QFocusEvent::Mouse ) + if ( e->reason() == Qt::MouseFocusReason ) m_eatClick = true; // change background color to the default 'edit' color - setLineWidth( 2 ); +#warning setLineWidth does not exists in Qt4 +// setLineWidth( 2 ); setPaletteBackgroundColor( Qt::white ); // call default handler QLineEdit::focusInEvent( e ); @@ -367,7 +370,8 @@ void PagesEdit::focusInEvent( QFocusEvent * e ) void PagesEdit::focusOutEvent( QFocusEvent * e ) { // change background color to a dark tone - setLineWidth( 1 ); +#warning setLineWidth does not exists in Qt4 +// setLineWidth( 1 ); setPaletteBackgroundColor( palette().active().background().light( 105 ) ); // restore text QLineEdit::setText( backString ); @@ -445,7 +449,8 @@ void HoverButton::paintEvent( QPaintEvent * e ) // custom drawing of unhovered button QPainter p( this ); setPaletteBackgroundColor( palette().active().background() ); - drawButtonLabel( &p ); +#warning drawButtonLabel does not exists in Qt4 +// drawButtonLabel( &p ); } } diff --git a/ui/minibar.h b/ui/minibar.h index afdc01c31..c92b330a3 100644 --- a/ui/minibar.h +++ b/ui/minibar.h @@ -29,7 +29,7 @@ class MiniBar : public QFrame, public DocumentObserver // [INHERITED] from DocumentObserver uint observerId() const { return MINIBAR_ID; } - void notifySetup( const QValueVector< KPDFPage * > & pages, bool ); + void notifySetup( const QVector< KPDFPage * > & pages, bool ); void notifyViewportChanged( bool smoothMove ); signals: diff --git a/ui/pagepainter.cpp b/ui/pagepainter.cpp index 6144f4c91..a4e3537a2 100644 --- a/ui/pagepainter.cpp +++ b/ui/pagepainter.cpp @@ -79,7 +79,7 @@ void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags, nYMax = (double)limits.bottom() / (double)height; // if no rect intersects limits, disable paintHighlights paintHighlights = false; - QValueList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end(); + QList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end(); for ( ; hIt != hEnd; ++hIt ) { if ( (*hIt)->intersects( nXMin, nYMin, nXMax, nYMax ) ) @@ -161,7 +161,7 @@ void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags, if ( paintHighlights ) { // draw highlights that are inside the 'limits' paint region - QValueList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end(); + QList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end(); for ( ; hIt != hEnd; ++hIt ) { HighlightRect * r = *hIt; @@ -206,7 +206,7 @@ void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags, QRect limitsEnlarged = limits; limitsEnlarged.addCoords( -2, -2, 2, 2 ); // draw rects that are inside the 'limits' paint region as opaque rects - QValueList< ObjectRect * >::const_iterator lIt = page->m_rects.begin(), lEnd = page->m_rects.end(); + QList< ObjectRect * >::const_iterator lIt = page->m_rects.begin(), lEnd = page->m_rects.end(); for ( ; lIt != lEnd; ++lIt ) { ObjectRect * rect = *lIt; diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 854d79ec2..99efaf806 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -17,7 +17,9 @@ ***************************************************************************/ // qt/kde includes +#include #include +#include #include #include #include @@ -63,8 +65,8 @@ class PageViewPrivate public: // the document, pageviewItems and the 'visible cache' KPDFDocument * document; - QValueVector< PageViewItem * > items; - QValueList< PageViewItem * > visibleItems; + QVector< PageViewItem * > items; + QList< PageViewItem * > visibleItems; // view layout (columns and continuous in Settings), zoom and mouse PageView::ZoomMode zoomMode; @@ -122,7 +124,7 @@ public: * and many insignificant stuff like this comment :-) */ PageView::PageView( QWidget *parent, KPDFDocument *document ) - : QScrollView( parent, "KPDF::pageView", WStaticContents | WNoAutoErase ) + : Q3ScrollView( parent, "KPDF::pageView", Qt::WStaticContents | Qt::WNoAutoErase ) { // create and initialize private storage structure d = new PageViewPrivate(); @@ -147,7 +149,7 @@ PageView::PageView( QWidget *parent, KPDFDocument *document ) // widget setup: setup focus, accept drops and track mouse viewport()->setFocusProxy( this ); - viewport()->setFocusPolicy( StrongFocus ); + viewport()->setFocusPolicy( Qt::StrongFocus ); //viewport()->setPaletteBackgroundColor( Qt::white ); viewport()->setBackgroundMode( Qt::NoBackground ); setResizePolicy( Manual ); @@ -238,7 +240,7 @@ void PageView::fitPageWidth( int /*page*/ ) } //BEGIN DocumentObserver inherited methods -void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool documentChanged ) +void PageView::notifySetup( const QVector< KPDFPage * > & pageSet, bool documentChanged ) { // reuse current pages if nothing new if ( ( pageSet.count() == d->items.count() ) && !documentChanged ) @@ -252,14 +254,14 @@ void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool doc } // delete all widgets (one for each page in pageSet) - QValueVector< PageViewItem * >::iterator dIt = d->items.begin(), dEnd = d->items.end(); + QVector< PageViewItem * >::iterator dIt = d->items.begin(), dEnd = d->items.end(); for ( ; dIt != dEnd; ++dIt ) delete *dIt; d->items.clear(); d->visibleItems.clear(); // create children widgets - QValueVector< KPDFPage * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end(); + QVector< KPDFPage * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end(); for ( ; setIt != setEnd; ++setIt ) d->items.push_back( new PageViewItem( *setIt ) ); @@ -290,7 +292,7 @@ void PageView::notifyViewportChanged( bool smoothMove ) // find PageViewItem matching the viewport description const DocumentViewport & vp = d->document->viewport(); PageViewItem * item = 0; - QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); + QVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); for ( ; iIt != iEnd; ++iIt ) if ( (*iIt)->pageNumber() == vp.pageNumber ) { @@ -374,7 +376,7 @@ void PageView::notifyPageChanged( int pageNumber, int changedFlags ) return; // iterate over visible items: if page(pageNumber) is one of them, repaint it - QValueList< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end(); + QList< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end(); for ( ; iIt != iEnd; ++iIt ) if ( (*iIt)->pageNumber() == pageNumber ) { @@ -403,7 +405,7 @@ void PageView::notifyContentsCleared( int changedFlags ) bool PageView::canUnloadPixmap( int pageNumber ) { // if the item is visible, forbid unloading - QValueList< PageViewItem * >::iterator vIt = d->visibleItems.begin(), vEnd = d->visibleItems.end(); + QList< PageViewItem * >::iterator vIt = d->visibleItems.begin(), vEnd = d->visibleItems.end(); for ( ; vIt != vEnd; ++vIt ) if ( (*vIt)->pageNumber() == pageNumber ) return false; @@ -431,7 +433,8 @@ void PageView::viewportPaintEvent( QPaintEvent * pe ) // create the screen painter. a pixel painted ar contentsX,contentsY // appears to the top-left corner of the scrollview. - QPainter screenPainter( viewport(), true ); + QPainter screenPainter( viewport() ); + screenPainter.setClipping( true ); screenPainter.translate( -contentsX(), -contentsY() ); // selectionRect is the normalized mouse selection rect @@ -446,7 +449,7 @@ void PageView::viewportPaintEvent( QPaintEvent * pe ) d->selectionRectColor : Qt::red; // subdivide region into rects - QMemArray allRects = pe->region().rects(); + Q3MemArray allRects = pe->region().rects(); uint numRects = allRects.count(); // preprocess rects area to see if it worths or not using subdivision @@ -503,7 +506,7 @@ void PageView::viewportPaintEvent( QPaintEvent * pe ) QImage blendedImage = blendedPixmap.convertToImage(); KImageEffect::blend( selBlendColor.dark(140), blendedImage, 0.2 ); // copy the blended pixmap back to its place - pixmapPainter.drawPixmap( blendRect.left(), blendRect.top(), blendedImage ); + pixmapPainter.drawImage( blendRect.left(), blendRect.top(), blendedImage ); } // draw border (red if the selection is too small) pixmapPainter.setPen( selBlendColor ); @@ -565,7 +568,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) if( d->typeAheadActive ) { // backspace: remove a char and search or terminates search - if( e->key() == Key_BackSpace ) + if( e->key() == Qt::Key_BackSpace ) { if( d->typeAheadString.length() > 1 ) { @@ -588,15 +591,15 @@ void PageView::keyPressEvent( QKeyEvent * e ) { // part doesn't get this key event because of the keyboard grab d->findTimeoutTimer->stop(); // restore normal operation during possible messagebox is displayed - releaseKeyboard(); + //releaseKeyboard(); if ( d->document->continueSearch( PAGEVIEW_SEARCH_ID ) ) d->messageWindow->display( i18n("Text found: \"%1\".").arg(d->typeAheadString.lower()), PageViewMessage::Find, 3000 ); d->findTimeoutTimer->start( 3000, true ); - grabKeyboard(); + // grabKeyboard(); } // esc and return: end search - else if( e->key() == Key_Escape || e->key() == Key_Return ) + else if( e->key() == Qt::Key_Escape || e->key() == Qt::Key_Return ) { findAheadStop(); } @@ -632,7 +635,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) connect( d->findTimeoutTimer, SIGNAL( timeout() ), this, SLOT( findAheadStop() ) ); } d->findTimeoutTimer->start( 3000, true ); - grabKeyboard(); + // grabKeyboard(); return; } @@ -643,12 +646,12 @@ void PageView::keyPressEvent( QKeyEvent * e ) // move/scroll page by using keys switch ( e->key() ) { - case Key_Up: - case Key_PageUp: + case Qt::Key_Up: + case Qt::Key_PageUp: // if in single page mode and at the top of the screen, go to previous page if ( Settings::viewContinuous() || verticalScrollBar()->value() > verticalScrollBar()->minValue() ) { - if ( e->key() == Key_Up ) + if ( e->key() == Qt::Key_Up ) verticalScrollBar()->subtractLine(); else verticalScrollBar()->subtractPage(); @@ -663,12 +666,12 @@ void PageView::keyPressEvent( QKeyEvent * e ) d->document->setViewport( newViewport ); } break; - case Key_Down: - case Key_PageDown: + case Qt::Key_Down: + case Qt::Key_PageDown: // if in single page mode and at the bottom of the screen, go to next page if ( Settings::viewContinuous() || verticalScrollBar()->value() < verticalScrollBar()->maxValue() ) { - if ( e->key() == Key_Down ) + if ( e->key() == Qt::Key_Down ) verticalScrollBar()->addLine(); else verticalScrollBar()->addPage(); @@ -683,14 +686,14 @@ void PageView::keyPressEvent( QKeyEvent * e ) d->document->setViewport( newViewport ); } break; - case Key_Left: + case Qt::Key_Left: horizontalScrollBar()->subtractLine(); break; - case Key_Right: + case Qt::Key_Right: horizontalScrollBar()->addLine(); break; - case Key_Shift: - case Key_Control: + case Qt::Key_Shift: + case Qt::Key_Control: if ( d->autoScrollTimer ) { if ( d->autoScrollTimer->isActive() ) @@ -722,7 +725,7 @@ void PageView::contentsMouseMoveEvent( QMouseEvent * e ) return; // if holding mouse mid button, perform zoom - if ( (e->state() & MidButton) && d->mouseMidStartY > 0 ) + if ( (e->state() & Qt::MidButton) && d->mouseMidStartY > 0 ) { int deltaY = d->mouseMidStartY - e->globalPos().y(); d->mouseMidStartY = e->globalPos().y(); @@ -733,8 +736,8 @@ void PageView::contentsMouseMoveEvent( QMouseEvent * e ) return; } - bool leftButton = e->state() & LeftButton, - rightButton = e->state() & RightButton; + bool leftButton = e->state() & Qt::LeftButton, + rightButton = e->state() & Qt::RightButton; switch ( d->mouseMode ) { case MouseNormal: @@ -802,10 +805,10 @@ void PageView::contentsMousePressEvent( QMouseEvent * e ) } // if pressing mid mouse button while not doing other things, begin 'comtinous zoom' mode - if ( e->button() & MidButton ) + if ( e->button() & Qt::MidButton ) { d->mouseMidStartY = e->globalPos().y(); - setCursor( sizeVerCursor ); + setCursor( Qt::sizeVerCursor ); return; } @@ -813,8 +816,8 @@ void PageView::contentsMousePressEvent( QMouseEvent * e ) d->mousePressPos = e->globalPos(); // handle mode dependant mouse press actions - bool leftButton = e->button() & LeftButton, - rightButton = e->button() & RightButton; + bool leftButton = e->button() & Qt::LeftButton, + rightButton = e->button() & Qt::RightButton; switch ( d->mouseMode ) { case MouseNormal: // drag start / click / link following @@ -822,7 +825,7 @@ void PageView::contentsMousePressEvent( QMouseEvent * e ) { d->mouseGrabPos = d->mouseOnRect ? QPoint() : d->mousePressPos; if ( !d->mouseOnRect ) - setCursor( sizeAllCursor ); + setCursor( Qt::sizeAllCursor ); } break; @@ -852,7 +855,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) if ( d->items.isEmpty() ) { // ..except for right Clicks (emitted even it viewport is empty) - if ( e->button() == RightButton ) + if ( e->button() == Qt::RightButton ) emit rightClick( 0, e->globalPos() ); return; } @@ -862,7 +865,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) return; // handle mode indepent mid buttom zoom - bool midButton = e->button() & MidButton; + bool midButton = e->button() & Qt::MidButton; if ( midButton && d->mouseMidStartY > 0 ) { d->mouseMidStartY = -1; @@ -871,8 +874,8 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) return; } - bool leftButton = e->button() & LeftButton, - rightButton = e->button() & RightButton; + bool leftButton = e->button() & Qt::LeftButton, + rightButton = e->button() & Qt::RightButton; switch ( d->mouseMode ) { case MouseNormal:{ @@ -977,7 +980,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) // grab text in selection by extracting it from all intersected pages QString selectedText; - QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); + QVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); for ( ; iIt != iEnd; ++iIt ) { PageViewItem * item = *iIt; @@ -1001,15 +1004,15 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) if ( !selectedText.isEmpty() ) { menu.insertTitle( i18n( "Text (1 character)", "Text (%n characters)", selectedText.length() ) ); - menu.insertItem( SmallIcon("editcopy"), i18n( "Copy to Clipboard" ), 1 ); + menu.insertItem( QIcon(SmallIcon("editcopy")), i18n( "Copy to Clipboard" ), 1 ); if ( !d->document->isAllowed( KPDFDocument::AllowCopy ) ) menu.setItemEnabled( 1, false ); if ( Settings::useKTTSD() ) - menu.insertItem( SmallIcon("kttsd"), i18n( "Speak Text" ), 2 ); + menu.insertItem( QIcon(SmallIcon("kttsd")), i18n( "Speak Text" ), 2 ); } menu.insertTitle( i18n( "Image (%1 by %2 pixels)" ).arg( selectionRect.width() ).arg( selectionRect.height() ) ); - menu.insertItem( SmallIcon("image"), i18n( "Copy to Clipboard" ), 3 ); - menu.insertItem( SmallIcon("filesave"), i18n( "Save to File..." ), 4 ); + menu.insertItem( QIcon(SmallIcon("image")), i18n( "Copy to Clipboard" ), 3 ); + menu.insertItem( QIcon(SmallIcon("filesave")), i18n( "Save to File..." ), 4 ); int choice = menu.exec( e->globalPos() ); // IMAGE operation choosen if ( choice > 2 ) @@ -1079,16 +1082,16 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) // serialize the text to speech (selectedText) and the // preferred reader ("" is the default voice) ... QByteArray data; - QDataStream arg( data, IO_WriteOnly ); + QDataStream arg( &data, IO_WriteOnly ); arg << selectedText; arg << QString(); - QCString replyType; + DCOPCString replyType; QByteArray replyData; // ..and send it to KTTSD if (client->call( "kttsd", "KSpeech", "setText(QString,QString)", data, replyType, replyData, true )) { QByteArray data2; - QDataStream arg2(data2, IO_WriteOnly); + QDataStream arg2(&data2, IO_WriteOnly); arg2 << 0; client->send("kttsd", "KSpeech", "startText(uint)", data2 ); } @@ -1124,7 +1127,7 @@ void PageView::wheelEvent( QWheelEvent *e ) int delta = e->delta(), vScroll = verticalScrollBar()->value(); e->accept(); - if ( (e->state() & ControlButton) == ControlButton ) { + if ( (e->state() & Qt::ControlButton) == Qt::ControlButton ) { if ( e->delta() < 0 ) slotZoomOut(); else @@ -1157,7 +1160,7 @@ void PageView::wheelEvent( QWheelEvent *e ) } } else - QScrollView::wheelEvent( e ); + Q3ScrollView::wheelEvent( e ); QPoint cp = viewportToContents(e->pos()); updateCursor(cp); @@ -1187,8 +1190,8 @@ void PageView::paintItems( QPainter * p, const QRect & contentsRect ) // create a region from wich we'll subtract painted rects QRegion remainingArea( contentsRect ); - //QValueVector< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end(); - QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); + //QVector< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end(); + QVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); for ( ; iIt != iEnd; ++iIt ) { // check if a piece of the page intersects the contents rect @@ -1216,9 +1219,10 @@ void PageView::paintItems( QPainter * p, const QRect & contentsRect ) p->drawRect( -1, -1, pixmapWidth + 2, pixmapHeight + 2 ); // draw bottom/right gradient int levels = 2; - int r = Qt::gray.red() / (levels + 2), - g = Qt::gray.green() / (levels + 2), - b = Qt::gray.blue() / (levels + 2); + QColor gray = Qt::gray; + int r = gray.red() / (levels + 2), + g = gray.green() / (levels + 2), + b = gray.blue() / (levels + 2); for ( int i = 0; i < levels; i++ ) { p->setPen( QColor( r * (i+2), g * (i+2), b * (i+2) ) ); @@ -1247,7 +1251,7 @@ void PageView::paintItems( QPainter * p, const QRect & contentsRect ) } // paint with background color the unpainted area - QMemArray backRects = remainingArea.rects(); + Q3MemArray backRects = remainingArea.rects(); uint backRectsNumber = backRects.count(); for ( uint jr = 0; jr < backRectsNumber; jr++ ) p->fillRect( backRects[ jr ], Qt::gray ); @@ -1289,7 +1293,7 @@ void PageView::updateItemSize( PageViewItem * item, int colWidth, int rowHeight PageViewItem * PageView::pickItemOnPoint( int x, int y ) { PageViewItem * item = 0; - QValueList< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end(); + QList< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end(); for ( ; iIt != iEnd; ++iIt ) { PageViewItem * i = *iIt; @@ -1340,7 +1344,7 @@ void PageView::selectionEndPoint( int x, int y ) compoundRegion -= intersection; } // tassellate region with rects and enqueue paint events - QMemArray rects = compoundRegion.rects(); + Q3MemArray rects = compoundRegion.rects(); for ( uint i = 0; i < rects.count(); i++ ) updateContents( rects[i] ); } @@ -1479,16 +1483,16 @@ void PageView::updateCursor( const QPoint &p ) // if over a ObjectRect (of type Link) change cursor to hand d->mouseOnRect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY ); if ( d->mouseOnRect ) - setCursor( pointingHandCursor ); + setCursor( Qt::pointingHandCursor ); else - setCursor( arrowCursor ); + setCursor( Qt::arrowCursor ); } else { // if there's no page over the cursor and we were showing the pointingHandCursor // go back to the normal one d->mouseOnRect = false; - setCursor( arrowCursor ); + setCursor( Qt::arrowCursor ); } } @@ -1514,7 +1518,7 @@ void PageView::slotRelayoutPages() } // common iterator used in this method and viewport parameters - QValueVector< PageViewItem * >::iterator iIt, iEnd = d->items.end(); + QVector< PageViewItem * >::iterator iIt, iEnd = d->items.end(); int viewportWidth = visibleWidth(), viewportHeight = visibleHeight(), fullWidth = 0, @@ -1704,8 +1708,8 @@ void PageView::slotRequestVisiblePixmaps( int newLeft, int newTop ) // iterate over all items d->visibleItems.clear(); - QValueList< PixmapRequest * > requestedPixmaps; - QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); + QList< PixmapRequest * > requestedPixmaps; + QVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); for ( ; iIt != iEnd; ++iIt ) { PageViewItem * i = *iIt; @@ -1845,7 +1849,7 @@ void PageView::findAheadStop() d->typeAheadActive = false; d->typeAheadString = ""; d->messageWindow->display( i18n("Find stopped."), PageViewMessage::Find, 1000 ); - releaseKeyboard(); + //releaseKeyboard(); } void PageView::slotZoom() diff --git a/ui/pageview.h b/ui/pageview.h index e0b944535..4bde72ac5 100644 --- a/ui/pageview.h +++ b/ui/pageview.h @@ -19,8 +19,8 @@ #ifndef _KPDF_PAGEVIEW_H_ #define _KPDF_PAGEVIEW_H_ -#include -#include +#include +#include #include "core/observer.h" class KURL; @@ -35,7 +35,7 @@ class PageViewPrivate; * @short display of course :-) * ... */ -class PageView : public QScrollView, public DocumentObserver +class PageView : public Q3ScrollView, public DocumentObserver { Q_OBJECT @@ -57,7 +57,7 @@ class PageView : public QScrollView, public DocumentObserver // inherited from DocumentObserver uint observerId() const { return PAGEVIEW_ID; } - void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged ); + void notifySetup( const QVector< KPDFPage * > & pages, bool documentChanged ); void notifyViewportChanged( bool smoothMove ); void notifyPageChanged( int pageNumber, int changedFlags ); void notifyContentsCleared( int changedFlags ); diff --git a/ui/pageviewutils.cpp b/ui/pageviewutils.cpp index 09cbf94b5..f1723fbb0 100644 --- a/ui/pageviewutils.cpp +++ b/ui/pageviewutils.cpp @@ -9,6 +9,7 @@ // qt/kde includes #include +#include #include #include #include @@ -23,8 +24,8 @@ PageViewMessage::PageViewMessage( QWidget * parent ) : QWidget( parent, "pageViewMessage" ), m_timer( 0 ) { - setFocusPolicy( NoFocus ); - setBackgroundMode( NoBackground ); + setFocusPolicy( Qt::NoFocus ); + setBackgroundMode( Qt::NoBackground ); move( 10, 10 ); resize( 0, 0 ); hide(); diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index d8303cda4..50f34ef26 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -8,6 +8,8 @@ ***************************************************************************/ // qt/kde includes +#include +#include #include #include #include @@ -49,7 +51,7 @@ struct PresentationFrame PresentationWidget::PresentationWidget( QWidget * parent, KPDFDocument * doc ) - : QDialog( parent, "presentationWidget", true, WDestructiveClose | WStyle_NoBorder), m_document( doc ), m_frameIndex( -1 ) + : QDialog( parent, "presentationWidget", true, Qt::WDestructiveClose | Qt::WStyle_NoBorder), m_document( doc ), m_frameIndex( -1 ) { // set look and geometry setBackgroundMode( Qt::NoBackground ); @@ -88,16 +90,16 @@ PresentationWidget::~PresentationWidget() m_document->setViewportPage( m_frameIndex/*, PRESENTATION_ID*/ ); // delete frames - QValueVector< PresentationFrame * >::iterator fIt = m_frames.begin(), fEnd = m_frames.end(); + QVector< PresentationFrame * >::iterator fIt = m_frames.begin(), fEnd = m_frames.end(); for ( ; fIt != fEnd; ++fIt ) delete *fIt; } -void PresentationWidget::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool /*documentChanged*/ ) +void PresentationWidget::notifySetup( const QVector< KPDFPage * > & pageSet, bool /*documentChanged*/ ) { // delete previous frames (if any (shouldn't be)) - QValueVector< PresentationFrame * >::iterator fIt = m_frames.begin(), fEnd = m_frames.end(); + QVector< PresentationFrame * >::iterator fIt = m_frames.begin(), fEnd = m_frames.end(); for ( ; fIt != fEnd; ++fIt ) delete *fIt; if ( !m_frames.isEmpty() ) @@ -105,7 +107,7 @@ void PresentationWidget::notifySetup( const QValueVector< KPDFPage * > & pageSet m_frames.clear(); // create the new frames - QValueVector< KPDFPage * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end(); + QVector< KPDFPage * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end(); float screenRatio = (float)m_height / (float)m_width; for ( ; setIt != setEnd; ++setIt ) { @@ -180,15 +182,15 @@ void PresentationWidget::keyPressEvent( QKeyEvent * e ) { if (m_width == -1) return; - if ( e->key() == Key_Left || e->key() == Key_Backspace || e->key() == Key_Prior ) + if ( e->key() == Qt::Key_Left || e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Prior ) slotPrevPage(); - else if ( e->key() == Key_Right || e->key() == Key_Space || e->key() == Key_Next ) + else if ( e->key() == Qt::Key_Right || e->key() == Qt::Key_Space || e->key() == Qt::Key_Next ) slotNextPage(); - else if ( e->key() == Key_Home ) + else if ( e->key() == Qt::Key_Home ) slotFirstPage(); - else if ( e->key() == Key_End ) + else if ( e->key() == Qt::Key_End ) slotLastPage(); - else if ( e->key() == Key_Escape ) + else if ( e->key() == Qt::Key_Escape ) { if ( m_topBar->isShown() ) m_topBar->hide(); @@ -290,7 +292,7 @@ void PresentationWidget::paintEvent( QPaintEvent * pe ) return; // blit the pixmap to the screen - QMemArray allRects = pe->region().rects(); + Q3MemArray allRects = pe->region().rects(); uint numRects = allRects.count(); for ( uint i = 0; i < numRects; i++ ) { @@ -356,7 +358,7 @@ void PresentationWidget::changePage( int newPage ) // notifyPixmapChanged call or else we can proceed to pixmap generation if ( !frame->page->hasPixmap( PRESENTATION_ID, pixW, pixH ) ) { - QValueList< PixmapRequest * > request; + QList< PixmapRequest * > request; request.push_back( new PixmapRequest( PRESENTATION_ID, m_frameIndex, pixW, pixH, PRESENTATION_PRIO ) ); m_document->requestPixmaps( request ); } @@ -402,7 +404,7 @@ void PresentationWidget::generateIntroPage( QPainter & p ) // use a vertical gray gradient background int blend1 = m_height / 10, blend2 = 9 * m_height / 10; - int baseTint = Qt::gray.red(); + int baseTint = QColor(Qt::gray).red(); for ( int i = 0; i < m_height; i++ ) { int k = baseTint; @@ -442,11 +444,11 @@ void PresentationWidget::generateIntroPage( QPainter & p ) // text shadow p.setPen( Qt::darkGray ); p.drawText( 2, m_height / 4 + strHeight * i + 2, m_width, strHeight, - AlignHCenter | AlignVCenter, m_metaStrings[i] ); + Qt::AlignHCenter | Qt::AlignVCenter, m_metaStrings[i] ); // text body p.setPen( 128 + (127 * i) / strNum ); p.drawText( 0, m_height / 4 + strHeight * i, m_width, strHeight, - AlignHCenter | AlignVCenter, m_metaStrings[i] ); + Qt::AlignHCenter | Qt::AlignVCenter, m_metaStrings[i] ); } } @@ -469,7 +471,7 @@ void PresentationWidget::generateContentsPage( int pageNum, QPainter & p ) // fill unpainted areas with background color QRegion unpainted( QRect( 0, 0, m_width, m_height ) ); - QMemArray rects = unpainted.subtract( frame->geometry ).rects(); + Q3MemArray rects = unpainted.subtract( frame->geometry ).rects(); for ( uint i = 0; i < rects.count(); i++ ) { const QRect & r = rects[i]; @@ -500,9 +502,11 @@ void PresentationWidget::generateOverlay() { // draw continuous slices int degrees = (int)( 360 * (float)(m_frameIndex + 1) / (float)pages ); pixmapPainter.setPen( 0x20 ); - pixmapPainter.setBrush( 0x10 ); +#warning QPainter.setBtush(0x10) ???? port this +// pixmapPainter.setBrush( 0x10 ); pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, (360-degrees)*16 ); - pixmapPainter.setBrush( 0xC0 ); +#warning QPainter.setBtush(0xC0) ???? port this +// pixmapPainter.setBrush( 0xC0 ); pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, -degrees*16 ); } else @@ -512,7 +516,8 @@ void PresentationWidget::generateOverlay() { float newCoord = -90 + 360 * (float)(i + 1) / (float)pages; pixmapPainter.setPen( i <= m_frameIndex ? 0x40 : 0x05 ); - pixmapPainter.setBrush( i <= m_frameIndex ? 0xC0 : 0x10 ); +#warning QPainter.setBtush(0xC0) ???? port this +// pixmapPainter.setBrush( i <= m_frameIndex ? 0xC0 : 0x10 ); pixmapPainter.drawPie( 2, 2, side - 4, side - 4, (int)( -16*(oldCoord + 1) ), (int)( -16*(newCoord - (oldCoord + 2)) ) ); oldCoord = newCoord; diff --git a/ui/presentationwidget.h b/ui/presentationwidget.h index fd59855fa..2373c3d29 100644 --- a/ui/presentationwidget.h +++ b/ui/presentationwidget.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include "core/observer.h" #include "core/pagetransition.h" @@ -38,7 +38,7 @@ class PresentationWidget : public QDialog, public DocumentObserver // inherited from DocumentObserver uint observerId() const { return PRESENTATION_ID; } - void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged ); + void notifySetup( const QVector< KPDFPage * > & pages, bool documentChanged ); void notifyViewportChanged( bool smoothMove ); void notifyPageChanged( int pageNumber, int changedFlags ); bool canUnloadPixmap( int pageNumber ); @@ -75,11 +75,11 @@ class PresentationWidget : public QDialog, public DocumentObserver QTimer * m_overlayHideTimer; int m_transitionDelay; int m_transitionMul; - QValueList< QRect > m_transitionRects; + QList< QRect > m_transitionRects; // misc stuff KPDFDocument * m_document; - QValueVector< PresentationFrame * > m_frames; + QVector< PresentationFrame * > m_frames; int m_frameIndex; QStringList m_metaStrings; KToolBar * m_topBar; diff --git a/ui/propertiesdialog.cpp b/ui/propertiesdialog.cpp index d5810a07b..1288a9daa 100644 --- a/ui/propertiesdialog.cpp +++ b/ui/propertiesdialog.cpp @@ -52,7 +52,7 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) // create labels and layout them QLabel *key = new QLabel( i18n( "%1:" ).arg( titleString ), page ); QLabel *value = new KSqueezedTextLabel( valueString, page ); - layout->addWidget( key, row, 0, AlignRight ); + layout->addWidget( key, row, 0, Qt::AlignRight ); layout->addWidget( value, row, 1 ); row++; diff --git a/ui/thumbnaillist.cpp b/ui/thumbnaillist.cpp index 247e17588..4bc225b92 100644 --- a/ui/thumbnaillist.cpp +++ b/ui/thumbnaillist.cpp @@ -8,6 +8,7 @@ ***************************************************************************/ // qt/kde includes +#include #include #include #include @@ -64,19 +65,19 @@ class ThumbnailWidget : public QWidget /** ThumbnailList implementation **/ ThumbnailList::ThumbnailList( QWidget *parent, KPDFDocument *document ) - : QScrollView( parent, "KPDF::Thumbnails", WNoAutoErase | WStaticContents ), + : Q3ScrollView( parent, "KPDF::Thumbnails", Qt::WNoAutoErase | Qt::WStaticContents ), m_document( document ), m_selected( 0 ), m_delayTimer( 0 ), m_bookmarkOverlay( 0 ) { // set scrollbars - setHScrollBarMode( QScrollView::AlwaysOff ); - setVScrollBarMode( QScrollView::AlwaysOn ); + setHScrollBarMode( Q3ScrollView::AlwaysOff ); + setVScrollBarMode( Q3ScrollView::AlwaysOn ); // dealing with large areas so enable clipper enableClipper( true ); // widget setup: can be focused by tab and mouse click (not wheel) viewport()->setFocusProxy( this ); - viewport()->setFocusPolicy( StrongFocus ); + viewport()->setFocusPolicy( Qt::StrongFocus ); setResizePolicy( Manual ); setAcceptDrops( true ); setDragAutoScroll( false ); @@ -94,10 +95,10 @@ ThumbnailList::~ThumbnailList() } //BEGIN DocumentObserver inherited methods -void ThumbnailList::notifySetup( const QValueVector< KPDFPage * > & pages, bool /*documentChanged*/ ) +void ThumbnailList::notifySetup( const QVector< KPDFPage * > & pages, bool /*documentChanged*/ ) { // delete all the Thumbnails - QValueVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); + QVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); for ( ; tIt != tEnd; ++tIt ) delete *tIt; m_thumbnails.clear(); @@ -114,7 +115,7 @@ void ThumbnailList::notifySetup( const QValueVector< KPDFPage * > & pages, bool //RESTORE THIS int flags = Settings::filterBookmarks() ? KPDFPage::Bookmark : KPDFPage::Highlight; // if no page matches filter rule, then display all pages - QValueVector< KPDFPage * >::const_iterator pIt = pages.begin(), pEnd = pages.end(); + QVector< KPDFPage * >::const_iterator pIt = pages.begin(), pEnd = pages.end(); bool skipCheck = true; for ( ; pIt != pEnd ; ++pIt ) //if ( (*pIt)->attributes() & flags ) @@ -161,7 +162,7 @@ void ThumbnailList::notifyViewportChanged( bool /*smoothMove*/ ) // select the page with viewport and ensure it's centered in the view m_vectorIndex = 0; - QValueVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); + QVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); for ( ; tIt != tEnd; ++tIt ) { if ( (*tIt)->pageNumber() == newPage ) @@ -186,7 +187,7 @@ void ThumbnailList::notifyPageChanged( int pageNumber, int /*changedFlags*/ ) // return; // iterate over visible items: if page(pageNumber) is one of them, repaint it - QValueList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); + QList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); for ( ; vIt != vEnd; ++vIt ) if ( (*vIt)->pageNumber() == pageNumber ) { @@ -205,7 +206,7 @@ void ThumbnailList::notifyContentsCleared( int changedFlags ) bool ThumbnailList::canUnloadPixmap( int pageNumber ) { // if the thubnail 'pageNumber' is one of the visible ones, forbid unloading - QValueList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); + QList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); for ( ; vIt != vEnd; ++vIt ) if ( (*vIt)->pageNumber() == pageNumber ) return false; @@ -219,7 +220,7 @@ void ThumbnailList::updateWidgets() { // find all widgets that intersects the viewport and update them QRect viewportRect( contentsX(), contentsY(), visibleWidth(), visibleHeight() ); - QValueList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); + QList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); for ( ; vIt != vEnd; ++vIt ) { ThumbnailWidget * t = *vIt; @@ -261,27 +262,27 @@ void ThumbnailList::keyPressEvent( QKeyEvent * keyEvent ) return keyEvent->ignore(); int nextPage = -1; - if ( keyEvent->key() == Key_Up ) + if ( keyEvent->key() == Qt::Key_Up ) { if ( !m_selected ) nextPage = 0; else if ( m_vectorIndex > 0 ) nextPage = m_thumbnails[ m_vectorIndex - 1 ]->pageNumber(); } - else if ( keyEvent->key() == Key_Down ) + else if ( keyEvent->key() == Qt::Key_Down ) { if ( !m_selected ) nextPage = 0; else if ( m_vectorIndex < (int)m_thumbnails.count() - 1 ) nextPage = m_thumbnails[ m_vectorIndex + 1 ]->pageNumber(); } - else if ( keyEvent->key() == Key_PageUp ) + else if ( keyEvent->key() == Qt::Key_PageUp ) verticalScrollBar()->subtractPage(); - else if ( keyEvent->key() == Key_PageDown ) + else if ( keyEvent->key() == Qt::Key_PageDown ) verticalScrollBar()->addPage(); - else if ( keyEvent->key() == Key_Home ) + else if ( keyEvent->key() == Qt::Key_Home ) nextPage = m_thumbnails[ 0 ]->pageNumber(); - else if ( keyEvent->key() == Key_End ) + else if ( keyEvent->key() == Qt::Key_End ) nextPage = m_thumbnails[ m_thumbnails.count() - 1 ]->pageNumber(); if ( nextPage == -1 ) @@ -299,7 +300,7 @@ void ThumbnailList::contentsMousePressEvent( QMouseEvent * e ) if ( e->button() != Qt::LeftButton ) return; int clickY = e->y(); - QValueList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); + QList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); for ( ; vIt != vEnd; ++vIt ) { ThumbnailWidget * t = *vIt; @@ -328,7 +329,7 @@ void ThumbnailList::viewportResizeEvent( QResizeEvent * e ) // resize and reposition items int totalHeight = 0, newWidth = e->size().width(); - QValueVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); + QVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); for ( ; tIt != tEnd; ++tIt ) { ThumbnailWidget *t = *tIt; @@ -383,8 +384,8 @@ void ThumbnailList::slotRequestVisiblePixmaps( int /*newContentsX*/, int newCont // scroll from the top to the last visible thumbnail m_visibleThumbnails.clear(); - QValueList< PixmapRequest * > requestedPixmaps; - QValueVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); + QList< PixmapRequest * > requestedPixmaps; + QVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); for ( ; tIt != tEnd; ++tIt ) { ThumbnailWidget * t = *tIt; @@ -438,7 +439,7 @@ void ThumbnailList::delayedRequestVisiblePixmaps( int delayMs ) /** ThumbnailWidget implementation **/ ThumbnailWidget::ThumbnailWidget( QWidget * parent, const KPDFPage * kp, ThumbnailList * tl ) - : QWidget( parent, 0, WNoAutoErase ), m_tl( tl ), m_page( kp ), + : QWidget( parent, 0, Qt::WNoAutoErase ), m_tl( tl ), m_page( kp ), m_selected( false ), m_pixmapWidth( 10 ), m_pixmapHeight( 10 ) { m_labelNumber = m_page->number() + 1; diff --git a/ui/thumbnaillist.h b/ui/thumbnaillist.h index e0f846101..73dca883d 100644 --- a/ui/thumbnaillist.h +++ b/ui/thumbnaillist.h @@ -10,9 +10,9 @@ #ifndef _KPDF_THUMBNAILLIST_H_ #define _KPDF_THUMBNAILLIST_H_ -#include -#include -#include +#include +#include +#include #include #include "core/observer.h" @@ -27,7 +27,7 @@ class ThumbnailWidget; * * ... */ -class ThumbnailList : public QScrollView, public DocumentObserver +class ThumbnailList : public Q3ScrollView, public DocumentObserver { Q_OBJECT public: @@ -37,7 +37,7 @@ Q_OBJECT // inherited: return thumbnails observer id uint observerId() const { return THUMBNAILS_ID; } // inherited: create thumbnails ( inherited as a DocumentObserver ) - void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged ); + void notifySetup( const QVector< KPDFPage * > & pages, bool documentChanged ); // inherited: hilihght current thumbnail ( inherited as DocumentObserver ) void notifyViewportChanged( bool smoothMove ); // inherited: redraw thumbnail ( inherited as DocumentObserver ) @@ -83,8 +83,8 @@ Q_OBJECT ThumbnailWidget *m_selected; QTimer *m_delayTimer; QPixmap *m_bookmarkOverlay; - QValueVector m_thumbnails; - QValueList m_visibleThumbnails; + QVector m_thumbnails; + QList m_visibleThumbnails; int m_vectorIndex; private slots: @@ -97,10 +97,10 @@ Q_OBJECT /** * @short A vertical boxed container with zero size hint (for insertion on left toolbox) */ -class ThumbnailsBox : public QVBox +class ThumbnailsBox : public Q3VBox { public: - ThumbnailsBox( QWidget * parent ) : QVBox( parent ) {}; + ThumbnailsBox( QWidget * parent ) : Q3VBox( parent ) {}; QSize sizeHint() const { return QSize(); } }; diff --git a/ui/toc.cpp b/ui/toc.cpp index bcebe78c5..9a470e575 100644 --- a/ui/toc.cpp +++ b/ui/toc.cpp @@ -8,7 +8,7 @@ ***************************************************************************/ // qt/kde includes -#include +#include #include // local includes @@ -63,7 +63,7 @@ TOC::TOC(QWidget *parent, KPDFDocument *document) : KListView(parent), m_documen setRootIsDecorated(true); setResizeMode(AllColumns); setAllColumnsShowFocus(true); - connect(this, SIGNAL(executed(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *))); + connect(this, SIGNAL(executed(Q3ListViewItem *)), this, SLOT(slotExecuted(Q3ListViewItem *))); } uint TOC::observerId() const @@ -71,7 +71,7 @@ uint TOC::observerId() const return TOC_ID; } -void TOC::notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged ) +void TOC::notifySetup( const QVector< KPDFPage * > & pages, bool documentChanged ) { if ( !documentChanged || pages.size() < 1 ) return; @@ -117,7 +117,7 @@ void TOC::addChildren( const QDomNode & parentNode, KListViewItem * parentItem ) } } -void TOC::slotExecuted( QListViewItem *i ) +void TOC::slotExecuted( Q3ListViewItem *i ) { const QDomElement & e = static_cast< TOCItem* >( i )->element(); if ( e.hasAttribute( "Viewport" ) ) diff --git a/ui/toc.h b/ui/toc.h index 6683e99b3..82314e794 100644 --- a/ui/toc.h +++ b/ui/toc.h @@ -24,13 +24,13 @@ Q_OBJECT // inherited from DocumentObserver uint observerId() const; - void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged ); + void notifySetup( const QVector< KPDFPage * > & pages, bool documentChanged ); signals: void hasTOC(bool has); private slots: - void slotExecuted(QListViewItem *i); + void slotExecuted(Q3ListViewItem *i); private: void addChildren( const QDomNode & parentNode, KListViewItem * parentItem = 0 ); diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index 19cc8ad07..224032dba 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -17,7 +17,7 @@ // KPDF: additional includes for Qt and Xft #include #include -#include +#include // -- gentoo compile fix (XFree 4.3.0, FC 2.2.3, FreeType 2.1.9) -- // on other distros these 2 lines should't harm #include @@ -1093,7 +1093,7 @@ DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { FC_SLANT, FcTypeInteger, slant, FC_WEIGHT, FcTypeInteger, weight, FC_WIDTH, FcTypeInteger, width, FC_LANG, FcTypeString, "xx", (char*)0); if (!p) goto fin; - m = XftFontMatch(qt_xdisplay(),qt_xscreen(),p,&res); + m = XftFontMatch(QX11Info::display(),QX11Info::appScreen(),p,&res); if (!m) goto fin; res = FcPatternGetString (m, FC_FILE, 0, &s); if (res != FcResultMatch || !s) goto fin; From e73e00117dfa435d782b2e9989a4b6782cb8f16d Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 31 May 2005 20:22:08 +0000 Subject: [PATCH 073/245] Don't crash when receive null qfocusevent * svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=420339 --- part.cpp | 2 -- ui/minibar.cpp | 7 ++++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/part.cpp b/part.cpp index c3a739443..cd7d235c4 100644 --- a/part.cpp +++ b/part.cpp @@ -790,8 +790,6 @@ void Part::slotPrint() if (width > height) landscape++; else portrait++; } -#warning whoever ported Kprinter messed, setOrientation is QPrinted::Orientation not Qt::Orientation -#warning change it // if (landscape > portrait) printer.setOrientation(KPrinter::Landscape); if (printer.setup(widget())) doPrint( printer ); diff --git a/ui/minibar.cpp b/ui/minibar.cpp index 524784d9f..ceb152730 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -366,9 +366,14 @@ void PagesEdit::focusInEvent( QFocusEvent * e ) // call default handler QLineEdit::focusInEvent( e ); } - +#include void PagesEdit::focusOutEvent( QFocusEvent * e ) { + if (!e) + { + kdDebug() << "Got a null QFocusEvent, investigate" << endl; + return; + } // change background color to a dark tone #warning setLineWidth does not exists in Qt4 // setLineWidth( 1 ); From affdd4c089c0a4a711c2740b1b8a36b0c4a9c2dd Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 31 May 2005 20:54:14 +0000 Subject: [PATCH 074/245] QCustomEvent still exists :-) svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=420348 --- core/generator_pdf/generator_pdf.cpp | 6 +++--- core/generator_pdf/generator_pdf.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 654cf77d9..8854d8561 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -894,7 +894,7 @@ void PDFGenerator::addTransition( int pageNumber, KPDFPage * page ) } -/* + void PDFGenerator::customEvent( QCustomEvent * event ) { // catch generator 'ready events' only @@ -906,7 +906,7 @@ void PDFGenerator::customEvent( QCustomEvent * event ) if ( generatorThread->running() ) { // if so, wait for effective thread termination - if ( !generatorThread->wait( 9999 /*10s timeout*/ /*) ) + if ( !generatorThread->wait( 9999 /*10s timeout*/ ) ) { kdWarning() << "PDFGenerator: thread sent 'data available' " << "signal but had problems ending." << endl; @@ -945,7 +945,7 @@ void PDFGenerator::customEvent( QCustomEvent * event ) ready = true; // notify the new generation signalRequestDone( request ); -}*/ +} diff --git a/core/generator_pdf/generator_pdf.h b/core/generator_pdf/generator_pdf.h index e5be98f54..72db05a32 100644 --- a/core/generator_pdf/generator_pdf.h +++ b/core/generator_pdf/generator_pdf.h @@ -12,6 +12,7 @@ #define _KPDF_GENERATOR_PDF_H_ #include +#include #include #include #include @@ -96,8 +97,7 @@ class PDFGenerator : public Generator // private function for creating the transition information void addTransition( int pageNumber, KPDFPage * page ); // (async related) receive data from the generator thread -#warning QCustomEvent is gone :-/ -// void customEvent( QCustomEvent * ); + void customEvent( QCustomEvent * ); // xpdf dependant stuff QMutex docLock; From 655113f5f943fa298c1e8e02e122a831d5c1a484 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 31 May 2005 21:30:21 +0000 Subject: [PATCH 075/245] i'm able to see a thumbnail now :-) svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=420358 --- core/document.cpp | 4 +++- core/generator_pdf/generator_pdf.cpp | 7 +++++-- core/generator_pdf/generator_pdf.h | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index ea754f296..394102b23 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -1218,7 +1218,9 @@ int KPDFDocument::getTotalMemory() int KPDFDocument::getFreeMemory() { -#ifdef __linux__ +#warning this hangs, check why +#if 0 +//#ifdef __linux__ // if /proc/meminfo doesn't exist, return MEMORY FULL QFile memFile( "/proc/meminfo" ); if ( !memFile.open( IO_ReadOnly ) ) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 8854d8561..f2151b621 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -895,12 +895,14 @@ void PDFGenerator::addTransition( int pageNumber, KPDFPage * page ) -void PDFGenerator::customEvent( QCustomEvent * event ) +void PDFGenerator::customEvent( QEvent * e ) { // catch generator 'ready events' only - if ( event->type() != TGE_DATAREADY_ID ) + if ( e->type() != TGE_DATAREADY_ID ) return; + QCustomEvent *event = static_cast(e); + #if 0 // check if thread is running (has to be stopped now) if ( generatorThread->running() ) @@ -1100,4 +1102,5 @@ void PDFPixmapGeneratorThread::run() QCustomEvent * readyEvent = new QCustomEvent( TGE_DATAREADY_ID ); readyEvent->setData( d->currentRequest ); QApplication::postEvent( d->generator, readyEvent ); + kdDebug() << "UEEEEEE GENERATED" << endl; } diff --git a/core/generator_pdf/generator_pdf.h b/core/generator_pdf/generator_pdf.h index 72db05a32..67d789a69 100644 --- a/core/generator_pdf/generator_pdf.h +++ b/core/generator_pdf/generator_pdf.h @@ -97,7 +97,7 @@ class PDFGenerator : public Generator // private function for creating the transition information void addTransition( int pageNumber, KPDFPage * page ); // (async related) receive data from the generator thread - void customEvent( QCustomEvent * ); + void customEvent( QEvent * ); // xpdf dependant stuff QMutex docLock; From 4f73724c99a7e2abaf2cac41ef229f5486e1b71b Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 31 May 2005 21:31:11 +0000 Subject: [PATCH 076/245] slipped debug comment svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=420359 --- core/generator_pdf/generator_pdf.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index f2151b621..89ab4dd52 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -1102,5 +1102,4 @@ void PDFPixmapGeneratorThread::run() QCustomEvent * readyEvent = new QCustomEvent( TGE_DATAREADY_ID ); readyEvent->setData( d->currentRequest ); QApplication::postEvent( d->generator, readyEvent ); - kdDebug() << "UEEEEEE GENERATED" << endl; } From 9c0b0a45a0361d038f37bce7be1c63f4a7ecf9a9 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 31 May 2005 22:25:54 +0000 Subject: [PATCH 077/245] you can open files, but any try to scroll the viewport will make it crash svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=420380 --- core/document.cpp | 6 +++++- core/generator_pdf/generator_pdf.cpp | 1 + ui/pageview.cpp | 7 ++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 394102b23..6176c422c 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -1173,6 +1173,10 @@ void KPDFDocument::cleanupPixmapMemory( int /*sure? bytesOffset*/ ) while ( (pIt != pEnd) && (memoryToFree > 0) ) { AllocatedPixmap * p = *pIt; +#warning this should NOT be needed + // TODO quick way to avoid crashes + if (!d->observers[ p->id ]) return; + if ( d->observers[ p->id ]->canUnloadPixmap( p->page ) ) { // update internal variables @@ -1380,7 +1384,7 @@ void KPDFDocument::saveDocumentInfo() const QDomElement bookmarkList = doc.createElement( "bookmarkList" ); root.appendChild( bookmarkList ); - for ( uint i = 0; i < pages_vector.count() ; i++ ) + for ( int i = 0; i < pages_vector.count() ; i++ ) { if ( pages_vector[i]->hasBookmark() ) { diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 89ab4dd52..3e48969e6 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -289,6 +289,7 @@ void PDFGenerator::generatePixmap( PixmapRequest * request ) if ( request->async ) { // start the generation into the thread + generatorThread->wait(); generatorThread->startGeneration( request ); return; } diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 99efaf806..623ca4ef9 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -434,7 +434,8 @@ void PageView::viewportPaintEvent( QPaintEvent * pe ) // create the screen painter. a pixel painted ar contentsX,contentsY // appears to the top-left corner of the scrollview. QPainter screenPainter( viewport() ); - screenPainter.setClipping( true ); +// TODO seems we don't need that in Qt4 +// screenPainter.setClipping( true ); screenPainter.translate( -contentsX(), -contentsY() ); // selectionRect is the normalized mouse selection rect @@ -676,7 +677,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) else verticalScrollBar()->addPage(); } - else if ( d->document->currentPage() < d->items.count() - 1 ) + else if ( (int)d->document->currentPage() < d->items.count() - 1 ) { // more optmized than document->setNextPage and then move view to top DocumentViewport newViewport = d->document->viewport(); @@ -1136,7 +1137,7 @@ void PageView::wheelEvent( QWheelEvent *e ) else if ( delta <= -120 && !Settings::viewContinuous() && vScroll == verticalScrollBar()->maxValue() ) { // go to next page - if ( d->document->currentPage() < d->items.count() - 1 ) + if ( (int)d->document->currentPage() < d->items.count() - 1 ) { // more optmized than document->setNextPage and then move view to top DocumentViewport newViewport = d->document->viewport(); From b07bc9e9e18746019a48dd1f07450c9d6a4e9a43 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 31 May 2005 22:29:47 +0000 Subject: [PATCH 078/245] crash-- svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=420382 --- core/document.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 6176c422c..0c70fb841 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -1436,9 +1436,10 @@ void KPDFDocument::saveDocumentInfo() const void KPDFDocument::slotTimedMemoryCheck() { // [MEM] clean memory (for 'free mem dependant' profiles only) - if ( Settings::memoryLevel() != Settings::EnumMemoryLevel::Low && +#warning commented because makes it crash +/* if ( Settings::memoryLevel() != Settings::EnumMemoryLevel::Low && d->allocatedPixmapsTotalMemory > 1024*1024 ) - cleanupPixmapMemory(); + cleanupPixmapMemory();*/ } From f10d8d6b1b9dfa4a7efb8e023e285ae63d0adeb5 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 31 May 2005 22:46:24 +0000 Subject: [PATCH 079/245] used linkedlist instead of list and now it does not crashes on viewport scrolling svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=420385 --- core/document.cpp | 56 +++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 0c70fb841..f349c732b 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -58,14 +58,14 @@ class KPDFDocumentPrivate QStringList kimgioMimes; // viewport stuff - QList< DocumentViewport > viewportHistory; - QList< DocumentViewport >::iterator viewportIterator; + QLinkedList< DocumentViewport > viewportHistory; + QLinkedList< DocumentViewport >::iterator viewportIterator; DocumentViewport nextDocumentViewport; // see KPDFLink::Goto for an explanation // observers / requests / allocator stuff QMap< int, DocumentObserver * > observers; - QList< PixmapRequest * > pixmapRequestsStack; - QList< AllocatedPixmap * > allocatedPixmapsFifo; + QLinkedList< PixmapRequest * > pixmapRequestsStack; + QLinkedList< AllocatedPixmap * > allocatedPixmapsFifo; int allocatedPixmapsTotalMemory; // timers (memory checking / info saver) @@ -88,7 +88,7 @@ struct RunningSearch // store search properties int continueOnPage; NormalizedRect continueOnMatch; - QList< int > highlightedPages; + QLinkedList< int > highlightedPages; // fields related to previous searches (used for 'continueSearch') QString cachedString; @@ -245,8 +245,8 @@ void KPDFDocument::closeDocument() d->url = KURL(); // remove requests left in queue - QList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(); - QList< PixmapRequest * >::iterator sEnd = d->pixmapRequestsStack.end(); + QLinkedList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(); + QLinkedList< PixmapRequest * >::iterator sEnd = d->pixmapRequestsStack.end(); for ( ; sIt != sEnd; ++sIt ) delete *sIt; d->pixmapRequestsStack.clear(); @@ -262,8 +262,8 @@ void KPDFDocument::closeDocument() pages_vector.clear(); // clear 'memory allocation' descriptors - QList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); - QList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + QLinkedList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QLinkedList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); for ( ; aIt != aEnd; ++aIt ) delete *aIt; d->allocatedPixmapsFifo.clear(); @@ -308,8 +308,8 @@ void KPDFDocument::removeObserver( DocumentObserver * pObserver ) (*it)->deletePixmap( observerId ); // [MEM] free observer's allocation descriptors - QList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); - QList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + QLinkedList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QLinkedList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); while ( aIt != aEnd ) { AllocatedPixmap * p = *aIt; @@ -338,8 +338,8 @@ void KPDFDocument::reparseConfig() (*it)->deletePixmapsAndRects(); // [MEM] remove allocation descriptors - QList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); - QList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + QLinkedList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QLinkedList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); for ( ; aIt != aEnd; ++aIt ) delete *aIt; d->allocatedPixmapsFifo.clear(); @@ -445,7 +445,7 @@ void KPDFDocument::requestPixmaps( const QList< PixmapRequest * > & requests ) // 1. [CLEAN STACK] remove previous requests of requesterID int requesterID = requests.first()->id; - QList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(), sEnd = d->pixmapRequestsStack.end(); + QLinkedList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(), sEnd = d->pixmapRequestsStack.end(); while ( sIt != sEnd ) { if ( (*sIt)->id == requesterID ) @@ -573,9 +573,9 @@ void KPDFDocument::setViewport( const DocumentViewport & viewport, int excludeId if ( d->allocatedPixmapsFifo.count() > 1 ) { const int page = viewport.pageNumber; - QList< AllocatedPixmap * > viewportPixmaps; - QList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); - QList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + QLinkedList< AllocatedPixmap * > viewportPixmaps; + QLinkedList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QLinkedList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); while ( aIt != aEnd ) { if ( (*aIt)->page == page ) @@ -605,7 +605,7 @@ void KPDFDocument::setPrevViewport() void KPDFDocument::setNextViewport() // restore next viewport from the history { - QList< DocumentViewport >::iterator nextIterator = d->viewportIterator; + QLinkedList< DocumentViewport >::iterator nextIterator = d->viewportIterator; ++nextIterator; if ( nextIterator != d->viewportHistory.end() ) { @@ -643,11 +643,11 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar // global data for search bool foundAMatch = false; - QList< int > pagesToNotify; + QLinkedList< int > pagesToNotify; // remove highlights from pages and queue them for notifying changes pagesToNotify += s->highlightedPages; - QList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end(); + QLinkedList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end(); for ( ; it != end; ++it ) pages_vector[ *it ]->deleteHighlights( searchID ); s->highlightedPages.clear(); @@ -859,7 +859,7 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar } // notify observers about highlights changes - QList< int >::iterator nIt = pagesToNotify.begin(), nEnd = pagesToNotify.end(); + QLinkedList< int >::iterator nIt = pagesToNotify.begin(), nEnd = pagesToNotify.end(); for ( ; nIt != nEnd; ++nIt ) foreachObserver( notifyPageChanged( *nIt, DocumentObserver::Highlights ) ); @@ -890,7 +890,7 @@ void KPDFDocument::resetSearch( int searchID ) RunningSearch * s = d->searches[ searchID ]; // unhighlight pages and inform observers about that - QList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end(); + QLinkedList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end(); for ( ; it != end; ++it ) { int pageNumber = *it; @@ -1082,8 +1082,8 @@ void KPDFDocument::requestDone( PixmapRequest * req ) #endif // [MEM] 1.1 find and remove a previous entry for the same page and id - QList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); - QList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + QLinkedList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QLinkedList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); for ( ; aIt != aEnd; ++aIt ) if ( (*aIt)->page == req->pageNumber && (*aIt)->id == req->id ) { @@ -1168,8 +1168,8 @@ void KPDFDocument::cleanupPixmapMemory( int /*sure? bytesOffset*/ ) { // [MEM] free memory starting from older pixmaps int pagesFreed = 0; - QList< AllocatedPixmap * >::iterator pIt = d->allocatedPixmapsFifo.begin(); - QList< AllocatedPixmap * >::iterator pEnd = d->allocatedPixmapsFifo.end(); + QLinkedList< AllocatedPixmap * >::iterator pIt = d->allocatedPixmapsFifo.begin(); + QLinkedList< AllocatedPixmap * >::iterator pEnd = d->allocatedPixmapsFifo.end(); while ( (pIt != pEnd) && (memoryToFree > 0) ) { AllocatedPixmap * p = *pIt; @@ -1400,7 +1400,7 @@ void KPDFDocument::saveDocumentInfo() const root.appendChild( generalInfo ); // ... saves history up to 10 viewports - QList< DocumentViewport >::iterator backIterator = d->viewportIterator; + QLinkedList< DocumentViewport >::iterator backIterator = d->viewportIterator; if ( backIterator != d->viewportHistory.end() ) { // go back up to 10 steps from the current viewportIterator @@ -1413,7 +1413,7 @@ void KPDFDocument::saveDocumentInfo() const generalInfo.appendChild( historyNode ); // add old[backIterator] and present[viewportIterator] items - QList< DocumentViewport >::iterator endIt = d->viewportIterator; + QLinkedList< DocumentViewport >::iterator endIt = d->viewportIterator; ++endIt; while ( backIterator != endIt ) { From 65f71d9cdf71246112597d221142c844421273cb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 31 May 2005 23:14:08 +0000 Subject: [PATCH 080/245] fix layouting a bit svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=420392 --- core/document.cpp | 9 ++------- part.cpp | 4 ++++ ui/minibar.cpp | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index f349c732b..2cc1a9982 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -1173,10 +1173,6 @@ void KPDFDocument::cleanupPixmapMemory( int /*sure? bytesOffset*/ ) while ( (pIt != pEnd) && (memoryToFree > 0) ) { AllocatedPixmap * p = *pIt; -#warning this should NOT be needed - // TODO quick way to avoid crashes - if (!d->observers[ p->id ]) return; - if ( d->observers[ p->id ]->canUnloadPixmap( p->page ) ) { // update internal variables @@ -1436,10 +1432,9 @@ void KPDFDocument::saveDocumentInfo() const void KPDFDocument::slotTimedMemoryCheck() { // [MEM] clean memory (for 'free mem dependant' profiles only) -#warning commented because makes it crash -/* if ( Settings::memoryLevel() != Settings::EnumMemoryLevel::Low && + if ( Settings::memoryLevel() != Settings::EnumMemoryLevel::Low && d->allocatedPixmapsTotalMemory > 1024*1024 ) - cleanupPixmapMemory();*/ + cleanupPixmapMemory(); } diff --git a/part.cpp b/part.cpp index cd7d235c4..1ecd23f6d 100644 --- a/part.cpp +++ b/part.cpp @@ -127,6 +127,8 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_leftPanel->setMinimumWidth( 90 ); m_leftPanel->setMaximumWidth( 300 ); QVBoxLayout * leftPanelLayout = new QVBoxLayout( m_leftPanel ); + leftPanelLayout->setMargin(0); + leftPanelLayout->setSpacing(0); // widgets: [left toolbox/..] | [] m_toolBox = new QToolBox( m_leftPanel ); @@ -166,6 +168,8 @@ Part::Part(QWidget *parentWidget, const char *widgetName, QWidget * miniBarContainer = new QWidget( m_leftPanel ); leftPanelLayout->addWidget( miniBarContainer ); QVBoxLayout * miniBarLayout = new QVBoxLayout( miniBarContainer ); + miniBarLayout->setMargin(0); + miniBarLayout->setSpacing(0); // widgets: [../[spacer/..]] | [] QWidget * miniSpacer = new QWidget( miniBarContainer ); miniSpacer->setFixedHeight( 6 ); diff --git a/ui/minibar.cpp b/ui/minibar.cpp index ceb152730..6f70c0907 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -86,6 +86,7 @@ MiniBar::MiniBar( QWidget * parent, KPDFDocument * document ) { // left spacer QHBoxLayout * horLayout = new QHBoxLayout( this ); + horLayout->setMargin(0); QSpacerItem * spacerL = new QSpacerItem( 20, 10, QSizePolicy::Expanding ); horLayout->addItem( spacerL ); From 84ac7076517be31d556be702243da7b3778d6c6e Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 1 Jun 2005 18:33:58 +0000 Subject: [PATCH 081/245] fix osd fix kpassworddialog::getpassword api change svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=420904 --- core/generator_pdf/generator_pdf.cpp | 2 +- ui/pageviewutils.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 3e48969e6..f28d172ff 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -143,7 +143,7 @@ bool PDFGenerator::loadDocument( const QString & filePath, QVector & firstInput = false; // if the user presses cancel, abort opening - if ( KPasswordDialog::getPassword( password, prompt ) != KPasswordDialog::Accepted ) + if ( KPasswordDialog::getPassword(0, password, prompt ) != KPasswordDialog::Accepted ) break; } diff --git a/ui/pageviewutils.cpp b/ui/pageviewutils.cpp index f1723fbb0..8b08966de 100644 --- a/ui/pageviewutils.cpp +++ b/ui/pageviewutils.cpp @@ -73,6 +73,7 @@ void PageViewMessage::display( const QString & message, Icon icon, int durationM height = QMAX( height, symbol.height() ); } QRect geometry( 0, 0, width + 10, height + 8 ); + QRect geometry2( 0, 0, width + 9, height + 7 ); // resize pixmap, mask and widget static QBitmap mask; @@ -81,17 +82,17 @@ void PageViewMessage::display( const QString & message, Icon icon, int durationM resize( geometry.size() ); // create and set transparency mask - QPainter maskPainter( &mask); - mask.fill( Qt::black ); - maskPainter.setBrush( Qt::white ); - maskPainter.drawRoundRect( geometry, 1600 / geometry.width(), 1600 / geometry.height() ); + QPainter maskPainter(&mask); + mask.fill( Qt::white ); + maskPainter.setBrush( Qt::black ); + maskPainter.drawRoundRect( geometry2, 1600 / geometry2.width(), 1600 / geometry2.height() ); setMask( mask ); // draw background QPainter bufferPainter( &m_pixmap ); bufferPainter.setPen( Qt::black ); bufferPainter.setBrush( backgroundColor() ); - bufferPainter.drawRoundRect( geometry, 1600 / geometry.width(), 1600 / geometry.height() ); + bufferPainter.drawRoundRect( geometry2, 1600 / geometry2.width(), 1600 / geometry2.height() ); // draw icon if present if ( !symbol.isNull() ) From 00795e5d73abcde99ae0e42e70bbb77fdd5de0b7 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 2 Jun 2005 17:22:35 +0000 Subject: [PATCH 082/245] Fix bug 106546, Jakubs that is who made the code don't see why it should be there if without it vim-like search still works svn path=/trunk/KDE/kdegraphics/kpdf/; revision=421280 --- ui/pageview.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 854d79ec2..be8887942 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -588,12 +588,12 @@ void PageView::keyPressEvent( QKeyEvent * e ) { // part doesn't get this key event because of the keyboard grab d->findTimeoutTimer->stop(); // restore normal operation during possible messagebox is displayed - releaseKeyboard(); + //releaseKeyboard(); if ( d->document->continueSearch( PAGEVIEW_SEARCH_ID ) ) d->messageWindow->display( i18n("Text found: \"%1\".").arg(d->typeAheadString.lower()), PageViewMessage::Find, 3000 ); d->findTimeoutTimer->start( 3000, true ); - grabKeyboard(); + // grabKeyboard(); } // esc and return: end search else if( e->key() == Key_Escape || e->key() == Key_Return ) @@ -632,7 +632,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) connect( d->findTimeoutTimer, SIGNAL( timeout() ), this, SLOT( findAheadStop() ) ); } d->findTimeoutTimer->start( 3000, true ); - grabKeyboard(); + // grabKeyboard(); return; } @@ -1845,7 +1845,7 @@ void PageView::findAheadStop() d->typeAheadActive = false; d->typeAheadString = ""; d->messageWindow->display( i18n("Find stopped."), PageViewMessage::Find, 1000 ); - releaseKeyboard(); + //releaseKeyboard(); } void PageView::slotZoom() From 26211ea3a1b12e2578439d7321c45de23a7bedec Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 2 Jun 2005 17:28:47 +0000 Subject: [PATCH 083/245] adding some comments svn path=/trunk/KDE/kdegraphics/kpdf/; revision=421284 --- ui/pageview.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index be8887942..afda2221d 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -588,11 +588,13 @@ void PageView::keyPressEvent( QKeyEvent * e ) { // part doesn't get this key event because of the keyboard grab d->findTimeoutTimer->stop(); // restore normal operation during possible messagebox is displayed + //commenting as seems to cause bug 106546 and does not seem to give anything //releaseKeyboard(); if ( d->document->continueSearch( PAGEVIEW_SEARCH_ID ) ) d->messageWindow->display( i18n("Text found: \"%1\".").arg(d->typeAheadString.lower()), PageViewMessage::Find, 3000 ); d->findTimeoutTimer->start( 3000, true ); + //commenting as seems to cause bug 106546 and does not seem to give anything // grabKeyboard(); } // esc and return: end search @@ -632,6 +634,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) connect( d->findTimeoutTimer, SIGNAL( timeout() ), this, SLOT( findAheadStop() ) ); } d->findTimeoutTimer->start( 3000, true ); + //commenting as seems to cause bug 106546 and does not seem to give anything // grabKeyboard(); return; } @@ -1845,6 +1848,7 @@ void PageView::findAheadStop() d->typeAheadActive = false; d->typeAheadString = ""; d->messageWindow->display( i18n("Find stopped."), PageViewMessage::Find, 1000 ); + //commenting as seems to cause bug 106546 and does not seem to give anything //releaseKeyboard(); } From f4026b3237483e8f58b99181198d17e636496ad8 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 2 Jun 2005 17:57:17 +0000 Subject: [PATCH 084/245] Fix bug 103433 (usability) svn path=/trunk/KDE/kdegraphics/kpdf/; revision=421295 --- ui/toc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/toc.cpp b/ui/toc.cpp index bcebe78c5..5fb8e5653 100644 --- a/ui/toc.cpp +++ b/ui/toc.cpp @@ -63,7 +63,8 @@ TOC::TOC(QWidget *parent, KPDFDocument *document) : KListView(parent), m_documen setRootIsDecorated(true); setResizeMode(AllColumns); setAllColumnsShowFocus(true); - connect(this, SIGNAL(executed(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *))); + connect(this, SIGNAL(clicked(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *))); + connect(this, SIGNAL(returnPressed(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *))); } uint TOC::observerId() const From 45f58c45a328a2956d6b5454911dd36600aaacb0 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 2 Jun 2005 18:18:33 +0000 Subject: [PATCH 085/245] Fix usability issues as reported by our usability man svn path=/trunk/KDE/kdegraphics/kpdf/; revision=421308 --- part.rc | 10 ++++------ ui/pageview.cpp | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/part.rc b/part.rc index e7592e70b..b1352ce61 100644 --- a/part.rc +++ b/part.rc @@ -14,8 +14,8 @@

&View - + @@ -24,9 +24,10 @@ &Go - + + @@ -34,7 +35,7 @@ - &Mouse Mode + &Tools @@ -55,9 +56,6 @@ - - - diff --git a/ui/pageview.cpp b/ui/pageview.cpp index afda2221d..f076cfe73 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -204,14 +204,14 @@ void PageView::setupActions( KActionCollection * ac ) d->aViewContinuous->setChecked( Settings::viewContinuous() ); // Mouse-Mode actions - d->aMouseNormal = new KRadioAction( i18n("&Normal"), "mouse", 0, this, SLOT( slotSetMouseNormal() ), ac, "mouse_drag" ); + d->aMouseNormal = new KRadioAction( i18n("&Browse Tool"), "mouse", 0, this, SLOT( slotSetMouseNormal() ), ac, "mouse_drag" ); d->aMouseNormal->setExclusiveGroup( "MouseType" ); d->aMouseNormal->setChecked( true ); KToggleAction * mz = new KRadioAction( i18n("&Zoom Tool"), "viewmag", 0, this, SLOT( slotSetMouseZoom() ), ac, "mouse_zoom" ); mz->setExclusiveGroup( "MouseType" ); - d->aMouseSelect = new KRadioAction( i18n("&Select"), "frame_edit", 0, this, SLOT( slotSetMouseSelect() ), ac, "mouse_select" ); + d->aMouseSelect = new KRadioAction( i18n("&Select Tool"), "frame_edit", 0, this, SLOT( slotSetMouseSelect() ), ac, "mouse_select" ); d->aMouseSelect->setExclusiveGroup( "MouseType" ); /* d->aMouseEdit = new KRadioAction( i18n("Draw"), "edit", 0, this, SLOT( slotSetMouseDraw() ), ac, "mouse_draw" ); From c6698337c756170a619e5762da9050ba7931d2ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0smail=20D=C3=B6nmez?= Date: Thu, 2 Jun 2005 19:12:52 +0000 Subject: [PATCH 086/245] Bump version so it actually works svn path=/trunk/KDE/kdegraphics/kpdf/; revision=421328 --- part.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/part.rc b/part.rc index b1352ce61..92d8ed6a6 100644 --- a/part.rc +++ b/part.rc @@ -1,5 +1,5 @@ - + &File From d599aebde916b37bbeff23f2c8dcfc805e32666f Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 2 Jun 2005 19:38:55 +0000 Subject: [PATCH 087/245] don't crash when clicking on [+] svn path=/trunk/KDE/kdegraphics/kpdf/; revision=421335 --- ui/toc.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/toc.cpp b/ui/toc.cpp index 5fb8e5653..9f20bcca7 100644 --- a/ui/toc.cpp +++ b/ui/toc.cpp @@ -120,7 +120,11 @@ void TOC::addChildren( const QDomNode & parentNode, KListViewItem * parentItem ) void TOC::slotExecuted( QListViewItem *i ) { - const QDomElement & e = static_cast< TOCItem* >( i )->element(); + TOCItem* tocItem = dynamic_cast( i ); + // that filters clicks on [+] that for a strange reason don't seem to be TOCItem* + if (tocItem == NULL) + return; + const QDomElement & e = tocItem->element(); if ( e.hasAttribute( "Viewport" ) ) { // if the node has a viewport, set it From 66c71c3c72ed970745de7d2c963f6a71e2aa58d9 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 3 Jun 2005 16:09:36 +0000 Subject: [PATCH 088/245] Q3MemArray -> QVector Fix almost all presentation mode svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=421637 --- core/page.cpp | 9 ++++----- ui/pageview.cpp | 9 ++++----- ui/presentationwidget.cpp | 38 ++++++++++++++++++++++---------------- ui/presentationwidget.h | 4 ++-- ui/toc.cpp | 4 ++-- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/core/page.cpp b/core/page.cpp index 8d0da0953..fe3b67b22 100644 --- a/core/page.cpp +++ b/core/page.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include // local includes @@ -111,7 +110,7 @@ NormalizedRect * KPDFPage::findText( const QString & text, bool strictCase, Norm // create a xpf's Unicode (unsigned int) array for the given text const QChar * str = text.unicode(); int len = text.length(); - Q3MemArray u(len); + QVector u(len); for (int i = 0; i < len; ++i) u[i] = str[i].unicode(); @@ -131,12 +130,12 @@ NormalizedRect * KPDFPage::findText( const QString & text, bool strictCase, Norm while ( !found ) { if ( dir == FromTop ) - found = m_text->findText( const_cast(static_cast(u)), len, gTrue, gTrue, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom ); + found = m_text->findText( u.data(), len, gTrue, gTrue, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom ); else if ( dir == NextMatch ) - found = m_text->findText( const_cast(static_cast(u)), len, gFalse, gTrue, gTrue, gFalse, &sLeft, &sTop, &sRight, &sBottom ); + found = m_text->findText( u.data(), len, gFalse, gTrue, gTrue, gFalse, &sLeft, &sTop, &sRight, &sBottom ); else if ( dir == PrevMatch ) // FIXME: this doesn't work as expected (luckily backward search isn't yet used) - found = m_text->findText( const_cast(static_cast(u)), len, gTrue, gFalse, gFalse, gTrue, &sLeft, &sTop, &sRight, &sBottom ); + found = m_text->findText( u.data(), len, gTrue, gFalse, gFalse, gTrue, &sLeft, &sTop, &sRight, &sBottom ); // if not found (even in case unsensitive search), terminate if ( !found ) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 9aae6f2b9..895153d6a 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -17,7 +17,6 @@ ***************************************************************************/ // qt/kde includes -#include #include #include #include @@ -450,7 +449,7 @@ void PageView::viewportPaintEvent( QPaintEvent * pe ) d->selectionRectColor : Qt::red; // subdivide region into rects - Q3MemArray allRects = pe->region().rects(); + QVector allRects = pe->region().rects(); uint numRects = allRects.count(); // preprocess rects area to see if it worths or not using subdivision @@ -1255,7 +1254,7 @@ void PageView::paintItems( QPainter * p, const QRect & contentsRect ) } // paint with background color the unpainted area - Q3MemArray backRects = remainingArea.rects(); + QVector backRects = remainingArea.rects(); uint backRectsNumber = backRects.count(); for ( uint jr = 0; jr < backRectsNumber; jr++ ) p->fillRect( backRects[ jr ], Qt::gray ); @@ -1348,8 +1347,8 @@ void PageView::selectionEndPoint( int x, int y ) compoundRegion -= intersection; } // tassellate region with rects and enqueue paint events - Q3MemArray rects = compoundRegion.rects(); - for ( uint i = 0; i < rects.count(); i++ ) + QVector rects = compoundRegion.rects(); + for ( int i = 0; i < rects.count(); i++ ) updateContents( rects[i] ); } } diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index 50f34ef26..85b466133 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -8,9 +8,9 @@ ***************************************************************************/ // qt/kde includes -#include #include #include +#include #include #include #include @@ -51,7 +51,7 @@ struct PresentationFrame PresentationWidget::PresentationWidget( QWidget * parent, KPDFDocument * doc ) - : QDialog( parent, "presentationWidget", true, Qt::WDestructiveClose | Qt::WStyle_NoBorder), m_document( doc ), m_frameIndex( -1 ) + : QDialog( parent, "presentationWidget", true, Qt::WDestructiveClose), m_document( doc ), m_frameIndex( -1 ) { // set look and geometry setBackgroundMode( Qt::NoBackground ); @@ -260,15 +260,17 @@ void PresentationWidget::paintEvent( QPaintEvent * pe ) m_width = d.width(); m_height = d.height(); + KIconLoader *il = KGlobal::iconLoader(); + // create top toolbar - m_topBar = new KToolBar( this, "presentationBar" ); - m_topBar->setIconSize( 32 ); - m_topBar->setMovingEnabled( false ); - m_topBar->insertButton( "1leftarrow", 2, SIGNAL( clicked() ), this, SLOT( slotPrevPage() ) ); - m_topBar->insertButton( "1rightarrow", 3, SIGNAL( clicked() ), this, SLOT( slotNextPage() ) ); - m_topBar->insertButton( "exit", 1, SIGNAL( clicked() ), this, SLOT( close() ) ); + m_topBar = new QToolBar( this ); + m_topBar->addAction( QIcon(il->loadIcon("1leftarrow", KIcon::Toolbar)), i18n("Previous Page"), this, SLOT( slotPrevPage() ) ); + m_topBar->addAction( QIcon(il->loadIcon("1rightarrow", KIcon::Toolbar)), i18n("Next Page"), this, SLOT( slotNextPage() ) ); + QWidget *spacer = new QWidget(m_topBar); + spacer->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ); + m_topBar->addWidget( spacer ); + m_topBar->addAction( QIcon(il->loadIcon("exit", KIcon::Toolbar)), i18n("Exit Presentation Mode"), this, SLOT( close() ) ); m_topBar->setGeometry( 0, 0, m_width, 32 + 10 ); - m_topBar->alignItemRight( 1 ); m_topBar->hide(); // change topbar background color QPalette p = m_topBar->palette(); @@ -292,7 +294,7 @@ void PresentationWidget::paintEvent( QPaintEvent * pe ) return; // blit the pixmap to the screen - Q3MemArray allRects = pe->region().rects(); + QVector allRects = pe->region().rects(); uint numRects = allRects.count(); for ( uint i = 0; i < numRects; i++ ) { @@ -317,11 +319,15 @@ void PresentationWidget::paintEvent( QPaintEvent * pe ) // finally blit the pixmap to the screen pixPainter.end(); - bitBlt( this, r.topLeft(), &backPixmap, backPixmap.rect() ); + QPainter p(this); + p.drawPixmap(r.topLeft(), backPixmap ); } else #endif + { // copy the rendered pixmap to the screen - bitBlt( this, r.topLeft(), &m_lastRenderedPixmap, r ); + QPainter p(this); + p.drawPixmap(r.topLeft(), m_lastRenderedPixmap, r ); + } } } // @@ -471,7 +477,7 @@ void PresentationWidget::generateContentsPage( int pageNum, QPainter & p ) // fill unpainted areas with background color QRegion unpainted( QRect( 0, 0, m_width, m_height ) ); - Q3MemArray rects = unpainted.subtract( frame->geometry ).rects(); + QVector rects = unpainted.subtract( frame->geometry ).rects(); for ( uint i = 0; i < rects.count(); i++ ) { const QRect & r = rects[i]; @@ -502,10 +508,10 @@ void PresentationWidget::generateOverlay() { // draw continuous slices int degrees = (int)( 360 * (float)(m_frameIndex + 1) / (float)pages ); pixmapPainter.setPen( 0x20 ); -#warning QPainter.setBtush(0x10) ???? port this +#warning QPainter.setBrush(0x10) ???? port this // pixmapPainter.setBrush( 0x10 ); pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, (360-degrees)*16 ); -#warning QPainter.setBtush(0xC0) ???? port this +#warning QPainter.setBrush(0xC0) ???? port this // pixmapPainter.setBrush( 0xC0 ); pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, -degrees*16 ); } @@ -516,7 +522,7 @@ void PresentationWidget::generateOverlay() { float newCoord = -90 + 360 * (float)(i + 1) / (float)pages; pixmapPainter.setPen( i <= m_frameIndex ? 0x40 : 0x05 ); -#warning QPainter.setBtush(0xC0) ???? port this +#warning QPainter.setBrush(0xC0) ???? port this // pixmapPainter.setBrush( i <= m_frameIndex ? 0xC0 : 0x10 ); pixmapPainter.drawPie( 2, 2, side - 4, side - 4, (int)( -16*(oldCoord + 1) ), (int)( -16*(newCoord - (oldCoord + 2)) ) ); diff --git a/ui/presentationwidget.h b/ui/presentationwidget.h index 2373c3d29..24ddc1f46 100644 --- a/ui/presentationwidget.h +++ b/ui/presentationwidget.h @@ -17,7 +17,7 @@ #include "core/observer.h" #include "core/pagetransition.h" -class KToolBar; +class QToolBar; class QTimer; class KPDFDocument; @@ -82,7 +82,7 @@ class PresentationWidget : public QDialog, public DocumentObserver QVector< PresentationFrame * > m_frames; int m_frameIndex; QStringList m_metaStrings; - KToolBar * m_topBar; + QToolBar * m_topBar; private slots: void slotNextPage(); diff --git a/ui/toc.cpp b/ui/toc.cpp index 2387d8800..b53161daf 100644 --- a/ui/toc.cpp +++ b/ui/toc.cpp @@ -63,8 +63,8 @@ TOC::TOC(QWidget *parent, KPDFDocument *document) : KListView(parent), m_documen setRootIsDecorated(true); setResizeMode(AllColumns); setAllColumnsShowFocus(true); - connect(this, SIGNAL(clicked(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *))); - connect(this, SIGNAL(returnPressed(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *))); + connect(this, SIGNAL(clicked(Q3ListViewItem *)), this, SLOT(slotExecuted(Q3ListViewItem *))); + connect(this, SIGNAL(returnPressed(Q3ListViewItem *)), this, SLOT(slotExecuted(Q3ListViewItem *))); } uint TOC::observerId() const From 12e6eefcfe7397dd9fa5e2f30fdd9b465c78d1fd Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 3 Jun 2005 17:38:20 +0000 Subject: [PATCH 089/245] revert fix for 106546 was causing other problems svn path=/trunk/KDE/kdegraphics/kpdf/; revision=421672 --- ui/pageview.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index f076cfe73..def51773f 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -588,14 +588,18 @@ void PageView::keyPressEvent( QKeyEvent * e ) { // part doesn't get this key event because of the keyboard grab d->findTimeoutTimer->stop(); // restore normal operation during possible messagebox is displayed - //commenting as seems to cause bug 106546 and does not seem to give anything - //releaseKeyboard(); + // it is needed to grab the keyboard becase people may have Space assigned to a + // accel and without grabbing the keyboard you can not vim-search for space + // because it activates the accel + releaseKeyboard(); if ( d->document->continueSearch( PAGEVIEW_SEARCH_ID ) ) d->messageWindow->display( i18n("Text found: \"%1\".").arg(d->typeAheadString.lower()), PageViewMessage::Find, 3000 ); d->findTimeoutTimer->start( 3000, true ); - //commenting as seems to cause bug 106546 and does not seem to give anything - // grabKeyboard(); + // it is needed to grab the keyboard becase people may have Space assigned to a + // accel and without grabbing the keyboard you can not vim-search for space + // because it activates the accel + grabKeyboard(); } // esc and return: end search else if( e->key() == Key_Escape || e->key() == Key_Return ) @@ -634,8 +638,10 @@ void PageView::keyPressEvent( QKeyEvent * e ) connect( d->findTimeoutTimer, SIGNAL( timeout() ), this, SLOT( findAheadStop() ) ); } d->findTimeoutTimer->start( 3000, true ); - //commenting as seems to cause bug 106546 and does not seem to give anything - // grabKeyboard(); + // it is needed to grab the keyboard becase people may have Space assigned to a + // accel and without grabbing the keyboard you can not vim-search for space + // because it activates the accel + grabKeyboard(); return; } @@ -1848,8 +1854,10 @@ void PageView::findAheadStop() d->typeAheadActive = false; d->typeAheadString = ""; d->messageWindow->display( i18n("Find stopped."), PageViewMessage::Find, 1000 ); - //commenting as seems to cause bug 106546 and does not seem to give anything - //releaseKeyboard(); + // it is needed to grab the keyboard becase people may have Space assigned to a + // accel and without grabbing the keyboard you can not vim-search for space + // because it activates the accel + releaseKeyboard(); } void PageView::slotZoom() From 37f510a31122b2a42dd3500b747b26fd870318ca Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 4 Jun 2005 10:30:55 +0000 Subject: [PATCH 090/245] Fix crash on documents like the one on 106767, we must not check for a imagelink if we found a normal link that points to another document because the imagelink does not exists anymore, this was not present on 3.4 but yes on 3.4.1, backporting on a moment Fix bug on 106767, need to relayout the pages when opening a document Enrico please check that both things are "correct" and if they are remove the TODO i added for you ;-) BUGS: 106767 CCMAIL: rosenric@dei.unipd.it svn path=/trunk/KDE/kdegraphics/kpdf/; revision=422023 --- part.rc | 1 + ui/pageview.cpp | 30 ++++++++++++++++++------------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/part.rc b/part.rc index 92d8ed6a6..a09419e8a 100644 --- a/part.rc +++ b/part.rc @@ -15,6 +15,7 @@ + diff --git a/ui/pageview.cpp b/ui/pageview.cpp index def51773f..97aa9c6be 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -263,9 +263,13 @@ void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool doc for ( ; setIt != setEnd; ++setIt ) d->items.push_back( new PageViewItem( *setIt ) ); - // invalidate layout so relayout/repaint will happen on next viewport change if ( pageSet.count() > 0 ) - d->dirtyLayout = true; + // TODO for Enrico: Check if doing always the slotRelayoutPages() is not + // suboptimal in some cases, i'd say it is not but a recheck will not hurt + // Need slotRelayoutPages() here instead of d->dirtyLayout = true + // because opening a pdf from another pdf will not trigger a viewportchange + // so pages are never relayouted + slotRelayoutPages(); else resizeContents( 0, 0 ); @@ -904,17 +908,19 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) const KPDFLink * link = static_cast< const KPDFLink * >( linkRect->pointer() ); d->document->processLink( link ); } - - imageRect = pageItem->page()->hasObject( ObjectRect::Image, nX, nY ); - if ( imageRect ) - { - // handle click over a image - } - - if (!linkRect && !imageRect) + else { - // if not on a rect, the click selects the page - d->document->setViewportPage( pageItem->pageNumber(), PAGEVIEW_ID ); + // a link can move us to another page or even to another document, there's no point in trying to process the click on the image once we have processes the click on the link + imageRect = pageItem->page()->hasObject( ObjectRect::Image, nX, nY ); + if ( imageRect ) + { + // handle click over a image + } + else + { + // if not on a rect, the click selects the page + d->document->setViewportPage( pageItem->pageNumber(), PAGEVIEW_ID ); + } } } else if ( rightButton ) From e2cdb1ca6c4aa2b254eddfaf1f90b06f25736634 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 4 Jun 2005 10:31:47 +0000 Subject: [PATCH 091/245] This was not supposed to go in, grrrrrrr svn path=/trunk/KDE/kdegraphics/kpdf/; revision=422024 --- part.rc | 1 - 1 file changed, 1 deletion(-) diff --git a/part.rc b/part.rc index a09419e8a..92d8ed6a6 100644 --- a/part.rc +++ b/part.rc @@ -15,7 +15,6 @@ - From 108cc456a8088379a58f22b6cfccc36c9194c039 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 4 Jun 2005 13:35:02 +0000 Subject: [PATCH 092/245] fix usability issues 1.8 and 3.3 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=422082 --- part.rc | 5 +++-- ui/pageview.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/part.rc b/part.rc index 92d8ed6a6..416d5c295 100644 --- a/part.rc +++ b/part.rc @@ -53,8 +53,9 @@ - - + + + diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 97aa9c6be..66e320cf8 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -179,16 +179,17 @@ void PageView::setupActions( KActionCollection * ac ) // Zoom actions ( higher scales takes lots of memory! ) d->aZoom = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, this, SLOT( slotZoom() ), ac, "zoom_to" ); d->aZoom->setEditable( true ); + d->aZoom->setMaxComboViewCount( 13 ); updateZoomText(); KStdAction::zoomIn( this, SLOT( slotZoomIn() ), ac, "zoom_in" ); KStdAction::zoomOut( this, SLOT( slotZoomOut() ), ac, "zoom_out" ); - d->aZoomFitWidth = new KToggleAction( i18n("Fit to Page &Width"), "viewmagfit", 0, ac, "zoom_fit_width" ); + d->aZoomFitWidth = new KToggleAction( i18n("Fit to Page &Width"), "view_fit_width", 0, ac, "zoom_fit_width" ); connect( d->aZoomFitWidth, SIGNAL( toggled( bool ) ), SLOT( slotFitToWidthToggled( bool ) ) ); - d->aZoomFitPage = new KToggleAction( i18n("Fit to &Page"), "viewmagfit", 0, ac, "zoom_fit_page" ); + d->aZoomFitPage = new KToggleAction( i18n("Fit to &Page"), "view_fit_window", 0, ac, "zoom_fit_page" ); connect( d->aZoomFitPage, SIGNAL( toggled( bool ) ), SLOT( slotFitToPageToggled( bool ) ) ); d->aZoomFitText = new KToggleAction( i18n("Fit to &Text"), "viewmagfit", 0, ac, "zoom_fit_text" ); From 5c4ae71cdeeda8aa65cd8861b49b4606d5ef4487 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 4 Jun 2005 13:57:20 +0000 Subject: [PATCH 093/245] syncing with the commit coolo made to branch saying something about fixing complation on gcc 4.0.1 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=422092 --- xpdf/xpdf/TextOutputDev.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/xpdf/xpdf/TextOutputDev.h b/xpdf/xpdf/TextOutputDev.h index 80f692273..5e8b49a09 100644 --- a/xpdf/xpdf/TextOutputDev.h +++ b/xpdf/xpdf/TextOutputDev.h @@ -25,6 +25,8 @@ class GList; class GfxFont; class GfxState; class UnicodeMap; +class TextBlock; +class TextPage; class TextLineFrag; //------------------------------------------------------------------------ @@ -167,8 +169,6 @@ private: // TextLine //------------------------------------------------------------------------ -class TextBlock; - class TextLine { public: @@ -226,8 +226,6 @@ private: // TextBlock //------------------------------------------------------------------------ -class TextPage; - class TextBlock { public: From a867c64ef71adb6128e20444e856d4979e255baa Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 5 Jun 2005 11:26:07 +0000 Subject: [PATCH 094/245] qimage generator is working again but seems kimgio is not plugging correctly the plugins svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=422396 --- core/Makefile.am | 4 ++-- core/document.cpp | 18 +++++++++--------- core/generator_kimgio/generator_kimgio.cpp | 2 +- core/generator_kimgio/generator_kimgio.h | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core/Makefile.am b/core/Makefile.am index c49b58eec..74c774855 100644 --- a/core/Makefile.am +++ b/core/Makefile.am @@ -1,10 +1,10 @@ -SUBDIRS = generator_pdf # generator_kimgio +SUBDIRS = generator_pdf generator_kimgio INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(srcdir)/../xpdf -I$(srcdir)/../xpdf/goo -I$(top_builddir)/kpdf $(all_includes) METASOURCES = AUTO -libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la # ./generator_kimgio/libgeneratorkimgio.la +libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la ./generator_kimgio/libgeneratorkimgio.la libkpdfcore_la_SOURCES = document.cpp link.cpp page.cpp pagetransition.cpp noinst_LTLIBRARIES = libkpdfcore.la diff --git a/core/document.cpp b/core/document.cpp index 2cc1a9982..9b9c1e92c 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,7 @@ #include "page.h" #include "link.h" #include "generator_pdf/generator_pdf.h" // PDF generator -//#include "generator_kimgio/generator_kimgio.h" // KIMGIO generator +#include "generator_kimgio/generator_kimgio.h" // KIMGIO generator #include "conf/settings.h" // structures used internally by KPDFDocument for local variables storage @@ -112,15 +113,14 @@ KPDFDocument::KPDFDocument() d->allocatedPixmapsTotalMemory = 0; d->memCheckTimer = 0; d->saveBookmarksTimer = 0; -#warning kimgio generator disabled ATM -/* KImageIO::registerFormats(); - QStringList list = QImage::inputFormatList(); - QStringList::Iterator it = list.begin(); + KImageIO::registerFormats(); + QList list = QImageReader::supportedImageFormats(); + QList::Iterator it = list.begin(); while( it != list.end() ) { - d->kimgioMimes << KMimeType::findByPath(QString("foo.%1").arg(*it), 0, true)->name(); + d->kimgioMimes << KMimeType::findByPath("foo." + QString(*it), 0, true)->name(); ++it; - }*/ + } } KPDFDocument::~KPDFDocument() @@ -156,7 +156,7 @@ bool KPDFDocument::openDocument( const QString & docFile, const KURL & url ) generator = new PDFGenerator( this ); // else if ( mimeName == "application/postscript" ) // kdError() << "PS generator not available" << endl; -/* else + else { QStringList::Iterator it = d->kimgioMimes.begin(); while( it != d->kimgioMimes.end() ) @@ -174,7 +174,7 @@ bool KPDFDocument::openDocument( const QString & docFile, const KURL & url ) kdWarning() << "Unknown mimetype '" << mime->name() << "'." << endl; return false; } - }*/ + } // 1. load Document (and set busy cursor while loading) QApplication::setOverrideCursor( Qt::waitCursor ); diff --git a/core/generator_kimgio/generator_kimgio.cpp b/core/generator_kimgio/generator_kimgio.cpp index bb7546868..46bcc7f3d 100644 --- a/core/generator_kimgio/generator_kimgio.cpp +++ b/core/generator_kimgio/generator_kimgio.cpp @@ -23,7 +23,7 @@ KIMGIOGenerator::~KIMGIOGenerator() delete m_pix; } -bool KIMGIOGenerator::loadDocument( const QString & fileName, QValueVector & pagesVector ) +bool KIMGIOGenerator::loadDocument( const QString & fileName, QVector & pagesVector ) { m_pix = new QPixmap(fileName); diff --git a/core/generator_kimgio/generator_kimgio.h b/core/generator_kimgio/generator_kimgio.h index bda411f2d..46041f0ec 100644 --- a/core/generator_kimgio/generator_kimgio.h +++ b/core/generator_kimgio/generator_kimgio.h @@ -19,7 +19,7 @@ class KIMGIOGenerator : public Generator virtual ~KIMGIOGenerator(); // [INHERITED] load a document and fill up the pagesVector - bool loadDocument( const QString & fileName, QValueVector & pagesVector ); + bool loadDocument( const QString & fileName, QVector & pagesVector ); // [INHERITED] perform actions on document / pages bool canGeneratePixmap(); From 18402fb87189d6a1b5892614aed9172781ccb8ea Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 5 Jun 2005 11:43:20 +0000 Subject: [PATCH 095/245] atEnd() on /proc files don't seem to work svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=422402 --- core/document.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 9b9c1e92c..ea51331b8 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -1218,9 +1218,8 @@ int KPDFDocument::getTotalMemory() int KPDFDocument::getFreeMemory() { -#warning this hangs, check why -#if 0 -//#ifdef __linux__ +#warning seems this is a bit slow on qt4 check performance vs qt3 +#ifdef __linux__ // if /proc/meminfo doesn't exist, return MEMORY FULL QFile memFile( "/proc/meminfo" ); if ( !memFile.open( IO_ReadOnly ) ) @@ -1231,9 +1230,10 @@ int KPDFDocument::getFreeMemory() int memoryFree = 0; QString entry; QTextStream readStream( &memFile ); - while ( !readStream.atEnd() ) + while ( true ) { entry = readStream.readLine(); + if ( entry.isNull() ) break; if ( entry.startsWith( "MemFree:" ) || entry.startsWith( "Buffers:" ) || entry.startsWith( "Cached:" ) || From d8fe1a9ecb743b3721a238c2989318b2832a1627 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 5 Jun 2005 11:54:31 +0000 Subject: [PATCH 096/245] fix call to kprinter svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=422403 --- core/generator_pdf/generator_pdf.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index f28d172ff..0e06c155d 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -453,8 +453,7 @@ bool PDFGenerator::print( KPrinter& printer ) // needs to be here so that the file is flushed, do not merge with the one // in the else delete psOut; -#warning K/QPrinter changed - //printer.printFiles(tf.name(), true); + printer.printFiles(QStringList(tf.name()), true); return true; } else From 71f275a6c6dfef58aeffb0ce572a1e89d906b9c4 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 6 Jun 2005 16:22:14 +0000 Subject: [PATCH 097/245] build a bit more svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=422830 --- ui/pageview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index b0b388648..e3894fb7f 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -180,6 +180,7 @@ void PageView::setupActions( KActionCollection * ac ) // Zoom actions ( higher scales takes lots of memory! ) d->aZoom = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, this, SLOT( slotZoom() ), ac, "zoom_to" ); d->aZoom->setEditable( true ); + d->aZoom->setMaxComboViewCount( 13 ); updateZoomText(); KStdAction::zoomIn( this, SLOT( slotZoomIn() ), ac, "zoom_in" ); From 3b246afb3ef3c1ef72ee5ee7039d330aa8025d87 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 6 Jun 2005 21:06:58 +0000 Subject: [PATCH 098/245] Fix bug 106771 BUGS: 106771 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=422907 --- part.cpp | 18 +++++++++++++++--- part.h | 4 ++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/part.cpp b/part.cpp index 728543a83..907ba8bbc 100644 --- a/part.cpp +++ b/part.cpp @@ -80,13 +80,13 @@ Part::Part(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const QStringList & /*args*/ ) : DCOPObject("kpdf"), KParts::ReadOnlyPart(parent, name), m_showMenuBarAction(0), m_showFullScreenAction(0), - m_actionsSearched(false), m_searchStarted(false) + m_actionsSearched(false), m_searchStarted(false), m_notifyOpening(false) { // load catalog for translation KGlobal::locale()->insertCatalogue("kpdf"); // create browser extension (for printing when embedded into browser) - new BrowserExtension(this); + m_bExtension = new BrowserExtension(this); // xpdf 'extern' global class (m_count is a static instance counter) //if ( m_count ) TODO check if we need to insert these lines.. @@ -102,7 +102,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_document = new KPDFDocument(); connect( m_document, SIGNAL( linkFind() ), this, SLOT( slotFind() ) ); connect( m_document, SIGNAL( linkGoToPage() ), this, SLOT( slotGoToPage() ) ); - connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURL(const KURL &) ) ); + connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURLFromDocument(const KURL &) ) ); // widgets: ^searchbar (toolbar containing label and SearchWidget) // m_searchToolBar = new KToolBar( parentWidget, "searchBar" ); @@ -367,6 +367,12 @@ bool Part::openFile() return true; } +void Part::openURLFromDocument(const KURL &url) +{ + m_notifyOpening = true; + openURL(url); +} + bool Part::openURL(const KURL &url) { // note: this can be the right place to check the file for gz or bz2 extension @@ -375,6 +381,12 @@ bool Part::openURL(const KURL &url) // this calls the above 'openURL' method bool b = KParts::ReadOnlyPart::openURL(url); + if (m_notifyOpening) + { + m_bExtension->openURLNotify(); + m_bExtension->setLocationBarURL(url.prettyURL()); + m_notifyOpening = false; + } if ( !b ) KMessageBox::error( widget(), i18n("Could not open %1").arg( url.prettyURL() ) ); else diff --git a/part.h b/part.h index 74e221101..f05ebdcb5 100644 --- a/part.h +++ b/part.h @@ -106,6 +106,8 @@ protected slots: // can be connected to widget elements void updateViewActions(); void enableTOC(bool enable); + + void openURLFromDocument(const KURL &url); public slots: // connected to Shell action (and browserExtension), not local one @@ -156,6 +158,8 @@ private: KToggleAction* m_showFullScreenAction; bool m_actionsSearched; bool m_searchStarted; + BrowserExtension *m_bExtension; + bool m_notifyOpening; }; From a81eb09c3dfa37a276d2ba21454f6090e0be2acf Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 22 Jun 2005 19:27:45 +0000 Subject: [PATCH 099/245] always notify the shell we've opened a new url, fixes comment #4 from 106771 CCMAIL: 106771 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=428028 --- part.cpp | 18 ++++-------------- part.h | 3 --- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/part.cpp b/part.cpp index 907ba8bbc..ee4a7e87d 100644 --- a/part.cpp +++ b/part.cpp @@ -80,7 +80,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const QStringList & /*args*/ ) : DCOPObject("kpdf"), KParts::ReadOnlyPart(parent, name), m_showMenuBarAction(0), m_showFullScreenAction(0), - m_actionsSearched(false), m_searchStarted(false), m_notifyOpening(false) + m_actionsSearched(false), m_searchStarted(false) { // load catalog for translation KGlobal::locale()->insertCatalogue("kpdf"); @@ -102,7 +102,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_document = new KPDFDocument(); connect( m_document, SIGNAL( linkFind() ), this, SLOT( slotFind() ) ); connect( m_document, SIGNAL( linkGoToPage() ), this, SLOT( slotGoToPage() ) ); - connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURLFromDocument(const KURL &) ) ); + connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURL(const KURL &) ) ); // widgets: ^searchbar (toolbar containing label and SearchWidget) // m_searchToolBar = new KToolBar( parentWidget, "searchBar" ); @@ -367,12 +367,6 @@ bool Part::openFile() return true; } -void Part::openURLFromDocument(const KURL &url) -{ - m_notifyOpening = true; - openURL(url); -} - bool Part::openURL(const KURL &url) { // note: this can be the right place to check the file for gz or bz2 extension @@ -381,12 +375,8 @@ bool Part::openURL(const KURL &url) // this calls the above 'openURL' method bool b = KParts::ReadOnlyPart::openURL(url); - if (m_notifyOpening) - { - m_bExtension->openURLNotify(); - m_bExtension->setLocationBarURL(url.prettyURL()); - m_notifyOpening = false; - } + m_bExtension->openURLNotify(); + m_bExtension->setLocationBarURL(url.prettyURL()); if ( !b ) KMessageBox::error( widget(), i18n("Could not open %1").arg( url.prettyURL() ) ); else diff --git a/part.h b/part.h index f05ebdcb5..e8cf9b4f3 100644 --- a/part.h +++ b/part.h @@ -106,8 +106,6 @@ protected slots: // can be connected to widget elements void updateViewActions(); void enableTOC(bool enable); - - void openURLFromDocument(const KURL &url); public slots: // connected to Shell action (and browserExtension), not local one @@ -159,7 +157,6 @@ private: bool m_actionsSearched; bool m_searchStarted; BrowserExtension *m_bExtension; - bool m_notifyOpening; }; From c099383be4a6f03bc4fb628060fc91fd6d7d8c50 Mon Sep 17 00:00:00 2001 From: Script Kiddy Date: Thu, 23 Jun 2005 04:06:12 +0000 Subject: [PATCH 100/245] SVN_SILENT made messages (.desktop file) svn path=/trunk/KDE/kdegraphics/kpdf/; revision=428099 --- shell/kpdf.desktop | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/kpdf.desktop b/shell/kpdf.desktop index c0fd505c8..cd9f0fdb5 100644 --- a/shell/kpdf.desktop +++ b/shell/kpdf.desktop @@ -24,7 +24,6 @@ GenericName[et]=PDF failide vaataja GenericName[eu]=PDF ikustailua GenericName[fi]=PDF-näytin GenericName[fr]=Afficheur PDF -GenericName[ga]=Amharcán PDF GenericName[gl]=Visor PDF GenericName[he]=מציג PDF GenericName[hi]=पीडीà¤à¤« पà¥à¤°à¤¦à¤°à¥à¤¶à¤• From 67f091df4888b2130fb179ea3664bc8cb4a8e1b5 Mon Sep 17 00:00:00 2001 From: Script Kiddy Date: Fri, 24 Jun 2005 04:14:32 +0000 Subject: [PATCH 101/245] SVN_SILENT made messages (.desktop file) svn path=/trunk/KDE/kdegraphics/kpdf/; revision=428428 --- shell/kpdf.desktop | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/kpdf.desktop b/shell/kpdf.desktop index cd9f0fdb5..c0fd505c8 100644 --- a/shell/kpdf.desktop +++ b/shell/kpdf.desktop @@ -24,6 +24,7 @@ GenericName[et]=PDF failide vaataja GenericName[eu]=PDF ikustailua GenericName[fi]=PDF-näytin GenericName[fr]=Afficheur PDF +GenericName[ga]=Amharcán PDF GenericName[gl]=Visor PDF GenericName[he]=מציג PDF GenericName[hi]=पीडीà¤à¤« पà¥à¤°à¤¦à¤°à¥à¤¶à¤• From f241e05db84af7d4fbbffe14943bc76bc0f31492 Mon Sep 17 00:00:00 2001 From: Tobias Koenig Date: Mon, 27 Jun 2005 20:37:54 +0000 Subject: [PATCH 102/245] Add possibility to go to an external pdf document from the TOC. svn path=/trunk/KDE/kdegraphics/kpdf/; revision=429479 --- core/generator_pdf/generator_pdf.cpp | 11 +++++++++++ ui/toc.cpp | 29 +++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 1497d71a6..14bece476 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -806,6 +806,17 @@ void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items ) item.setAttribute( "Viewport", DocumentViewport( pageNumber ).toString() ); } } + else if ( a && a->getKind() == actionGoToR ) + { + LinkGoToR * g = static_cast< LinkGoToR * >( a ); + LinkDest * destination = g->getDest(); + if ( !destination && g->getNamedDest() ) + { + item.setAttribute( "ViewportName", g->getNamedDest()->getCString() ); + } + + item.setAttribute( "ExternalFileName", g->getFileName()->getCString() ); + } // 3. recursively descend over children outlineItem->open(); diff --git a/ui/toc.cpp b/ui/toc.cpp index 9f20bcca7..e6bcafce6 100644 --- a/ui/toc.cpp +++ b/ui/toc.cpp @@ -14,6 +14,7 @@ // local includes #include "toc.h" #include "core/document.h" +#include "core/link.h" #include "core/page.h" // uncomment following to enable a 2nd column showing the page referred @@ -125,18 +126,28 @@ void TOC::slotExecuted( QListViewItem *i ) if (tocItem == NULL) return; const QDomElement & e = tocItem->element(); - if ( e.hasAttribute( "Viewport" ) ) + + QString externalFileName = e.attribute( "ExternalFileName" ); + if ( !externalFileName.isEmpty() ) { - // if the node has a viewport, set it - m_document->setViewport( DocumentViewport( e.attribute( "Viewport" ) ), TOC_ID ); + KPDFLinkGoto link( externalFileName, DocumentViewport() ); + m_document->processLink( &link ); } - else if ( e.hasAttribute( "ViewportName" ) ) + else { - // if the node references a viewport, get the reference and set it - const QString & page = e.attribute( "ViewportName" ); - const QString & viewport = m_document->getMetaData( "NamedViewport", page ); - if ( !viewport.isNull() ) - m_document->setViewport( DocumentViewport( viewport ), TOC_ID ); + if ( e.hasAttribute( "Viewport" ) ) + { + // if the node has a viewport, set it + m_document->setViewport( DocumentViewport( e.attribute( "Viewport" ) ), TOC_ID ); + } + else if ( e.hasAttribute( "ViewportName" ) ) + { + // if the node references a viewport, get the reference and set it + const QString & page = e.attribute( "ViewportName" ); + const QString & viewport = m_document->getMetaData( "NamedViewport", page ); + if ( !viewport.isNull() ) + m_document->setViewport( DocumentViewport( viewport ), TOC_ID ); + } } } From d80b0b6e0e251abf2bd36a939e563e0f7c7a2eb5 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 27 Jun 2005 21:55:59 +0000 Subject: [PATCH 103/245] =?UTF-8?q?Patch=20i=20got=20from=20Thomas=20L?= =?UTF-8?q?=C3=BCbking=20=20to=20fix=20rendering?= =?UTF-8?q?=20for=20brainded=20styles=20like=20baghira,=20tested=20it=20an?= =?UTF-8?q?d=20woked,=20thanks=20:-)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit svn path=/trunk/KDE/kdegraphics/kpdf/; revision=429506 --- ui/pageviewutils.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/pageviewutils.cpp b/ui/pageviewutils.cpp index 09cbf94b5..627e84d37 100644 --- a/ui/pageviewutils.cpp +++ b/ui/pageviewutils.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,7 @@ PageViewMessage::PageViewMessage( QWidget * parent ) { setFocusPolicy( NoFocus ); setBackgroundMode( NoBackground ); + setPaletteBackgroundColor(kapp->palette().color(QPalette::Active, QColorGroup::Background)); move( 10, 10 ); resize( 0, 0 ); hide(); @@ -32,6 +34,7 @@ PageViewMessage::PageViewMessage( QWidget * parent ) void PageViewMessage::display( const QString & message, Icon icon, int durationMs ) // give to Caesar what Caesar owns: code taken from Amarok's osd.h/.cpp +// "redde (reddite, pl.) cesari quae sunt cesaris", just btw. ;) { if ( !Settings::showOSD() ) { @@ -89,7 +92,7 @@ void PageViewMessage::display( const QString & message, Icon icon, int durationM // draw background QPainter bufferPainter( &m_pixmap ); bufferPainter.setPen( Qt::black ); - bufferPainter.setBrush( backgroundColor() ); + bufferPainter.setBrush( paletteBackgroundColor() ); bufferPainter.drawRoundRect( geometry, 1600 / geometry.width(), 1600 / geometry.height() ); // draw icon if present @@ -98,7 +101,7 @@ void PageViewMessage::display( const QString & message, Icon icon, int durationM // draw shadow and text int yText = geometry.height() - height / 2; - bufferPainter.setPen( backgroundColor().dark( 115 ) ); + bufferPainter.setPen( paletteBackgroundColor().dark( 115 ) ); bufferPainter.drawText( 5 + textXOffset + shadowOffset, yText + 1, message ); bufferPainter.setPen( foregroundColor() ); bufferPainter.drawText( 5 + textXOffset, yText, message ); From 48bfc9caa50a116e596f61803c4d65838773efc4 Mon Sep 17 00:00:00 2001 From: Script Kiddy Date: Sat, 2 Jul 2005 04:01:18 +0000 Subject: [PATCH 104/245] SVN_SILENT made messages (.desktop file) svn path=/trunk/KDE/kdegraphics/kpdf/; revision=430651 --- shell/kpdf.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/kpdf.desktop b/shell/kpdf.desktop index c0fd505c8..71376853c 100644 --- a/shell/kpdf.desktop +++ b/shell/kpdf.desktop @@ -20,7 +20,7 @@ GenericName[de]=PDF-Betrachter GenericName[el]=ΠÏοβολέας PDF GenericName[eo]=PDF-rigardilo GenericName[es]=Visor de PDF -GenericName[et]=PDF failide vaataja +GenericName[et]=PDF-failide näitaja GenericName[eu]=PDF ikustailua GenericName[fi]=PDF-näytin GenericName[fr]=Afficheur PDF From 7ed5ae7867de42cc29233cbe84ddd65115ca3602 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 2 Jul 2005 19:32:08 +0000 Subject: [PATCH 105/245] Open PS files, NOOOOO, we have not coded generator_ps, we just use ps2pdf (if installed) and open the resulting file, results are quite acceptable in the few ps i've tried. Testing and feedback are welcome. svn path=/trunk/KDE/kdegraphics/kpdf/; revision=430941 --- part.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++++- part.h | 2 ++ shell/shell.cpp | 2 +- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/part.cpp b/part.cpp index ee4a7e87d..3fb44cb1e 100644 --- a/part.cpp +++ b/part.cpp @@ -47,9 +47,12 @@ #include #include #include +#include +#include +#include +#include #include #include -#include // local includes #include "xpdf/GlobalParams.h" @@ -332,6 +335,36 @@ KAboutData* Part::createAboutData() bool Part::openFile() { + KMimeType::Ptr mime = KMimeType::findByPath( m_file ); + if ( (*mime).is( "application/postscript" ) ) + { + QString app = KStandardDirs::findExe( "ps2pdf" ); + if ( !app.isNull() ) + { + KTempFile tf( QString::null, ".pdf" ); + if ( tf.status() == 0 ) + { + tf.close(); + m_temporaryLocalFile = tf.name(); + + KProcess *p = new KProcess; + *p << app; + *p << m_file << m_temporaryLocalFile; + m_pageView->showText(i18n("Transforming from ps to pdf..."), 0); + connect(p, SIGNAL(processExited(KProcess *)), this, SLOT(psTransformEnded())); + p -> start(); + return true; + } + } + else + { + KMessageBox::error(widget(), i18n("You don't have ps2pdf installed so kpdf can not open postscript files.")); + return false; + } + } + + m_temporaryLocalFile = QString::null; + bool ok = m_document->openDocument( m_file, url() ); // update one-time actions @@ -386,6 +419,12 @@ bool Part::openURL(const KURL &url) bool Part::closeURL() { + if (!m_temporaryLocalFile.isNull()) + { + QFile::remove( m_temporaryLocalFile ); + m_temporaryLocalFile = QString::null; + } + m_find->setEnabled( false ); m_findNext->setEnabled( false ); m_saveAs->setEnabled( false ); @@ -476,6 +515,12 @@ void Part::enableTOC(bool enable) m_toolBox->setItemEnabled(0, enable); } +void Part::psTransformEnded() +{ + m_file = m_temporaryLocalFile; + openFile(); +} + //BEGIN go to page dialog class KPDFGotoPageDialog : public KDialogBase { diff --git a/part.h b/part.h index e8cf9b4f3..0d914e3b5 100644 --- a/part.h +++ b/part.h @@ -106,6 +106,7 @@ protected slots: // can be connected to widget elements void updateViewActions(); void enableTOC(bool enable); + void psTransformEnded(); public slots: // connected to Shell action (and browserExtension), not local one @@ -120,6 +121,7 @@ private: // the document KPDFDocument * m_document; + QString m_temporaryLocalFile; // main widgets QSplitter *m_splitter; diff --git a/shell/shell.cpp b/shell/shell.cpp index 7398e7057..8104ffc4e 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -210,7 +210,7 @@ Shell::fileOpen() // this slot is called whenever the File->Open menu is selected, // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar // button is clicked - KURL url = KFileDialog::getOpenURL( QString::null, "application/pdf" );//getOpenFileName(); + KURL url = KFileDialog::getOpenURL( QString::null, "application/pdf application/postscript" );//getOpenFileName(); if (!url.isEmpty()) openURL(url); From ded2250d27257234d77c45df26d84f9c47d2629a Mon Sep 17 00:00:00 2001 From: Andrew Coles Date: Mon, 4 Jul 2005 12:52:01 +0000 Subject: [PATCH 106/245] SVN_SILENT Corrected typos. svn path=/trunk/KDE/kdegraphics/kpdf/; revision=431475 --- part.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/part.cpp b/part.cpp index 3fb44cb1e..639cbb566 100644 --- a/part.cpp +++ b/part.cpp @@ -358,7 +358,7 @@ bool Part::openFile() } else { - KMessageBox::error(widget(), i18n("You don't have ps2pdf installed so kpdf can not open postscript files.")); + KMessageBox::error(widget(), i18n("You do not have ps2pdf installed, so kpdf cannot open postscript files.")); return false; } } From 40d4f8efd7245e9785c46d3030fe9592f5618c4a Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Mon, 4 Jul 2005 20:45:44 +0000 Subject: [PATCH 107/245] update FSF address svn path=/trunk/KDE/kdegraphics/kpdf/; revision=431615 --- COPYING | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/COPYING b/COPYING index 96bdc086c..457eeb923 100644 --- a/COPYING +++ b/COPYING @@ -2,7 +2,7 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -305,7 +305,7 @@ the "copyright" line and a pointer to where the full notice is found. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail. From cc93acb143dbe01a1ae52611783d9b96411e83c0 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 4 Jul 2005 21:41:07 +0000 Subject: [PATCH 108/245] this generates more bad than good svn path=/trunk/KDE/kdegraphics/kpdf/; revision=431642 --- ui/pageview.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 66e320cf8..40a442fb3 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -917,11 +917,12 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) { // handle click over a image } - else - { + // Enrico and me have decided this is not worth the trouble it generates + // else + // { // if not on a rect, the click selects the page - d->document->setViewportPage( pageItem->pageNumber(), PAGEVIEW_ID ); - } + // d->document->setViewportPage( pageItem->pageNumber(), PAGEVIEW_ID ); + // } } } else if ( rightButton ) From 6dadfc11bf6e8c281ea5024dc74f3f724ef5f9a4 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 4 Jul 2005 21:45:42 +0000 Subject: [PATCH 109/245] This may fix #98891 i can not tell because i've never been able to reproduce it. I'm committing it to trunk (kde 3.5) and the kde 3.4 branch (so it will be in kde 3.4.2) if you can still reproduce this problem when using one of this releases please reopen this bug. BUGS: 98891 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=431645 --- xpdf/xpdf/PDFDoc.cc | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/xpdf/xpdf/PDFDoc.cc b/xpdf/xpdf/PDFDoc.cc index 16d795165..a0e992a64 100644 --- a/xpdf/xpdf/PDFDoc.cc +++ b/xpdf/xpdf/PDFDoc.cc @@ -114,7 +114,27 @@ PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { str->reset(); - + + char eof[8]; + int pos = str->getPos(); + str->setPos(7, -1); + eof[0] = str->getChar(); + eof[1] = str->getChar(); + eof[2] = str->getChar(); + eof[3] = str->getChar(); + eof[4] = str->getChar(); + eof[5] = str->getChar(); + eof[6] = str->getChar(); + eof[7] = '\0'; + if (strstr(eof, "%%EOF") == NULL) + { + error(-1, "Document does not has ending %%EOF"); + errCode = errDamaged; + return gFalse; + } + + str->setPos(pos); + // check header checkHeader(); From 65b5e0861a1eca1c440f54882a88878876373981 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 4 Jul 2005 22:25:16 +0000 Subject: [PATCH 110/245] typo fix svn path=/trunk/KDE/kdegraphics/kpdf/; revision=431662 --- xpdf/xpdf/PDFDoc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpdf/xpdf/PDFDoc.cc b/xpdf/xpdf/PDFDoc.cc index a0e992a64..efcda9533 100644 --- a/xpdf/xpdf/PDFDoc.cc +++ b/xpdf/xpdf/PDFDoc.cc @@ -128,7 +128,7 @@ GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { eof[7] = '\0'; if (strstr(eof, "%%EOF") == NULL) { - error(-1, "Document does not has ending %%EOF"); + error(-1, "Document does not have ending %%EOF"); errCode = errDamaged; return gFalse; } From eab6931e412419ae9bca7862fd2f0191b690b3c0 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 8 Jul 2005 22:27:54 +0000 Subject: [PATCH 111/245] Don't make people translate ... when it's never used svn path=/trunk/KDE/kdegraphics/kpdf/; revision=432887 --- conf/dlgperformance.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/dlgperformance.ui b/conf/dlgperformance.ui index 3ebb055b6..c0c90eb18 100644 --- a/conf/dlgperformance.ui +++ b/conf/dlgperformance.ui @@ -133,7 +133,7 @@ descLabel - ... + PlainText From 23a06294e45c94e01e571b90dbf8283e1ff2257f Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 10 Jul 2005 20:06:55 +0000 Subject: [PATCH 112/245] Transform -> Convert svn path=/trunk/KDE/kdegraphics/kpdf/; revision=433429 --- part.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/part.cpp b/part.cpp index 639cbb566..5aab591e7 100644 --- a/part.cpp +++ b/part.cpp @@ -350,7 +350,7 @@ bool Part::openFile() KProcess *p = new KProcess; *p << app; *p << m_file << m_temporaryLocalFile; - m_pageView->showText(i18n("Transforming from ps to pdf..."), 0); + m_pageView->showText(i18n("Converting from ps to pdf..."), 0); connect(p, SIGNAL(processExited(KProcess *)), this, SLOT(psTransformEnded())); p -> start(); return true; From 03786e5ca8c4ba696e2b80c9307056da4a0c1317 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 13 Jul 2005 22:49:14 +0000 Subject: [PATCH 113/245] Same fix for bug 109015 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=434395 --- xpdf/xpdf/Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am index 1271b746f..58c4e4d92 100644 --- a/xpdf/xpdf/Makefile.am +++ b/xpdf/xpdf/Makefile.am @@ -12,3 +12,7 @@ libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ TextOutputDev.cc UnicodeMap.cc UnicodeTypeTable.cc XRef.cc noinst_LTLIBRARIES = libxpdf.la +# This fixes crash in Bug 109015 which i assume is a compiler bug +# as adding some correctly placed printf in SplashOutputDev::convertPath() makes this +# option unneeded +KDE_CXXFLAGS=-fno-regmove From 2a241c8f0826482c3733d1f89cbb91b97cf180d6 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 14 Jul 2005 11:32:33 +0000 Subject: [PATCH 114/245] Work on non-gcc compilers svn path=/trunk/KDE/kdegraphics/kpdf/; revision=434498 --- configure.in.in | 2 ++ xpdf/xpdf/Makefile.am | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/configure.in.in b/configure.in.in index 9aec65c15..ae671ac5e 100644 --- a/configure.in.in +++ b/configure.in.in @@ -119,3 +119,5 @@ AC_ARG_ENABLE(force-kpdf-drm, , AC_DEFINE(KPDF_FORCE_DRM, 0, [Defines if force the use DRM in kpdf]) ) +KDE_CHECK_COMPILER_FLAG([fno-regmove], SUPPORTS_NOREGMOVE=true, SUPPORTS_NOREGMOVE=false) +AM_CONDITIONAL(CXX_SUPPORTS_NOREGMOVE, test "x$SUPPORTS_NOREGMOVE" = xtrue) diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am index 58c4e4d92..d19e20042 100644 --- a/xpdf/xpdf/Makefile.am +++ b/xpdf/xpdf/Makefile.am @@ -12,7 +12,10 @@ libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ TextOutputDev.cc UnicodeMap.cc UnicodeTypeTable.cc XRef.cc noinst_LTLIBRARIES = libxpdf.la -# This fixes crash in Bug 109015 which i assume is a compiler bug -# as adding some correctly placed printf in SplashOutputDev::convertPath() makes this -# option unneeded -KDE_CXXFLAGS=-fno-regmove + +if CXX_SUPPORTS_NOREGMOVE + # This fixes crash in Bug 109015 which i assume is a compiler bug + # as adding some correctly placed printf in SplashOutputDev::convertPath() makes this + # option unneeded + KDE_CXXFLAGS=-fno-regmove +endif From af4ffd72588162e8542d557b3c09a8e04a3a6072 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 16 Jul 2005 16:22:49 +0000 Subject: [PATCH 115/245] Avoid using automake conditionals svn path=/trunk/KDE/kdegraphics/kpdf/; revision=435341 --- configure.in.in | 5 ++++- xpdf/xpdf/Makefile.am | 10 ++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/configure.in.in b/configure.in.in index ae671ac5e..25bc3436e 100644 --- a/configure.in.in +++ b/configure.in.in @@ -120,4 +120,7 @@ AC_ARG_ENABLE(force-kpdf-drm, ) KDE_CHECK_COMPILER_FLAG([fno-regmove], SUPPORTS_NOREGMOVE=true, SUPPORTS_NOREGMOVE=false) -AM_CONDITIONAL(CXX_SUPPORTS_NOREGMOVE, test "x$SUPPORTS_NOREGMOVE" = xtrue) +if test "x$SUPPORTS_NOREGMOVE" = xtrue; then + NOREGMOVE="-fno-regmove" +fi +AC_SUBST(NOREGMOVE) diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am index d19e20042..1f21260c8 100644 --- a/xpdf/xpdf/Makefile.am +++ b/xpdf/xpdf/Makefile.am @@ -13,9 +13,7 @@ libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ noinst_LTLIBRARIES = libxpdf.la -if CXX_SUPPORTS_NOREGMOVE - # This fixes crash in Bug 109015 which i assume is a compiler bug - # as adding some correctly placed printf in SplashOutputDev::convertPath() makes this - # option unneeded - KDE_CXXFLAGS=-fno-regmove -endif +# This fixes crash in Bug 109015 which i assume is a compiler bug +# as adding some correctly placed printf in SplashOutputDev::convertPath() makes this +# option unneeded +KDE_CXXFLAGS=$(NOREGMOVE) From bdc00ae3f3f2aee4826bedf13e7f03fc7a33b6cb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 16 Jul 2005 16:41:03 +0000 Subject: [PATCH 116/245] Correct the implementation of Quit link action Add the implementation of close link action That two actions only work within inside kpdf as in konqueror they would be quite shocking Reverse the order link actions are added to m_rects because there are some pdf that have a rect with a link and inside of that another link with a snall rect, and with this order we match acrobat behaviour svn path=/trunk/KDE/kdegraphics/kpdf/; revision=435350 --- core/document.cpp | 5 ++++- core/document.h | 2 ++ core/generator_pdf/gp_outputdev.cpp | 4 +++- core/link.h | 2 +- part.cpp | 24 +++++++++++++++++++++++- part.h | 5 +++++ shell/shell.cpp | 1 + shell/shell.h | 5 +++-- ui/pageview.cpp | 5 +++++ 9 files changed, 47 insertions(+), 6 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 5d5a4e5cd..7a9ba10d3 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -1025,7 +1025,7 @@ void KPDFDocument::processLink( const KPDFLink * link ) setNextViewport(); break; case KPDFLinkAction::Quit: - kapp->quit(); + emit quit(); break; case KPDFLinkAction::Find: emit linkFind(); @@ -1033,6 +1033,9 @@ void KPDFDocument::processLink( const KPDFLink * link ) case KPDFLinkAction::GoToPage: emit linkGoToPage(); break; + case KPDFLinkAction::Close: + emit close(); + break; } } break; diff --git a/core/document.h b/core/document.h index 5feebf38a..7400f194d 100644 --- a/core/document.h +++ b/core/document.h @@ -102,6 +102,8 @@ class KPDFDocument : public QObject void requestDone( PixmapRequest * request ); signals: + void close(); + void quit(); void linkFind(); void linkGoToPage(); void openURL(const KURL &url); diff --git a/core/generator_pdf/gp_outputdev.cpp b/core/generator_pdf/gp_outputdev.cpp index 88ccd07d3..b46e2900b 100644 --- a/core/generator_pdf/gp_outputdev.cpp +++ b/core/generator_pdf/gp_outputdev.cpp @@ -174,7 +174,7 @@ void KPDFOutputDev::drawLink( Link * link, Catalog * catalog ) // create the rect using normalized coords and attach the KPDFLink to it ObjectRect * rect = new ObjectRect( nl, nt, nr, nb, ObjectRect::Link, l ); // add the ObjectRect to the vector container - m_rects.push_back( rect ); + m_rects.push_front( rect ); } } SplashOutputDev::drawLink( link, catalog ); @@ -325,6 +325,8 @@ KPDFLink * KPDFOutputDev::generateLink( LinkAction * a ) link = new KPDFLinkAction( KPDFLinkAction::GoToPage ); else if ( !strcmp( name, "Find" ) ) link = new KPDFLinkAction( KPDFLinkAction::Find ); + else if ( !strcmp( name, "Close" ) ) + link = new KPDFLinkAction( KPDFLinkAction::Close ); else kdDebug() << "Unknown named action: '" << name << "'" << endl; } diff --git a/core/link.h b/core/link.h index a40f35a2b..2954f7180 100644 --- a/core/link.h +++ b/core/link.h @@ -88,7 +88,7 @@ class KPDFLinkAction : public KPDFLink { public: // define types of actions - enum ActionType { PageFirst, PagePrev, PageNext, PageLast, HistoryBack, HistoryForward, Quit, Find, GoToPage }; + enum ActionType { PageFirst, PagePrev, PageNext, PageLast, HistoryBack, HistoryForward, Quit, Find, GoToPage, Close }; // query for action type ActionType actionType() const { return m_type; } diff --git a/part.cpp b/part.cpp index 5aab591e7..818187e6c 100644 --- a/part.cpp +++ b/part.cpp @@ -106,6 +106,12 @@ Part::Part(QWidget *parentWidget, const char *widgetName, connect( m_document, SIGNAL( linkFind() ), this, SLOT( slotFind() ) ); connect( m_document, SIGNAL( linkGoToPage() ), this, SLOT( slotGoToPage() ) ); connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURL(const KURL &) ) ); + connect( m_document, SIGNAL( close() ), this, SLOT( close() ) ); + + if (parent && parent->metaObject()->slotNames(true).contains("slotQuit()")) + connect( m_document, SIGNAL( quit() ), parent, SLOT( slotQuit() ) ); + else + connect( m_document, SIGNAL( quit() ), this, SLOT( cannotQuit() ) ); // widgets: ^searchbar (toolbar containing label and SearchWidget) // m_searchToolBar = new KToolBar( parentWidget, "searchBar" ); @@ -431,10 +437,12 @@ bool Part::closeURL() m_printPreview->setEnabled( false ); m_showProperties->setEnabled( false ); m_showPresentation->setEnabled( false ); - updateViewActions(); + emit setWindowCaption(""); + emit enablePrintAction(false); m_searchStarted = false; if (!m_file.isEmpty()) m_watcher->removeFile(m_file); m_document->closeDocument(); + updateViewActions(); m_searchWidget->clearText(); return KParts::ReadOnlyPart::closeURL(); } @@ -483,6 +491,15 @@ void Part::slotDoFileDirty() } } +void Part::close() +{ + if (parent() && strcmp(parent()->name(), "KPDF::Shell") == 0) + { + closeURL(); + } + else KMessageBox::information(widget(), i18n("This link points to a close document action that does not work when using the embedded viewer."), QString::null, "warnNoCloseIfNotInKPDF"); +} + void Part::updateViewActions() { bool opened = m_document->pages() > 0; @@ -521,6 +538,11 @@ void Part::psTransformEnded() openFile(); } +void Part::cannotQuit() +{ + KMessageBox::information(widget(), i18n("This link points to a quit application action that does not work when using the embedded viewer."), QString::null, "warnNoQuitIfNotInKPDF"); +} + //BEGIN go to page dialog class KPDFGotoPageDialog : public KDialogBase { diff --git a/part.h b/part.h index 0d914e3b5..a590c25c8 100644 --- a/part.h +++ b/part.h @@ -78,6 +78,9 @@ public: uint currentPage(); KURL currentDocument(); +signals: + void enablePrintAction(bool enable); + protected: // reimplemented from KParts::ReadOnlyPart bool openFile(); @@ -103,10 +106,12 @@ protected slots: void slotShowProperties(); void slotShowLeftPanel(); void slotShowPresentation(); + void close(); // can be connected to widget elements void updateViewActions(); void enableTOC(bool enable); void psTransformEnded(); + void cannotQuit(); public slots: // connected to Shell action (and browserExtension), not local one diff --git a/shell/shell.cpp b/shell/shell.cpp index 8104ffc4e..a3e241a29 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -88,6 +88,7 @@ void Shell::init() } connect( this, SIGNAL( restoreDocument(const KURL &, int) ),m_part, SLOT( restoreDocument(const KURL &, int))); connect( this, SIGNAL( saveDocumentRestoreInfo(KConfig*) ), m_part, SLOT( saveDocumentRestoreInfo(KConfig*))); + connect( m_part, SIGNAL( enablePrintAction(bool) ), m_printAction, SLOT( setEnabled(bool))); readSettings(); if (!KGlobal::config()->hasGroup("MainWindow")) diff --git a/shell/shell.h b/shell/shell.h index a3dabe79b..4e2e2b07c 100644 --- a/shell/shell.h +++ b/shell/shell.h @@ -70,11 +70,12 @@ namespace KPDF void writeSettings(); void setFullScreen( bool ); + public slots: + void slotQuit(); + private slots: void fileOpen(); - void slotQuit(); - void optionsConfigureToolbars(); void applyNewToolbarConfig(); void slotUpdateFullScreen(); diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 40a442fb3..a4741453f 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -272,7 +272,12 @@ void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool doc // so pages are never relayouted slotRelayoutPages(); else + { + // update the mouse cursor when closing because we may have close through a link and + // want the cursor to come back to the normal cursor + updateCursor( viewportToContents( mapFromGlobal( QCursor::pos() ) ) ); resizeContents( 0, 0 ); + } // OSD to display pages if ( documentChanged && pageSet.count() > 0 && Settings::showOSD() ) From d785f1368c582af27e407089bf437431494bbb75 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 18 Jul 2005 16:46:51 +0000 Subject: [PATCH 117/245] Rename Settings to KpdfSettings to avoid #101155 Henrique you should rename ark class also so that this doesn't happen again with other kparts BUGS: 101155 CCMAIL: henriquepinto@ufmg.br svn path=/trunk/KDE/kdegraphics/kpdf/; revision=435918 --- conf/settings.kcfgc | 2 +- core/document.cpp | 14 +++---- core/generator_pdf/generator_pdf.cpp | 6 +-- part.cpp | 24 +++++------ ui/pagepainter.cpp | 24 +++++------ ui/pageview.cpp | 54 ++++++++++++------------ ui/pageviewutils.cpp | 2 +- ui/presentationwidget.cpp | 62 ++++++++++++++-------------- ui/thumbnaillist.cpp | 6 +-- 9 files changed, 97 insertions(+), 97 deletions(-) diff --git a/conf/settings.kcfgc b/conf/settings.kcfgc index eaa2e417d..bfdad9ee5 100644 --- a/conf/settings.kcfgc +++ b/conf/settings.kcfgc @@ -1,4 +1,4 @@ -ClassName=Settings +ClassName=KpdfSettings File=kpdf.kcfg Mutators=true Singleton=true diff --git a/core/document.cpp b/core/document.cpp index 7a9ba10d3..9edc9e889 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -349,7 +349,7 @@ void KPDFDocument::reparseConfig() } // free memory if in 'low' profile - if ( Settings::memoryLevel() == Settings::EnumMemoryLevel::Low && + if ( KpdfSettings::memoryLevel() == KpdfSettings::EnumMemoryLevel::Low && !d->allocatedPixmapsFifo.isEmpty() && !pages_vector.isEmpty() ) cleanupPixmapMemory(); } @@ -458,7 +458,7 @@ void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & request } // 2. [ADD TO STACK] add requests to stack - bool threadingDisabled = !Settings::enableThreading(); + bool threadingDisabled = !KpdfSettings::enableThreading(); QValueList< PixmapRequest * >::const_iterator rIt = requests.begin(), rEnd = requests.end(); for ( ; rIt != rEnd; ++rIt ) { @@ -1147,18 +1147,18 @@ void KPDFDocument::cleanupPixmapMemory( int /*sure? bytesOffset*/ ) // [MEM] choose memory parameters based on configuration profile int clipValue = -1; int memoryToFree = -1; - switch ( Settings::memoryLevel() ) + switch ( KpdfSettings::memoryLevel() ) { - case Settings::EnumMemoryLevel::Low: + case KpdfSettings::EnumMemoryLevel::Low: memoryToFree = d->allocatedPixmapsTotalMemory; break; - case Settings::EnumMemoryLevel::Normal: + case KpdfSettings::EnumMemoryLevel::Normal: memoryToFree = d->allocatedPixmapsTotalMemory - getTotalMemory() / 3; clipValue = (d->allocatedPixmapsTotalMemory - getFreeMemory()) / 2; break; - case Settings::EnumMemoryLevel::Aggressive: + case KpdfSettings::EnumMemoryLevel::Aggressive: clipValue = (d->allocatedPixmapsTotalMemory - getFreeMemory()) / 2; break; } @@ -1432,7 +1432,7 @@ void KPDFDocument::saveDocumentInfo() const void KPDFDocument::slotTimedMemoryCheck() { // [MEM] clean memory (for 'free mem dependant' profiles only) - if ( Settings::memoryLevel() != Settings::EnumMemoryLevel::Low && + if ( KpdfSettings::memoryLevel() != KpdfSettings::EnumMemoryLevel::Low && d->allocatedPixmapsTotalMemory > 1024*1024 ) cleanupPixmapMemory(); } diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 14bece476..bf5b78d02 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -256,7 +256,7 @@ const DocumentSynopsis * PDFGenerator::generateDocumentSynopsis() bool PDFGenerator::isAllowed( int permissions ) { #if !KPDF_FORCE_DRM - if (kapp->authorize("skip_drm") && !Settings::obeyDRM()) return true; + if (kapp->authorize("skip_drm") && !KpdfSettings::obeyDRM()) return true; #endif bool b = true; @@ -499,8 +499,8 @@ QString PDFGenerator::getMetaData( const QString & key, const QString & option ) bool PDFGenerator::reparseConfig() { // load paper color from Settings or use the white default color - QColor color = ( (Settings::renderMode() == Settings::EnumRenderMode::Paper ) && - Settings::changeColors() ) ? Settings::paperColor() : Qt::white; + QColor color = ( (KpdfSettings::renderMode() == KpdfSettings::EnumRenderMode::Paper ) && + KpdfSettings::changeColors() ) ? KpdfSettings::paperColor() : Qt::white; // if paper color is changed we have to rebuild every visible pixmap in addition // to the outputDevice. it's the 'heaviest' case, other effect are just recoloring // over the page rendered on 'standard' white background. diff --git a/part.cpp b/part.cpp index 818187e6c..9b9f1322c 100644 --- a/part.cpp +++ b/part.cpp @@ -129,7 +129,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_showLeftPanel = new KToggleAction( i18n( "Show &Navigation Panel"), 0, this, SLOT( slotShowLeftPanel() ), actionCollection(), "show_leftpanel" ); m_showLeftPanel->setCheckedState( i18n( "Hide &Navigation Panel") ); m_showLeftPanel->setShortcut( "CTRL+L" ); - m_showLeftPanel->setChecked( Settings::showLeftPanel() ); + m_showLeftPanel->setChecked( KpdfSettings::showLeftPanel() ); // widgets: [left panel] | [] m_leftPanel = new QWidget( m_splitter ); @@ -253,7 +253,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_pageView->setupActions( ac ); // apply configuration (both internal settings and GUI configured items) - QValueList splitterSizes = Settings::splitterSizes(); + QValueList splitterSizes = KpdfSettings::splitterSizes(); if ( !splitterSizes.count() ) { // the first time use 1/10 for the panel and 9/10 for the pageView @@ -270,7 +270,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, // [SPEECH] check for KTTSD presence and usability KTrader::OfferList offers = KTrader::self()->query("DCOP/Text-to-Speech", "Name == 'KTTSD'"); - Settings::setUseKTTSD( (offers.count() > 0) ); + KpdfSettings::setUseKTTSD( (offers.count() > 0) ); // set our XML-UI resource file setXMLFile("part.rc"); @@ -280,9 +280,9 @@ Part::Part(QWidget *parentWidget, const char *widgetName, Part::~Part() { // save internal settings - Settings::setSplitterSizes( m_splitter->sizes() ); + KpdfSettings::setSplitterSizes( m_splitter->sizes() ); // write to disk config file - Settings::writeConfig(); + KpdfSettings::writeConfig(); delete m_document; if ( --m_count == 0 ) @@ -450,7 +450,7 @@ bool Part::closeURL() void Part::slotShowLeftPanel() { bool showLeft = m_showLeftPanel->isChecked(); - Settings::setShowLeftPanel(showLeft); + KpdfSettings::setShowLeftPanel(showLeft); // show/hide left qtoolbox m_leftPanel->setShown( showLeft ); // this needs to be hidden explicitly to disable thumbnails gen @@ -662,7 +662,7 @@ void Part::slotPreferences() return; // we didn't find an instance of this dialog, so lets create it - PreferencesDialog * dialog = new PreferencesDialog( m_pageView, Settings::self() ); + PreferencesDialog * dialog = new PreferencesDialog( m_pageView, KpdfSettings::self() ); // keep us informed when the user changes settings connect( dialog, SIGNAL( settingsChanged() ), this, SLOT( slotNewConfig() ) ); @@ -675,7 +675,7 @@ void Part::slotNewConfig() // changed before applying changes. // Watch File - bool watchFile = Settings::watchFile(); + bool watchFile = KpdfSettings::watchFile(); if ( watchFile && m_watcher->isStopped() ) m_watcher->startScan(); if ( !watchFile && !m_watcher->isStopped() ) @@ -684,12 +684,12 @@ void Part::slotNewConfig() m_watcher->stopScan(); } - bool showSearch = Settings::showSearchBar(); + bool showSearch = KpdfSettings::showSearchBar(); if ( m_searchWidget->isShown() != showSearch ) m_searchWidget->setShown( showSearch ); // Main View (pageView) - QScrollView::ScrollBarMode scrollBarMode = Settings::showScrollBars() ? + QScrollView::ScrollBarMode scrollBarMode = KpdfSettings::showScrollBars() ? QScrollView::AlwaysOn : QScrollView::AlwaysOff; if ( m_pageView->hScrollBarMode() != scrollBarMode ) { @@ -701,9 +701,9 @@ void Part::slotNewConfig() m_document->reparseConfig(); // update Main View and ThumbnailList contents - // TODO do this only when changing Settings::renderMode() + // TODO do this only when changing KpdfSettings::renderMode() m_pageView->updateContents(); - if ( Settings::showLeftPanel() && m_thumbnailList->isShown() ) + if ( KpdfSettings::showLeftPanel() && m_thumbnailList->isShown() ) m_thumbnailList->updateWidgets(); } diff --git a/ui/pagepainter.cpp b/ui/pagepainter.cpp index 6144f4c91..823bdb9fa 100644 --- a/ui/pagepainter.cpp +++ b/ui/pagepainter.cpp @@ -49,9 +49,9 @@ void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags, // if have no pixmap, draw blank page with gray cross and exit if ( !pixmap ) { - if ( Settings::changeColors() && - Settings::renderMode() == Settings::EnumRenderMode::Paper ) - destPainter->fillRect( limits, Settings::paperColor() ); + if ( KpdfSettings::changeColors() && + KpdfSettings::renderMode() == KpdfSettings::EnumRenderMode::Paper ) + destPainter->fillRect( limits, KpdfSettings::paperColor() ); else destPainter->fillRect( limits, Qt::white ); @@ -65,10 +65,10 @@ void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags, } // find out what to paint over the pixmap (manipulations / overlays) - bool paintAccessibility = (flags & Accessibility) && Settings::changeColors() && (Settings::renderMode() != Settings::EnumRenderMode::Paper); + bool paintAccessibility = (flags & Accessibility) && KpdfSettings::changeColors() && (KpdfSettings::renderMode() != KpdfSettings::EnumRenderMode::Paper); bool paintHighlights = (flags & Highlights) && !page->m_highlights.isEmpty(); - bool enhanceLinks = (flags & EnhanceLinks) && Settings::highlightLinks(); - bool enhanceImages = (flags & EnhanceImages) && Settings::highlightImages(); + bool enhanceLinks = (flags & EnhanceLinks) && KpdfSettings::highlightLinks(); + bool enhanceImages = (flags & EnhanceImages) && KpdfSettings::highlightImages(); // check if there are really some highlightRects to paint if ( paintHighlights ) { @@ -122,21 +122,21 @@ void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags, // 2.1. modify pixmap following accessibility settings if ( paintAccessibility ) { - switch ( Settings::renderMode() ) + switch ( KpdfSettings::renderMode() ) { - case Settings::EnumRenderMode::Inverted: + case KpdfSettings::EnumRenderMode::Inverted: // Invert image pixels using QImage internal function backImage.invertPixels(false); break; - case Settings::EnumRenderMode::Recolor: + case KpdfSettings::EnumRenderMode::Recolor: // Recolor image using KImageEffect::flatten with dither:0 - KImageEffect::flatten( backImage, Settings::recolorForeground(), Settings::recolorBackground() ); + KImageEffect::flatten( backImage, KpdfSettings::recolorForeground(), KpdfSettings::recolorBackground() ); break; - case Settings::EnumRenderMode::BlackWhite: + case KpdfSettings::EnumRenderMode::BlackWhite: // Manual Gray and Contrast unsigned int * data = (unsigned int *)backImage.bits(); int val, pixels = backImage.width() * backImage.height(), - con = Settings::bWContrast(), thr = 255 - Settings::bWThreshold(); + con = KpdfSettings::bWContrast(), thr = 255 - KpdfSettings::bWThreshold(); for( int i = 0; i < pixels; ++i ) { val = qGray( data[i] ); diff --git a/ui/pageview.cpp b/ui/pageview.cpp index a4741453f..b59f21258 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -127,8 +127,8 @@ PageView::PageView( QWidget *parent, KPDFDocument *document ) // create and initialize private storage structure d = new PageViewPrivate(); d->document = document; - d->zoomMode = (PageView::ZoomMode)Settings::zoomMode(); - d->zoomFactor = Settings::zoomFactor(); + d->zoomMode = (PageView::ZoomMode)KpdfSettings::zoomMode(); + d->zoomFactor = KpdfSettings::zoomFactor(); d->mouseMode = MouseNormal; d->mouseMidStartY = -1; d->mouseOnRect = false; @@ -198,11 +198,11 @@ void PageView::setupActions( KActionCollection * ac ) // View-Layout actions d->aViewTwoPages = new KToggleAction( i18n("&Two Pages"), "view_left_right", 0, ac, "view_twopages" ); connect( d->aViewTwoPages, SIGNAL( toggled( bool ) ), SLOT( slotTwoPagesToggled( bool ) ) ); - d->aViewTwoPages->setChecked( Settings::viewColumns() > 1 ); + d->aViewTwoPages->setChecked( KpdfSettings::viewColumns() > 1 ); d->aViewContinuous = new KToggleAction( i18n("&Continuous"), "view_text", 0, ac, "view_continuous" ); connect( d->aViewContinuous, SIGNAL( toggled( bool ) ), SLOT( slotContinuousToggled( bool ) ) ); - d->aViewContinuous->setChecked( Settings::viewContinuous() ); + d->aViewContinuous->setChecked( KpdfSettings::viewContinuous() ); // Mouse-Mode actions d->aMouseNormal = new KRadioAction( i18n("&Browse Tool"), "mouse", 0, this, SLOT( slotSetMouseNormal() ), ac, "mouse_drag" ); @@ -280,7 +280,7 @@ void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool doc } // OSD to display pages - if ( documentChanged && pageSet.count() > 0 && Settings::showOSD() ) + if ( documentChanged && pageSet.count() > 0 && KpdfSettings::showOSD() ) d->messageWindow->display( i18n(" Loaded a one-page document.", " Loaded a %n-page document.", @@ -315,7 +315,7 @@ void PageView::notifyViewportChanged( bool smoothMove ) // relayout in "Single Pages" mode or if a relayout is pending d->blockPixmapsRequest = true; - if ( !Settings::viewContinuous() || d->dirtyLayout ) + if ( !KpdfSettings::viewContinuous() || d->dirtyLayout ) slotRelayoutPages(); // restore viewport center or use default {x-center,v-top} alignment @@ -486,7 +486,7 @@ void PageView::viewportPaintEvent( QPaintEvent * pe ) // note: this check will take care of all things requiring alpha blending (not only selection) bool wantCompositing = !selectionRect.isNull() && contentsRect.intersects( selectionRect ); - if ( wantCompositing && Settings::enableCompositing() ) + if ( wantCompositing && KpdfSettings::enableCompositing() ) { // create pixmap and open a painter over it (contents{left,top} becomes pixmap {0,0}) QPixmap doubleBuffer( contentsRect.size() ); @@ -520,7 +520,7 @@ void PageView::viewportPaintEvent( QPaintEvent * pe ) pixmapPainter.drawRect( selectionRect ); } // 4) Layer 3: overlays - if ( Settings::debugDrawBoundaries() ) + if ( KpdfSettings::debugDrawBoundaries() ) { pixmapPainter.setPen( Qt::blue ); pixmapPainter.drawRect( contentsRect ); @@ -543,7 +543,7 @@ void PageView::viewportPaintEvent( QPaintEvent * pe ) screenPainter.drawRect( selectionRect ); } // 4) Layer 3: overlays - if ( Settings::debugDrawBoundaries() ) + if ( KpdfSettings::debugDrawBoundaries() ) { screenPainter.setPen( Qt::red ); screenPainter.drawRect( contentsRect ); @@ -665,7 +665,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) case Key_Up: case Key_PageUp: // if in single page mode and at the top of the screen, go to previous page - if ( Settings::viewContinuous() || verticalScrollBar()->value() > verticalScrollBar()->minValue() ) + if ( KpdfSettings::viewContinuous() || verticalScrollBar()->value() > verticalScrollBar()->minValue() ) { if ( e->key() == Key_Up ) verticalScrollBar()->subtractLine(); @@ -685,7 +685,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) case Key_Down: case Key_PageDown: // if in single page mode and at the bottom of the screen, go to next page - if ( Settings::viewContinuous() || verticalScrollBar()->value() < verticalScrollBar()->maxValue() ) + if ( KpdfSettings::viewContinuous() || verticalScrollBar()->value() < verticalScrollBar()->maxValue() ) { if ( e->key() == Key_Down ) verticalScrollBar()->addLine(); @@ -1026,7 +1026,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) menu.insertItem( SmallIcon("editcopy"), i18n( "Copy to Clipboard" ), 1 ); if ( !d->document->isAllowed( KPDFDocument::AllowCopy ) ) menu.setItemEnabled( 1, false ); - if ( Settings::useKTTSD() ) + if ( KpdfSettings::useKTTSD() ) menu.insertItem( SmallIcon("kttsd"), i18n( "Speak Text" ), 2 ); } menu.insertTitle( i18n( "Image (%1 by %2 pixels)" ).arg( selectionRect.width() ).arg( selectionRect.height() ) ); @@ -1093,10 +1093,10 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) if (KApplication::startServiceByDesktopName("kttsd", QStringList(), &error)) { d->messageWindow->display( i18n("Starting KTTSD Failed: %1").arg(error) ); - Settings::setUseKTTSD(false); + KpdfSettings::setUseKTTSD(false); } } - if ( Settings::useKTTSD() ) + if ( KpdfSettings::useKTTSD() ) { // serialize the text to speech (selectedText) and the // preferred reader ("" is the default voice) ... @@ -1152,7 +1152,7 @@ void PageView::wheelEvent( QWheelEvent *e ) else slotZoomIn(); } - else if ( delta <= -120 && !Settings::viewContinuous() && vScroll == verticalScrollBar()->maxValue() ) + else if ( delta <= -120 && !KpdfSettings::viewContinuous() && vScroll == verticalScrollBar()->maxValue() ) { // go to next page if ( d->document->currentPage() < d->items.count() - 1 ) @@ -1165,7 +1165,7 @@ void PageView::wheelEvent( QWheelEvent *e ) d->document->setViewport( newViewport ); } } - else if ( delta >= 120 && !Settings::viewContinuous() && vScroll == verticalScrollBar()->minValue() ) + else if ( delta >= 120 && !KpdfSettings::viewContinuous() && vScroll == verticalScrollBar()->minValue() ) { // go to prev page if ( d->document->currentPage() > 0 ) @@ -1439,8 +1439,8 @@ void PageView::updateZoom( ZoomMode newZoomMode ) d->aZoomFitText->setChecked( checkedZoomAction == d->aZoomFitText ); // save selected zoom factor - Settings::setZoomMode(newZoomMode); - Settings::setZoomFactor(newFactor); + KpdfSettings::setZoomMode(newZoomMode); + KpdfSettings::setZoomFactor(newFactor); } } @@ -1544,11 +1544,11 @@ void PageView::slotRelayoutPages() QRect viewportRect( contentsX(), contentsY(), viewportWidth, viewportHeight ); // set all items geometry and resize contents. handle 'continuous' and 'single' modes separately - if ( Settings::viewContinuous() ) + if ( KpdfSettings::viewContinuous() ) { // Here we find out column's width and row's height to compute a table // so we can place widgets 'centered in virtual cells'. - int nCols = Settings::viewColumns(), + int nCols = KpdfSettings::viewColumns(), nRows = (int)ceil( (float)pageCount / (float)nCols ), * colWidth = new int[ nCols ], * rowHeight = new int[ nRows ], @@ -1615,7 +1615,7 @@ void PageView::slotRelayoutPages() PageViewItem * currentItem = d->items[ QMAX( 0, (int)d->document->currentPage() ) ]; // setup varialbles for a 1(row) x N(columns) grid - int nCols = Settings::viewColumns(), + int nCols = KpdfSettings::viewColumns(), * colWidth = new int[ nCols ], cIdx = 0; fullHeight = viewportHeight; @@ -1769,8 +1769,8 @@ void PageView::slotRequestVisiblePixmaps( int newLeft, int newTop ) // if preloading is enabled, add the pages before and after in preloading if ( !d->visibleItems.isEmpty() && - Settings::memoryLevel() != Settings::EnumMemoryLevel::Low && - Settings::enableThreading() ) + KpdfSettings::memoryLevel() != KpdfSettings::EnumMemoryLevel::Low && + KpdfSettings::enableThreading() ) { // add the page before the 'visible series' in preload int headRequest = d->visibleItems.first()->pageNumber() - 1; @@ -1907,9 +1907,9 @@ void PageView::slotFitToTextToggled( bool on ) void PageView::slotTwoPagesToggled( bool on ) { uint newColumns = on ? 2 : 1; - if ( Settings::viewColumns() != newColumns ) + if ( KpdfSettings::viewColumns() != newColumns ) { - Settings::setViewColumns( newColumns ); + KpdfSettings::setViewColumns( newColumns ); if ( d->document->pages() > 0 ) slotRelayoutPages(); } @@ -1917,9 +1917,9 @@ void PageView::slotTwoPagesToggled( bool on ) void PageView::slotContinuousToggled( bool on ) { - if ( Settings::viewContinuous() != on ) + if ( KpdfSettings::viewContinuous() != on ) { - Settings::setViewContinuous( on ); + KpdfSettings::setViewContinuous( on ); if ( d->document->pages() > 0 ) slotRelayoutPages(); } diff --git a/ui/pageviewutils.cpp b/ui/pageviewutils.cpp index 627e84d37..84ff5c058 100644 --- a/ui/pageviewutils.cpp +++ b/ui/pageviewutils.cpp @@ -36,7 +36,7 @@ void PageViewMessage::display( const QString & message, Icon icon, int durationM // give to Caesar what Caesar owns: code taken from Amarok's osd.h/.cpp // "redde (reddite, pl.) cesari quae sunt cesaris", just btw. ;) { - if ( !Settings::showOSD() ) + if ( !KpdfSettings::showOSD() ) { hide(); return; diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index d8303cda4..48f179703 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -67,12 +67,12 @@ PresentationWidget::PresentationWidget( QWidget * parent, KPDFDocument * doc ) connect( m_overlayHideTimer, SIGNAL( timeout() ), this, SLOT( slotHideOverlay() ) ); // handle cursor appearance as specified in configuration - if ( Settings::slidesCursor() == Settings::EnumSlidesCursor::HiddenDelay ) + if ( KpdfSettings::slidesCursor() == KpdfSettings::EnumSlidesCursor::HiddenDelay ) { KCursor::setAutoHideCursor( this, true ); KCursor::setHideCursorDelay( 3000 ); } - else if ( Settings::slidesCursor() == Settings::EnumSlidesCursor::Hidden ) + else if ( KpdfSettings::slidesCursor() == KpdfSettings::EnumSlidesCursor::Hidden ) { setCursor( KCursor::blankCursor() ); } @@ -143,15 +143,15 @@ void PresentationWidget::notifySetup( const QValueVector< KPDFPage * > & pageSet void PresentationWidget::notifyViewportChanged( bool /*smoothMove*/ ) { // discard notifications if displaying the summary - if ( m_frameIndex == -1 && Settings::slidesShowSummary() ) + if ( m_frameIndex == -1 && KpdfSettings::slidesShowSummary() ) return; // display the current page changePage( m_document->viewport().pageNumber ); // auto advance to the next page if set - if ( Settings::slidesAdvance() ) - QTimer::singleShot( Settings::slidesAdvanceTime() * 1000, this, SLOT( slotNextPage() ) ); + if ( KpdfSettings::slidesAdvance() ) + QTimer::singleShot( KpdfSettings::slidesAdvanceTime() * 1000, this, SLOT( slotNextPage() ) ); } void PresentationWidget::notifyPageChanged( int pageNumber, int changedFlags ) @@ -278,7 +278,7 @@ void PresentationWidget::paintEvent( QPaintEvent * pe ) m_document->addObserver( this ); // show summary if requested - if ( Settings::slidesShowSummary() ) + if ( KpdfSettings::slidesShowSummary() ) generatePage(); KMessageBox::information(this, i18n("There are two ways of exiting presentation mode, you can press either ESC key or click with the quit button that appears when placing the mouse in the top-right corner. Of course you can cycle windows (Alt+TAB by default)"), QString::null, "presentationInfo"); @@ -298,7 +298,7 @@ void PresentationWidget::paintEvent( QPaintEvent * pe ) if ( !r.isValid() ) continue; #ifdef ENABLE_PROGRESS_OVERLAY - if ( Settings::slidesShowProgress() && r.intersects( m_overlayGeometry ) ) + if ( KpdfSettings::slidesShowProgress() && r.intersects( m_overlayGeometry ) ) { // backbuffer the overlay operation QPixmap backPixmap( r.size() ); @@ -382,7 +382,7 @@ void PresentationWidget::generatePage() // generate the top-right corner overlay #ifdef ENABLE_PROGRESS_OVERLAY - if ( Settings::slidesShowProgress() && m_frameIndex != -1 ) + if ( KpdfSettings::slidesShowProgress() && m_frameIndex != -1 ) generateOverlay(); #endif @@ -473,7 +473,7 @@ void PresentationWidget::generateContentsPage( int pageNum, QPainter & p ) for ( uint i = 0; i < rects.count(); i++ ) { const QRect & r = rects[i]; - p.fillRect( r, Settings::slidesBackgroundColor() ); + p.fillRect( r, KpdfSettings::slidesBackgroundColor() ); } } @@ -556,7 +556,7 @@ void PresentationWidget::generateOverlay() void PresentationWidget::slotNextPage() { // loop when configured - if ( m_frameIndex == (int)m_frames.count() - 1 && Settings::slidesLoop() ) + if ( m_frameIndex == (int)m_frames.count() - 1 && KpdfSettings::slidesLoop() ) m_frameIndex = -1; if ( m_frameIndex < (int)m_frames.count() - 1 ) @@ -574,8 +574,8 @@ void PresentationWidget::slotNextPage() setFocus(); // auto advance to the next page if set - if ( Settings::slidesAdvance() ) - QTimer::singleShot( Settings::slidesAdvanceTime() * 1000, this, SLOT( slotNextPage() ) ); + if ( KpdfSettings::slidesAdvance() ) + QTimer::singleShot( KpdfSettings::slidesAdvanceTime() * 1000, this, SLOT( slotNextPage() ) ); } void PresentationWidget::slotPrevPage() @@ -629,73 +629,73 @@ void PresentationWidget::slotTransitionStep() const KPDFPageTransition PresentationWidget::defaultTransition() const { - return defaultTransition( Settings::slidesTransition() ); + return defaultTransition( KpdfSettings::slidesTransition() ); } const KPDFPageTransition PresentationWidget::defaultTransition( int type ) const { switch ( type ) { - case Settings::EnumSlidesTransition::BlindsHorizontal: + case KpdfSettings::EnumSlidesTransition::BlindsHorizontal: { KPDFPageTransition transition( KPDFPageTransition::Blinds ); transition.setAlignment( KPDFPageTransition::Horizontal ); return transition; break; } - case Settings::EnumSlidesTransition::BlindsVertical: + case KpdfSettings::EnumSlidesTransition::BlindsVertical: { KPDFPageTransition transition( KPDFPageTransition::Blinds ); transition.setAlignment( KPDFPageTransition::Vertical ); return transition; break; } - case Settings::EnumSlidesTransition::BoxIn: + case KpdfSettings::EnumSlidesTransition::BoxIn: { KPDFPageTransition transition( KPDFPageTransition::Box ); transition.setDirection( KPDFPageTransition::Inward ); return transition; break; } - case Settings::EnumSlidesTransition::BoxOut: + case KpdfSettings::EnumSlidesTransition::BoxOut: { KPDFPageTransition transition( KPDFPageTransition::Box ); transition.setDirection( KPDFPageTransition::Outward ); return transition; break; } - case Settings::EnumSlidesTransition::Dissolve: + case KpdfSettings::EnumSlidesTransition::Dissolve: { return KPDFPageTransition( KPDFPageTransition::Dissolve ); break; } - case Settings::EnumSlidesTransition::GlitterDown: + case KpdfSettings::EnumSlidesTransition::GlitterDown: { KPDFPageTransition transition( KPDFPageTransition::Glitter ); transition.setAngle( 270 ); return transition; break; } - case Settings::EnumSlidesTransition::GlitterRight: + case KpdfSettings::EnumSlidesTransition::GlitterRight: { KPDFPageTransition transition( KPDFPageTransition::Glitter ); transition.setAngle( 0 ); return transition; break; } - case Settings::EnumSlidesTransition::GlitterRightDown: + case KpdfSettings::EnumSlidesTransition::GlitterRightDown: { KPDFPageTransition transition( KPDFPageTransition::Glitter ); transition.setAngle( 315 ); return transition; break; } - case Settings::EnumSlidesTransition::Random: + case KpdfSettings::EnumSlidesTransition::Random: { return defaultTransition( KApplication::random() % 18 ); break; } - case Settings::EnumSlidesTransition::SplitHorizontalIn: + case KpdfSettings::EnumSlidesTransition::SplitHorizontalIn: { KPDFPageTransition transition( KPDFPageTransition::Split ); transition.setAlignment( KPDFPageTransition::Horizontal ); @@ -703,7 +703,7 @@ const KPDFPageTransition PresentationWidget::defaultTransition( int type ) const return transition; break; } - case Settings::EnumSlidesTransition::SplitHorizontalOut: + case KpdfSettings::EnumSlidesTransition::SplitHorizontalOut: { KPDFPageTransition transition( KPDFPageTransition::Split ); transition.setAlignment( KPDFPageTransition::Horizontal ); @@ -711,7 +711,7 @@ const KPDFPageTransition PresentationWidget::defaultTransition( int type ) const return transition; break; } - case Settings::EnumSlidesTransition::SplitVerticalIn: + case KpdfSettings::EnumSlidesTransition::SplitVerticalIn: { KPDFPageTransition transition( KPDFPageTransition::Split ); transition.setAlignment( KPDFPageTransition::Vertical ); @@ -719,7 +719,7 @@ const KPDFPageTransition PresentationWidget::defaultTransition( int type ) const return transition; break; } - case Settings::EnumSlidesTransition::SplitVerticalOut: + case KpdfSettings::EnumSlidesTransition::SplitVerticalOut: { KPDFPageTransition transition( KPDFPageTransition::Split ); transition.setAlignment( KPDFPageTransition::Vertical ); @@ -727,35 +727,35 @@ const KPDFPageTransition PresentationWidget::defaultTransition( int type ) const return transition; break; } - case Settings::EnumSlidesTransition::WipeDown: + case KpdfSettings::EnumSlidesTransition::WipeDown: { KPDFPageTransition transition( KPDFPageTransition::Wipe ); transition.setAngle( 270 ); return transition; break; } - case Settings::EnumSlidesTransition::WipeRight: + case KpdfSettings::EnumSlidesTransition::WipeRight: { KPDFPageTransition transition( KPDFPageTransition::Wipe ); transition.setAngle( 0 ); return transition; break; } - case Settings::EnumSlidesTransition::WipeLeft: + case KpdfSettings::EnumSlidesTransition::WipeLeft: { KPDFPageTransition transition( KPDFPageTransition::Wipe ); transition.setAngle( 180 ); return transition; break; } - case Settings::EnumSlidesTransition::WipeUp: + case KpdfSettings::EnumSlidesTransition::WipeUp: { KPDFPageTransition transition( KPDFPageTransition::Wipe ); transition.setAngle( 90 ); return transition; break; } - case Settings::EnumSlidesTransition::Replace: + case KpdfSettings::EnumSlidesTransition::Replace: default: return KPDFPageTransition( KPDFPageTransition::Replace ); break; diff --git a/ui/thumbnaillist.cpp b/ui/thumbnaillist.cpp index 247e17588..595fb9d16 100644 --- a/ui/thumbnaillist.cpp +++ b/ui/thumbnaillist.cpp @@ -168,7 +168,7 @@ void ThumbnailList::notifyViewportChanged( bool /*smoothMove*/ ) { m_selected = *tIt; m_selected->setSelected( true ); - if ( Settings::syncThumbnailsViewport() ) + if ( KpdfSettings::syncThumbnailsViewport() ) { int yOffset = QMAX( visibleHeight() / 4, m_selected->height() / 2 ); ensureVisible( 0, childY( m_selected ) + m_selected->height()/2, 0, yOffset ); @@ -246,7 +246,7 @@ const QPixmap * ThumbnailList::getBookmarkOverlay() const void ThumbnailList::slotFilterBookmarks( bool filterOn ) { // save state - Settings::setFilterBookmarks( filterOn ); + KpdfSettings::setFilterBookmarks( filterOn ); // ask for the 'notifySetup' with a little trick (on reinsertion the // document sends the list again) m_document->removeObserver( this ); @@ -552,7 +552,7 @@ ThumbnailController::ThumbnailController( QWidget * parent, ThumbnailList * list list, SLOT( slotFilterBookmarks( bool ) ), true, i18n( "Show bookmarked pages only" ) ); setToggle( FILTERB_ID ); - setButton( FILTERB_ID, Settings::filterBookmarks() ); + setButton( FILTERB_ID, KpdfSettings::filterBookmarks() ); //insertLineSeparator(); } From fe9ef1d751177091587447442426178880316271 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 18 Jul 2005 21:23:36 +0000 Subject: [PATCH 118/245] Link following in presentation mode. Cookie goes to Enrico for implementing kpdf's second most voted wish BUGS: 98388 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=436026 --- TODO | 2 +- core/document.cpp | 6 + core/document.h | 6 +- core/generator_pdf/generator_pdf.cpp | 4 +- core/link.h | 2 +- part.cpp | 9 ++ part.h | 1 + ui/presentationwidget.cpp | 187 +++++++++++++++++++++++---- ui/presentationwidget.h | 6 + 9 files changed, 193 insertions(+), 30 deletions(-) diff --git a/TODO b/TODO index d94cc189c..6a00e14a8 100644 --- a/TODO +++ b/TODO @@ -59,7 +59,6 @@ More items (first items will enter 'In progress list' first): -> presentation: implement missing transitions (6/11 done) -> presentation: add some gfx tools (like a red pencil) -> presentation: save a flag (to the xml) to open a pdf in presentation mode --> presentation: link following (difficult due to pagerects related to pageview pixmap only) -> presentation: wheel not visible on black. gradient appreciated on lighter backgrounds. -> investigate 'Splash' lack of smoothness at low resolutions (see lines in thumbnails) -> add search on the toc widget (a 'prune on type' lineedit like in thumbnails widget) @@ -73,6 +72,7 @@ More items (first items will enter 'In progress list' first): Done (newest features come first): -- merging from kdpf_annotations branch -- +-> ADD: presentation: link following (BR98388) -> ADD: Save zoom setting on exit -> ADD: Put fonts used by the document on the properties dialog -> ADD: partial implementation of XYZ links diff --git a/core/document.cpp b/core/document.cpp index 9edc9e889..8b562888f 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -1027,6 +1027,12 @@ void KPDFDocument::processLink( const KPDFLink * link ) case KPDFLinkAction::Quit: emit quit(); break; + case KPDFLinkAction::Presentation: + emit linkPresentation(); + break; + case KPDFLinkAction::EndPresentation: + emit linkEndPresentation(); + break; case KPDFLinkAction::Find: emit linkFind(); break; diff --git a/core/document.h b/core/document.h index 7400f194d..07fb11f3e 100644 --- a/core/document.h +++ b/core/document.h @@ -102,11 +102,13 @@ class KPDFDocument : public QObject void requestDone( PixmapRequest * request ); signals: - void close(); - void quit(); + void close(); + void quit(); void linkFind(); void linkGoToPage(); void openURL(const KURL &url); + void linkPresentation(); + void linkEndPresentation(); private: void sendGeneratorRequest(); diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index bf5b78d02..d83a8a6fe 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -304,7 +304,7 @@ void PDFGenerator::generatePixmap( PixmapRequest * request ) bool genTextPage = !page->hasSearchPage() && (request->width == page->width()) && (request->height == page->height()); // generate links and image rects if rendering pages on pageview - bool genObjectRects = request->id == PAGEVIEW_ID; + bool genObjectRects = request->id & (PAGEVIEW_ID | PRESENTATION_ID); // 0. LOCK [waits for the thread end] docLock.lock(); @@ -1080,7 +1080,7 @@ void PDFPixmapGeneratorThread::run() ( height == page->height() ); // generate links and image rects if rendering pages on pageview - bool genObjectRects = d->currentRequest->id == PAGEVIEW_ID; + bool genObjectRects = d->currentRequest->id & (PAGEVIEW_ID | PRESENTATION_ID); // 0. LOCK s[tart locking XPDF thread unsafe classes] d->generator->docLock.lock(); diff --git a/core/link.h b/core/link.h index 2954f7180..bbff4eaee 100644 --- a/core/link.h +++ b/core/link.h @@ -88,7 +88,7 @@ class KPDFLinkAction : public KPDFLink { public: // define types of actions - enum ActionType { PageFirst, PagePrev, PageNext, PageLast, HistoryBack, HistoryForward, Quit, Find, GoToPage, Close }; + enum ActionType { PageFirst, PagePrev, PageNext, PageLast, HistoryBack, HistoryForward, Quit, Presentation, EndPresentation, Find, GoToPage, Close }; // query for action type ActionType actionType() const { return m_type; } diff --git a/part.cpp b/part.cpp index 9b9f1322c..54b8eae1d 100644 --- a/part.cpp +++ b/part.cpp @@ -105,6 +105,8 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_document = new KPDFDocument(); connect( m_document, SIGNAL( linkFind() ), this, SLOT( slotFind() ) ); connect( m_document, SIGNAL( linkGoToPage() ), this, SLOT( slotGoToPage() ) ); + connect( m_document, SIGNAL( linkPresentation() ), this, SLOT( slotShowPresentation() ) ); + connect( m_document, SIGNAL( linkEndPresentation() ), this, SLOT( slotHidePresentation() ) ); connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURL(const KURL &) ) ); connect( m_document, SIGNAL( close() ), this, SLOT( close() ) ); @@ -431,6 +433,7 @@ bool Part::closeURL() m_temporaryLocalFile = QString::null; } + slotHidePresentation(); m_find->setEnabled( false ); m_findNext->setEnabled( false ); m_saveAs->setEnabled( false ); @@ -832,6 +835,12 @@ void Part::slotShowPresentation() m_presentationWidget = new PresentationWidget( widget(), m_document ); } +void Part::slotHidePresentation() +{ + if ( m_presentationWidget ) + delete (PresentationWidget*) m_presentationWidget; +} + void Part::slotPrint() { if (m_document->pages() == 0) return; diff --git a/part.h b/part.h index a590c25c8..b8cf0342c 100644 --- a/part.h +++ b/part.h @@ -106,6 +106,7 @@ protected slots: void slotShowProperties(); void slotShowLeftPanel(); void slotShowPresentation(); + void slotHidePresentation(); void close(); // can be connected to widget elements void updateViewActions(); diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index 48f179703..ba247382e 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -32,6 +32,7 @@ #include "pagepainter.h" #include "core/generator.h" #include "core/page.h" +#include "core/link.h" #include "conf/settings.h" @@ -49,7 +50,8 @@ struct PresentationFrame PresentationWidget::PresentationWidget( QWidget * parent, KPDFDocument * doc ) - : QDialog( parent, "presentationWidget", true, WDestructiveClose | WStyle_NoBorder), m_document( doc ), m_frameIndex( -1 ) + : QDialog( parent, "presentationWidget", true, WDestructiveClose | WStyle_NoBorder), + m_pressedLink( 0 ), m_handCursor( false ), m_document( doc ), m_frameIndex( -1 ) { // set look and geometry setBackgroundMode( Qt::NoBackground ); @@ -222,32 +224,62 @@ void PresentationWidget::mousePressEvent( QMouseEvent * e ) // pressing left button if ( e->button() == Qt::LeftButton ) { + // if pressing on a link, skip other checks + if ( ( m_pressedLink = getLink( e->x(), e->y() ) ) ) + return; + + // handle clicking on top-right overlay if ( m_overlayGeometry.contains( e->pos() ) ) + { overlayClick( e->pos() ); - else - slotNextPage(); + return; + } + + // if no other actions, go to next page + slotNextPage(); } // pressing right button else if ( e->button() == Qt::RightButton ) slotPrevPage(); } +void PresentationWidget::mouseReleaseEvent( QMouseEvent * e ) +{ + // if releasing on the same link we pressed over, execute it + if ( m_pressedLink && e->button() == Qt::LeftButton ) + { + const KPDFLink * link = getLink( e->x(), e->y() ); + if ( link == m_pressedLink ) + m_document->processLink( link ); + m_pressedLink = 0; + } +} + void PresentationWidget::mouseMoveEvent( QMouseEvent * e ) { - if (m_width == -1) return; - - // hide a shown bar when exiting the area + // safety check + if ( m_width == -1 ) + return; + + // update cursor and tooltip if hovering a link + if ( KpdfSettings::slidesCursor() != KpdfSettings::EnumSlidesCursor::Hidden ) + testCursorOnLink( e->x(), e->y() ); + if ( m_topBar->isShown() ) { + // hide a shown bar when exiting the area if ( e->y() > ( m_topBar->height() + 1 ) ) m_topBar->hide(); } - // show a hidden bar if mouse reaches the top of the screen - else if ( !e->y() ) - m_topBar->show(); - // change page if dragging the mouse over the 'wheel' - else if ( e->state() == Qt::LeftButton && m_overlayGeometry.contains( e->pos() ) ) + else + { + // show the bar if reaching top 2 pixels + if ( e->y() <= (geometry().top() + 1) ) + m_topBar->show(); + // handle "dragging the wheel" if clicking on its geometry + else if ( e->state() == Qt::LeftButton && m_overlayGeometry.contains( e->pos() ) ) overlayClick( e->pos() ); + } } void PresentationWidget::paintEvent( QPaintEvent * pe ) @@ -325,6 +357,58 @@ void PresentationWidget::paintEvent( QPaintEvent * pe ) // +const KPDFLink * PresentationWidget::getLink( int x, int y, QRect * geometry ) const +{ + // no links on invalid pages + if ( geometry && !geometry->isNull() ) + geometry->setRect( 0, 0, -1, -1 ); + if ( m_frameIndex < 0 || m_frameIndex >= (int)m_frames.size() ) + return 0; + + // get frame, page and geometry + const PresentationFrame * frame = m_frames[ m_frameIndex ]; + const KPDFPage * page = frame->page; + const QRect & frameGeometry = frame->geometry; + + // compute normalized x and y + double nx = (double)(x - frameGeometry.left()) / (double)frameGeometry.width(); + double ny = (double)(y - frameGeometry.top()) / (double)frameGeometry.height(); + + // no links outside the pages + if ( nx < 0 || nx > 1 || ny < 0 || ny > 1 ) + return 0; + + // check if 1) there is an object and 2) it's a link + const ObjectRect * object = page->hasObject( ObjectRect::Link, nx, ny ); + if ( !object ) + return 0; + + // compute link geometry if destination rect present + if ( geometry ) + { + *geometry = object->geometry( frameGeometry.width(), frameGeometry.height() ); + geometry->moveBy( frameGeometry.left(), frameGeometry.top() ); + } + + // return the link pointer + return (KPDFLink *)object->pointer(); +} + +void PresentationWidget::testCursorOnLink( int x, int y ) +{ + // get rect + QRect linkRect; + const KPDFLink * link = getLink( x, y, &linkRect ); + + // only react on changes (in/out from a link) + if ( (link && !m_handCursor) || (!link && m_handCursor) ) + { + // change cursor shape + m_handCursor = link != 0; + setCursor( m_handCursor ? KCursor::handCursor() : KCursor::arrowCursor()); + } +} + void PresentationWidget::overlayClick( const QPoint & position ) { // clicking the progress indicator @@ -356,12 +440,20 @@ void PresentationWidget::changePage( int newPage ) // notifyPixmapChanged call or else we can proceed to pixmap generation if ( !frame->page->hasPixmap( PRESENTATION_ID, pixW, pixH ) ) { + // operation will take long: set busy cursor + QApplication::setOverrideCursor( KCursor::workingCursor() ); + // request the pixmap QValueList< PixmapRequest * > request; request.push_back( new PixmapRequest( PRESENTATION_ID, m_frameIndex, pixW, pixH, PRESENTATION_PRIO ) ); m_document->requestPixmaps( request ); + // restore cursor + QApplication::restoreOverrideCursor(); } else + { + // make the background pixmap generatePage(); + } } void PresentationWidget::generatePage() @@ -395,6 +487,13 @@ void PresentationWidget::generatePage() KPDFPageTransition trans = defaultTransition(); initTransition( &trans ); } + + // update cursor + tooltip + if ( KpdfSettings::slidesCursor() != KpdfSettings::EnumSlidesCursor::Hidden ) + { + QPoint p = mapFromGlobal( QCursor::pos() ); + testCursorOnLink( p.x(), p.y() ); + } } void PresentationWidget::generateIntroPage( QPainter & p ) @@ -477,12 +576,14 @@ void PresentationWidget::generateContentsPage( int pageNum, QPainter & p ) } } +// from Arthur - Qt4 - (is defined elsewhere as 'qt_div_255' to not break final compilation) +inline int qt_div255(int x) { return (x + (x>>8) + 0x80) >> 8; } void PresentationWidget::generateOverlay() { #ifdef ENABLE_PROGRESS_OVERLAY // calculate overlay geometry and resize pixmap if needed int side = m_width / 16; - m_overlayGeometry.setRect( m_width - side, 0, side, side ); + m_overlayGeometry.setRect( m_width - side - 4, 4, side, side ); if ( m_lastRenderedOverlay.width() != side ) m_lastRenderedOverlay.resize( side, side ); @@ -496,13 +597,14 @@ void PresentationWidget::generateOverlay() // draw PIE SLICES in blue levels (the levels will then be the alpha component) int pages = m_document->pages(); - if ( pages > 36 ) + if ( pages > 28 ) { // draw continuous slices int degrees = (int)( 360 * (float)(m_frameIndex + 1) / (float)pages ); - pixmapPainter.setPen( 0x20 ); - pixmapPainter.setBrush( 0x10 ); + pixmapPainter.setPen( 0x05 ); + pixmapPainter.setBrush( 0x40 ); pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, (360-degrees)*16 ); - pixmapPainter.setBrush( 0xC0 ); + pixmapPainter.setPen( 0x40 ); + pixmapPainter.setBrush( 0xF0 ); pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, -degrees*16 ); } else @@ -512,7 +614,7 @@ void PresentationWidget::generateOverlay() { float newCoord = -90 + 360 * (float)(i + 1) / (float)pages; pixmapPainter.setPen( i <= m_frameIndex ? 0x40 : 0x05 ); - pixmapPainter.setBrush( i <= m_frameIndex ? 0xC0 : 0x10 ); + pixmapPainter.setBrush( i <= m_frameIndex ? 0xF0 : 0x40 ); pixmapPainter.drawPie( 2, 2, side - 4, side - 4, (int)( -16*(oldCoord + 1) ), (int)( -16*(newCoord - (oldCoord + 2)) ) ); oldCoord = newCoord; @@ -533,15 +635,52 @@ void PresentationWidget::generateOverlay() // end drawing pixmap and halve image pixmapPainter.end(); - side /= 2; - QImage image( doublePixmap.convertToImage().smoothScale( side, side ) ); + QImage image( doublePixmap.convertToImage().smoothScale( side / 2, side / 2 ) ); image.setAlphaBuffer( true ); - int red = 52, green = 115, blue = 178, - pixels = image.width() * image.height(); - unsigned int * data = (unsigned int *)image.bits(); - for( int i = 0; i < pixels; ++i ) - data[i] = qRgba( red, green, blue, data[i] & 0xFF ); + // draw circular shadow using the same technique + doublePixmap.fill( Qt::black ); + pixmapPainter.begin( &doublePixmap ); + pixmapPainter.setPen( 0x40 ); + pixmapPainter.setBrush( 0x80 ); + pixmapPainter.drawEllipse( 0, 0, side, side ); + pixmapPainter.end(); + QImage shadow( doublePixmap.convertToImage().smoothScale( side / 2, side / 2 ) ); + + // generate a 2 colors pixmap using mixing shadow (made with highlight color) + // and image (made with highlightedText color) + QColor color = palette().active().highlightedText(); + int red = color.red(), green = color.green(), blue = color.blue(); + color = palette().active().highlight(); + int sRed = color.red(), sGreen = color.green(), sBlue = color.blue(); + // pointers + unsigned int * data = (unsigned int *)image.bits(), + * shadowData = (unsigned int *)shadow.bits(), + pixels = image.width() * image.height(); + // cache data (reduce computation time to 26%!) + int c1 = -1, c2 = -1, cR = 0, cG = 0, cB = 0, cA = 0; + // foreach pixel + for( unsigned int i = 0; i < pixels; ++i ) + { + // alpha for shadow and image + int shadowAlpha = shadowData[i] & 0xFF, + srcAlpha = data[i] & 0xFF; + // cache values + if ( srcAlpha != c1 || shadowAlpha != c2 ) + { + c1 = srcAlpha; + c2 = shadowAlpha; + // fuse color components and alpha value of image over shadow + data[i] = qRgba( + cR = qt_div255( srcAlpha * red + (255 - srcAlpha) * sRed ), + cG = qt_div255( srcAlpha * green + (255 - srcAlpha) * sGreen ), + cB = qt_div255( srcAlpha * blue + (255 - srcAlpha) * sBlue ), + cA = qt_div255( srcAlpha * srcAlpha + (255 - srcAlpha) * shadowAlpha ) + ); + } + else + data[i] = qRgba( cR, cG, cB, cA ); + } m_lastRenderedOverlay.convertFromImage( image ); // start the autohide timer diff --git a/ui/presentationwidget.h b/ui/presentationwidget.h index fd59855fa..d601fb179 100644 --- a/ui/presentationwidget.h +++ b/ui/presentationwidget.h @@ -22,6 +22,7 @@ class QTimer; class KPDFDocument; class KPDFPage; +class KPDFLink; class PresentationFrame; /** @@ -49,10 +50,13 @@ class PresentationWidget : public QDialog, public DocumentObserver void keyPressEvent( QKeyEvent * e ); void wheelEvent( QWheelEvent * e ); void mousePressEvent( QMouseEvent * e ); + void mouseReleaseEvent( QMouseEvent * e ); void mouseMoveEvent( QMouseEvent * e ); void paintEvent( QPaintEvent * e ); private: + const KPDFLink * getLink( int x, int y, QRect * geometry = 0 ) const; + void testCursorOnLink( int x, int y ); void overlayClick( const QPoint & position ); void changePage( int newPage ); void generatePage(); @@ -69,6 +73,8 @@ class PresentationWidget : public QDialog, public DocumentObserver QPixmap m_lastRenderedPixmap; QPixmap m_lastRenderedOverlay; QRect m_overlayGeometry; + const KPDFLink * m_pressedLink; + bool m_handCursor; // transition related QTimer * m_transitionTimer; From fe6563b64eb154286faa47652bbc4708de588c5d Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Tue, 19 Jul 2005 16:25:45 +0000 Subject: [PATCH 119/245] Versionning svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=436380 --- ui/pageview.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index d191696b0..9bef43c38 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -1105,6 +1105,8 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) // preferred reader ("" is the default voice) ... QByteArray data; QDataStream arg( &data, IO_WriteOnly ); + + arg.setVersion(QDataStream::Qt_3_1); arg << selectedText; arg << QString(); DCOPCString replyType; @@ -1114,6 +1116,8 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) { QByteArray data2; QDataStream arg2(&data2, IO_WriteOnly); + + arg2.setVersion(QDataStream::Qt_3_1); arg2 << 0; client->send("kttsd", "KSpeech", "startText(uint)", data2 ); } From 1d4dfafd5c8bcc4736bb06092dfb6753d8ad4535 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 19 Jul 2005 18:41:57 +0000 Subject: [PATCH 120/245] compile for kde 3.4 lib users svn path=/trunk/KDE/kdegraphics/kpdf/; revision=436424 --- ui/pageview.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index b59f21258..675099634 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -179,7 +179,9 @@ void PageView::setupActions( KActionCollection * ac ) // Zoom actions ( higher scales takes lots of memory! ) d->aZoom = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, this, SLOT( slotZoom() ), ac, "zoom_to" ); d->aZoom->setEditable( true ); +#if KDE_IS_VERSION(3,4,89) d->aZoom->setMaxComboViewCount( 13 ); +#endif updateZoomText(); KStdAction::zoomIn( this, SLOT( slotZoomIn() ), ac, "zoom_in" ); From 2101e21fb2daad535c671e9f1ff1c07a915260db Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 21 Jul 2005 14:04:24 +0000 Subject: [PATCH 121/245] Fix crash of poppler bug 3728 PAge 21 content does not appear but does not appear either on Acrobat 7 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=437303 --- xpdf/splash/Splash.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/xpdf/splash/Splash.cc b/xpdf/splash/Splash.cc index 1a372b67b..c6ec23de1 100644 --- a/xpdf/splash/Splash.cc +++ b/xpdf/splash/Splash.cc @@ -633,6 +633,11 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, } xPath = new SplashXPath(path, state->flatness, gTrue); xPath->sort(); + if (!&xPath->segs[0]) + { + delete xPath; + return splashErrEmptyPath; + } scanner = new SplashXPathScanner(xPath, eo); // get the min and max x and y values From fd070e110c97411a7917be1faa98c322ae12e1ab Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 21 Jul 2005 14:28:08 +0000 Subject: [PATCH 122/245] Fix crash on document available on poppler bug 3750 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=437316 --- xpdf/splash/Splash.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/xpdf/splash/Splash.cc b/xpdf/splash/Splash.cc index c6ec23de1..916786a58 100644 --- a/xpdf/splash/Splash.cc +++ b/xpdf/splash/Splash.cc @@ -240,6 +240,11 @@ SplashError Splash::stroke(SplashPath *path) { return splashErrEmptyPath; } xPath = new SplashXPath(path, state->flatness, gFalse); + if (!xPath->segs) + { + delete xPath; + return splashErrEmptyPath; + } if (state->lineDashLength > 0) { xPath2 = makeDashedPath(xPath); delete xPath; From 31326cbb425c9c10a1e0cebf482c37300b00e942 Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Sat, 23 Jul 2005 15:24:22 +0000 Subject: [PATCH 123/245] Yes/No dialog buttons are bad for usability svn path=/trunk/KDE/kdegraphics/kpdf/; revision=437918 --- core/document.cpp | 2 +- part.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 8b562888f..1b0154887 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -732,7 +732,7 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar { if ( currentPage >= pageCount ) { - if ( noDialogs || KMessageBox::questionYesNo(0, i18n("End of document reached.\nContinue from the beginning?")) == KMessageBox::Yes ) + if ( noDialogs || KMessageBox::questionYesNo(0, i18n("End of document reached.\nContinue from the beginning?"), QString::null, KStdGuiItem::cont(), KStdGuiItem::cancel()) == KMessageBox::Yes ) currentPage = 0; else break; diff --git a/part.cpp b/part.cpp index 54b8eae1d..efa5485ea 100644 --- a/part.cpp +++ b/part.cpp @@ -648,7 +648,7 @@ void Part::slotSaveFileAs() { if ( KIO::NetAccess::exists( saveURL, false, widget() ) ) { - if (KMessageBox::questionYesNo( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.filename())) != KMessageBox::Yes) + if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.filename(), QString::null, i18n("Overwrite"))) != KMessageBox::Continue) return; } From 3b9073ed4a322a91e0af944d2c5db40c5610c788 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 25 Jul 2005 20:42:53 +0000 Subject: [PATCH 124/245] Work on bad jpeg data that have garbage before the start marker. Fixes poppler bug #3299 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=438716 --- xpdf/xpdf/DCTStream.cc | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/xpdf/xpdf/DCTStream.cc b/xpdf/xpdf/DCTStream.cc index 868065114..a28554c14 100644 --- a/xpdf/xpdf/DCTStream.cc +++ b/xpdf/xpdf/DCTStream.cc @@ -64,6 +64,44 @@ void DCTStream::reset() { int row_stride; str->reset(); + + // JPEG data has to start with 0xFF 0xD8 + // but some pdf like the one on + // https://bugs.freedesktop.org/show_bug.cgi?id=3299 + // does have some garbage before that this seeks for + // the start marker... + bool startFound = false; + int c = 0, c2 = 0; + int n = 0; + while (!startFound) + { + if (!c) + { + c = str->getChar(); + if (c != 0xFF) c = 0; + if (c == -1) + { + error(-1, "Could not find start of jpeg data"); + exit(1); + } + } + else + { + c2 = str->getChar(); + if (c2 != 0xD8) + { + c = 0; + c2 = 0; + } + else startFound = true; + } + n++; + } + + // ...and this skips the garbage + str->reset(); + for (n = n - 2; n > 0; n--) str->getChar(); + jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); From dc1137ce0acbd3dcbedce04cb9fabe2ffbec818b Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 26 Jul 2005 21:02:31 +0000 Subject: [PATCH 125/245] Fix for crash in document from poppler bug 3344 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=439007 --- xpdf/fofi/FoFiType1.cc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/xpdf/fofi/FoFiType1.cc b/xpdf/fofi/FoFiType1.cc index 1ee5175f7..780368d65 100644 --- a/xpdf/fofi/FoFiType1.cc +++ b/xpdf/fofi/FoFiType1.cc @@ -186,17 +186,13 @@ void FoFiType1::parse() { } } } - } else { - p = strtok(buf, " \t\n\r"); - if (p) - { - if (!strcmp(p, "def")) break; - if (!strcmp(p, "readonly")) break; - // the spec does not says this but i'm mantaining old xpdf behaviour that accepts "foo def" as end of the encoding array - p = strtok(buf, " \t\n\r"); - if (p && !strcmp(p, "def")) break; - } } + + // Any line that begins with "def" or contains " def" + // terminates the encoding array. + if (!strcmp (p, "def") || strstr (buf, " def")) + break; + line = line1; } //~ check for getinterval/putinterval junk From 06772ef8d4de4771803c91742e8a58cd53eaf18d Mon Sep 17 00:00:00 2001 From: Enrico Ros Date: Thu, 28 Jul 2005 13:30:00 +0000 Subject: [PATCH 126/245] simple fixes to get this port compiling again. thanks to Albert who made kpdf run! making patches against annotations/ branch now. svn path=/branches/work/kde4/kdegraphics/kpdf/; revision=439565 --- part.cpp | 2 +- ui/presentationwidget.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/part.cpp b/part.cpp index 9a95ca1fc..5e111edaf 100644 --- a/part.cpp +++ b/part.cpp @@ -110,7 +110,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURL(const KURL &) ) ); connect( m_document, SIGNAL( close() ), this, SLOT( close() ) ); - if (parent && parent->metaObject()->slotNames(true).contains("slotQuit()")) + if ( parent && parent->metaObject()->indexOfSlot( SLOT( slotQuit() ) ) != -1 ) connect( m_document, SIGNAL( quit() ), parent, SLOT( slotQuit() ) ); else connect( m_document, SIGNAL( quit() ), this, SLOT( cannotQuit() ) ); diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index 76c0be609..ff0c3f5df 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -654,7 +654,8 @@ void PresentationWidget::generateOverlay() doublePixmap.fill( Qt::black ); pixmapPainter.begin( &doublePixmap ); pixmapPainter.setPen( 0x40 ); - pixmapPainter.setBrush( 0x80 ); +#warning QPainter.setBrush(0x80) ???? port this +// pixmapPainter.setBrush( 0x80 ); pixmapPainter.drawEllipse( 0, 0, side, side ); pixmapPainter.end(); QImage shadow( doublePixmap.convertToImage().smoothScale( side / 2, side / 2 ) ); From 3eb7c7ea55d0b100ccdfb3bc8febbbdd872cdb7a Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 29 Jul 2005 19:27:08 +0000 Subject: [PATCH 127/245] Remove the toc when closing the doc svn path=/trunk/KDE/kdegraphics/kpdf/; revision=440089 --- ui/toc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/toc.cpp b/ui/toc.cpp index ac9e4fad4..c06342821 100644 --- a/ui/toc.cpp +++ b/ui/toc.cpp @@ -75,7 +75,7 @@ uint TOC::observerId() const void TOC::notifySetup( const QVector< KPDFPage * > & pages, bool documentChanged ) { - if ( !documentChanged || pages.size() < 1 ) + if ( !documentChanged ) return; // clear contents From fc33ec93c7399b973d87f2e19a587ce78d088562 Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Sat, 30 Jul 2005 19:15:21 +0000 Subject: [PATCH 128/245] SVN_SILENT fixuifiles, i18n style guide fixes svn path=/trunk/KDE/kdegraphics/kpdf/; revision=440533 --- conf/dlggeneral.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/dlggeneral.ui b/conf/dlggeneral.ui index 89278e9ec..3d471da34 100644 --- a/conf/dlggeneral.ui +++ b/conf/dlggeneral.ui @@ -89,7 +89,7 @@ kcfg_WatchFile - &Watch File + &Watch file From cd61012bc5dc9b57b4fe2ad014665882bb4746d6 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 1 Aug 2005 19:16:29 +0000 Subject: [PATCH 129/245] Fix for the fix of poppler bug 3299 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=442148 --- xpdf/xpdf/DCTStream.cc | 15 ++++++++++----- xpdf/xpdf/DCTStream.h | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/xpdf/xpdf/DCTStream.cc b/xpdf/xpdf/DCTStream.cc index a28554c14..6e55ae39d 100644 --- a/xpdf/xpdf/DCTStream.cc +++ b/xpdf/xpdf/DCTStream.cc @@ -15,7 +15,15 @@ static void str_init_source(j_decompress_ptr /*cinfo*/) static boolean str_fill_input_buffer(j_decompress_ptr cinfo) { struct str_src_mgr * src = (struct str_src_mgr *)cinfo->src; - src->buffer = src->str->getChar(); + if (src->index == 0) { + src->buffer = 0xFF; + src->index++; + } + else if (src->index == 1) { + src->buffer = 0xD8; + src->index++; + } + else src->buffer = src->str->getChar(); src->pub.next_input_byte = &src->buffer; src->pub.bytes_in_buffer = 1; return TRUE; @@ -50,6 +58,7 @@ DCTStream::DCTStream(Stream *strA): src.pub.bytes_in_buffer = 0; src.pub.next_input_byte = NULL; src.str = str; + src.index = 0; cinfo.src = (jpeg_source_mgr *)&src; cinfo.err = jpeg_std_error(&jerr); x = 0; @@ -98,10 +107,6 @@ void DCTStream::reset() { n++; } - // ...and this skips the garbage - str->reset(); - for (n = n - 2; n > 0; n--) str->getChar(); - jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); diff --git a/xpdf/xpdf/DCTStream.h b/xpdf/xpdf/DCTStream.h index 064e690ef..885899d3b 100644 --- a/xpdf/xpdf/DCTStream.h +++ b/xpdf/xpdf/DCTStream.h @@ -44,6 +44,7 @@ struct str_src_mgr { struct jpeg_source_mgr pub; JOCTET buffer; Stream *str; + int index; }; From 63536d9ccc66207b1035c44ca69c19afe8ed65b5 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 2 Aug 2005 16:43:41 +0000 Subject: [PATCH 130/245] Fordwardoprt fix for bug 110034 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=442424 --- xpdf/xpdf/PDFDoc.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xpdf/xpdf/PDFDoc.cc b/xpdf/xpdf/PDFDoc.cc index efcda9533..4fcc8904a 100644 --- a/xpdf/xpdf/PDFDoc.cc +++ b/xpdf/xpdf/PDFDoc.cc @@ -115,9 +115,9 @@ PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { str->reset(); - char eof[8]; + char eof[9]; int pos = str->getPos(); - str->setPos(7, -1); + str->setPos(8, -1); eof[0] = str->getChar(); eof[1] = str->getChar(); eof[2] = str->getChar(); @@ -125,7 +125,8 @@ GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { eof[4] = str->getChar(); eof[5] = str->getChar(); eof[6] = str->getChar(); - eof[7] = '\0'; + eof[7] = str->getChar(); + eof[8] = '\0'; if (strstr(eof, "%%EOF") == NULL) { error(-1, "Document does not have ending %%EOF"); From a902f4c5ddd2088f355dd95c336454841d161586 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 2 Aug 2005 17:08:36 +0000 Subject: [PATCH 131/245] Fordward port fix for bug 110000 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=442430 --- xpdf/xpdf/PDFDoc.cc | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/xpdf/xpdf/PDFDoc.cc b/xpdf/xpdf/PDFDoc.cc index 4fcc8904a..3f363cdab 100644 --- a/xpdf/xpdf/PDFDoc.cc +++ b/xpdf/xpdf/PDFDoc.cc @@ -115,24 +115,19 @@ PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { str->reset(); - char eof[9]; + char *eof = new char[1025]; int pos = str->getPos(); - str->setPos(8, -1); - eof[0] = str->getChar(); - eof[1] = str->getChar(); - eof[2] = str->getChar(); - eof[3] = str->getChar(); - eof[4] = str->getChar(); - eof[5] = str->getChar(); - eof[6] = str->getChar(); - eof[7] = str->getChar(); - eof[8] = '\0'; + str->setPos(1024, -1); + for (int i = 0; i < 1024; i++) eof[i] = str->getChar(); + eof[1024] = '\0'; if (strstr(eof, "%%EOF") == NULL) { error(-1, "Document does not have ending %%EOF"); errCode = errDamaged; + delete[] eof; return gFalse; } + delete[] eof; str->setPos(pos); From 1b80842a80963ba089a7b4473cf0927d5a3b2df6 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 5 Aug 2005 22:23:19 +0000 Subject: [PATCH 132/245] Fordward port unbreak back fix svn path=/trunk/KDE/kdegraphics/kpdf/; revision=443371 --- part.cpp | 15 ++++++++++----- part.h | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/part.cpp b/part.cpp index 5e111edaf..84f442e33 100644 --- a/part.cpp +++ b/part.cpp @@ -107,7 +107,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, connect( m_document, SIGNAL( linkGoToPage() ), this, SLOT( slotGoToPage() ) ); connect( m_document, SIGNAL( linkPresentation() ), this, SLOT( slotShowPresentation() ) ); connect( m_document, SIGNAL( linkEndPresentation() ), this, SLOT( slotHidePresentation() ) ); - connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURL(const KURL &) ) ); + connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURLFromDocument(const KURL &) ) ); connect( m_document, SIGNAL( close() ), this, SLOT( close() ) ); if ( parent && parent->metaObject()->indexOfSlot( SLOT( slotQuit() ) ) != -1 ) @@ -158,7 +158,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, m_searchWidget = new SearchWidget( thumbsBox, m_document ); m_thumbnailList = new ThumbnailList( thumbsBox, m_document ); // ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList ); - connect( m_thumbnailList, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURL( const KURL & )) ); + connect( m_thumbnailList, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURLFromDocument( const KURL & )) ); connect( m_thumbnailList, SIGNAL( rightClick(const KPDFPage *, const QPoint &) ), this, SLOT( slotShowMenu(const KPDFPage *, const QPoint &) ) ); // shrink the bottom controller toolbar (too hackish..) thumbsBox->setStretchFactor( m_searchWidget, 100 ); @@ -192,7 +192,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, // widgets: [] | [right 'pageView'] m_pageView = new PageView( m_splitter, m_document ); m_pageView->setFocus(); //usability setting - connect( m_pageView, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURL( const KURL & ))); + connect( m_pageView, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURLFromDocument( const KURL & ))); connect( m_pageView, SIGNAL( rightClick(const KPDFPage *, const QPoint &) ), this, SLOT( slotShowMenu(const KPDFPage *, const QPoint &) ) ); // add document observers @@ -412,6 +412,13 @@ bool Part::openFile() return true; } +void Part::openURLFromDocument(const KURL &url) +{ + m_bExtension->openURLNotify(); + m_bExtension->setLocationBarURL(url.prettyURL()); + openURL(url); +} + bool Part::openURL(const KURL &url) { // note: this can be the right place to check the file for gz or bz2 extension @@ -420,8 +427,6 @@ bool Part::openURL(const KURL &url) // this calls the above 'openURL' method bool b = KParts::ReadOnlyPart::openURL(url); - m_bExtension->openURLNotify(); - m_bExtension->setLocationBarURL(url.prettyURL()); if ( !b ) KMessageBox::error( widget(), i18n("Could not open %1").arg( url.prettyURL() ) ); else diff --git a/part.h b/part.h index 5c744c0f7..c81a9a989 100644 --- a/part.h +++ b/part.h @@ -88,6 +88,7 @@ protected: bool closeURL(); protected slots: + void openURLFromDocument(const KURL &url); // connected to actions void slotGoToPage(); void slotPreviousPage(); From 203b594c3c947e092eb8aaee696858ec933724ce Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 6 Aug 2005 12:05:41 +0000 Subject: [PATCH 133/245] improve last 1024 bytes EOF seek svn path=/trunk/KDE/kdegraphics/kpdf/; revision=443469 --- xpdf/xpdf/PDFDoc.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/xpdf/xpdf/PDFDoc.cc b/xpdf/xpdf/PDFDoc.cc index 3f363cdab..f5d94eacf 100644 --- a/xpdf/xpdf/PDFDoc.cc +++ b/xpdf/xpdf/PDFDoc.cc @@ -118,8 +118,15 @@ GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { char *eof = new char[1025]; int pos = str->getPos(); str->setPos(1024, -1); - for (int i = 0; i < 1024; i++) eof[i] = str->getChar(); - eof[1024] = '\0'; + int i, ch; + for (i = 0; i < 1024; i++) + { + ch = str->getChar(); + if (ch == EOF) + break; + eof[i] = ch; + } + eof[i] = '\0'; if (strstr(eof, "%%EOF") == NULL) { error(-1, "Document does not have ending %%EOF"); From 92e24720f47a248b5a4e6f7f254b887a443c8760 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 7 Aug 2005 23:57:56 +0000 Subject: [PATCH 134/245] Fix %EOF checking svn path=/trunk/KDE/kdegraphics/kpdf/; revision=443938 --- xpdf/xpdf/PDFDoc.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/xpdf/xpdf/PDFDoc.cc b/xpdf/xpdf/PDFDoc.cc index f5d94eacf..627720a69 100644 --- a/xpdf/xpdf/PDFDoc.cc +++ b/xpdf/xpdf/PDFDoc.cc @@ -127,7 +127,15 @@ GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { eof[i] = ch; } eof[i] = '\0'; - if (strstr(eof, "%%EOF") == NULL) + + bool found = false; + for (i = i - 5; i >= 0; i--) { + if (strncmp (&eof[i], "%%EOF", 5) == 0) { + found = true; + break; + } + } + if (!found) { error(-1, "Document does not have ending %%EOF"); errCode = errDamaged; From ada90ac31ab2a2874102befdeed421fcf11618f7 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Tue, 16 Aug 2005 11:51:14 +0000 Subject: [PATCH 135/245] Fix crash on x86_64 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=449674 --- xpdf/xpdf/JPXStream.cc | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/xpdf/xpdf/JPXStream.cc b/xpdf/xpdf/JPXStream.cc index 1919cc685..4f65b7a3d 100644 --- a/xpdf/xpdf/JPXStream.cc +++ b/xpdf/xpdf/JPXStream.cc @@ -1995,7 +1995,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; } if (y0+y1 > cb->y0) { - diag += (coeff[-tileComp->cbW - 1].flags + diag += (coeff[-(int)tileComp->cbW - 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2009,7 +2009,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; } if (y0+y1 > cb->y0) { - diag += (coeff[-tileComp->cbW + 1].flags + diag += (coeff[-(int)tileComp->cbW + 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2018,9 +2018,9 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } } if (y0+y1 > cb->y0) { - if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) { + if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) { ++vert; - vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign) + vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign) ? -1 : 1; } } @@ -2070,7 +2070,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, if (x > cb->x0) { all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1; if (y0+y1 > cb->y0) { - all += (coeff[-tileComp->cbW - 1].flags + all += (coeff[-(int)tileComp->cbW - 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2081,7 +2081,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, if (x < cb->x1 - 1) { all += (coeff[1].flags >> jpxCoeffSignificantB) & 1; if (y0+y1 > cb->y0) { - all += (coeff[-tileComp->cbW + 1].flags + all += (coeff[-(int)tileComp->cbW + 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2090,7 +2090,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } } if (y0+y1 > cb->y0) { - all += (coeff[-tileComp->cbW].flags + all += (coeff[-(int)tileComp->cbW].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2128,12 +2128,12 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) && !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) && (x == cb->x0 || y0 == cb->y0 || - !(coeff1[-tileComp->cbW - 1].flags + !(coeff1[-(int)tileComp->cbW - 1].flags & jpxCoeffSignificant)) && (y0 == cb->y0 || - !(coeff1[-tileComp->cbW].flags & jpxCoeffSignificant)) && + !(coeff1[-(int)tileComp->cbW].flags & jpxCoeffSignificant)) && (x == cb->x1 - 1 || y0 == cb->y0 || - !(coeff1[-tileComp->cbW + 1].flags & jpxCoeffSignificant)) && + !(coeff1[-(int)tileComp->cbW + 1].flags & jpxCoeffSignificant)) && (x == cb->x0 || (!(coeff1[-1].flags & jpxCoeffSignificant) && !(coeff1[tileComp->cbW - 1].flags @@ -2196,7 +2196,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; } if (y0+y1 > cb->y0) { - diag += (coeff[-tileComp->cbW - 1].flags + diag += (coeff[-(int)tileComp->cbW - 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2210,7 +2210,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; } if (y0+y1 > cb->y0) { - diag += (coeff[-tileComp->cbW + 1].flags + diag += (coeff[-(int)tileComp->cbW + 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2219,9 +2219,9 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } } if (y0+y1 > cb->y0) { - if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) { + if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) { ++vert; - vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign) + vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign) ? -1 : 1; } } From 34f58b4a02f356e2830e168b49c2245d4b3a91bf Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 17 Aug 2005 22:42:22 +0000 Subject: [PATCH 136/245] Disable zlib based decoder from poppler as it causes bugs svn path=/trunk/KDE/kdegraphics/kpdf/; revision=450336 --- xpdf/xpdf/Makefile.am | 2 +- xpdf/xpdf/Stream.cc | 3 +-- xpdf/xpdf/Stream.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am index 1f21260c8..97a2ada5f 100644 --- a/xpdf/xpdf/Makefile.am +++ b/xpdf/xpdf/Makefile.am @@ -4,7 +4,7 @@ libxpdf_la_LDFLAGS = $(all_libraries) libxpdf_la_LIBADD = $(LIB_X11) $(LIBFREETYPE_LIBS) $(LIBPAPER_LIBS) $(XFT_LIBS) $(LIBJPEG) ../goo/libgoo.la ../fofi/libfofi.la ../splash/libsplash.la libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ Catalog.cc CharCodeToUnicode.cc CMap.cc Decrypt.cc Dict.cc DCTStream.cc \ - FontEncodingTables.cc FlateStream.cc Function.cc Gfx.cc \ + FontEncodingTables.cc Function.cc Gfx.cc \ GfxFont.cc GfxState.cc GlobalParams.cc JArithmeticDecoder.cc \ JBIG2Stream.cc Lexer.cc Link.cc NameToCharCode.cc Object.cc Outline.cc \ OutputDev.cc PDFDoc.cc PDFDocEncoding.cc PSTokenizer.cc \ diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc index ba2552047..e0ee890c6 100644 --- a/xpdf/xpdf/Stream.cc +++ b/xpdf/xpdf/Stream.cc @@ -33,7 +33,6 @@ #include "JPXStream.h" #include "Stream-CCITT.h" #include "DCTStream.h" -#include "FlateStream.h" #ifdef __DJGPP__ static GBool setDJSYSFLAGS = gFalse; @@ -3179,6 +3178,7 @@ GString *DCTStream::getPSFilter(int psLevel, const char *indent) { GBool DCTStream::isBinary(GBool /*last*/) { return str->isBinary(gTrue); } +#endif //------------------------------------------------------------------------ // FlateStream @@ -3710,7 +3710,6 @@ int FlateStream::getCodeWord(int bits) { codeSize -= bits; return c; } -#endif //------------------------------------------------------------------------ // EOFStream diff --git a/xpdf/xpdf/Stream.h b/xpdf/xpdf/Stream.h index cca65c65c..bc1e077c8 100644 --- a/xpdf/xpdf/Stream.h +++ b/xpdf/xpdf/Stream.h @@ -637,6 +637,7 @@ private: int readMarker(); int read16(); }; +#endif //------------------------------------------------------------------------ // FlateStream @@ -712,7 +713,6 @@ private: int getHuffmanCodeWord(FlateHuffmanTab *tab); int getCodeWord(int bits); }; -#endif //------------------------------------------------------------------------ // EOFStream From 07a7017c79cef4c7c6b54d242f8f4636746e607f Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 18 Aug 2005 18:36:13 +0000 Subject: [PATCH 137/245] Fordwardport the xpdf 3.01 merge svn path=/trunk/KDE/kdegraphics/kpdf/; revision=450656 --- core/generator_pdf/generator_pdf.cpp | 42 +- core/generator_pdf/gp_outputdev.cpp | 116 +- core/generator_pdf/gp_outputdev.h | 55 +- core/page.cpp | 18 +- xpdf/aconf.h | 3 + xpdf/fofi/FoFiTrueType.cc | 410 ++++- xpdf/fofi/FoFiTrueType.h | 17 +- xpdf/fofi/FoFiType1.cc | 24 +- xpdf/fofi/FoFiType1C.cc | 136 +- xpdf/fofi/FoFiType1C.h | 6 + xpdf/goo/GHash.cc | 28 +- xpdf/goo/GHash.h | 2 + xpdf/goo/GList.cc | 13 +- xpdf/goo/GList.h | 5 + xpdf/goo/GString.cc | 85 +- xpdf/goo/GString.h | 11 +- xpdf/goo/gmem.c | 25 + xpdf/goo/gmem.h | 9 + xpdf/splash/Splash.cc | 2356 +++++++++++++++++++++----- xpdf/splash/Splash.h | 86 +- xpdf/splash/SplashBitmap.cc | 207 ++- xpdf/splash/SplashBitmap.h | 13 +- xpdf/splash/SplashClip.cc | 12 +- xpdf/splash/SplashClip.h | 9 + xpdf/splash/SplashFTFont.cc | 59 +- xpdf/splash/SplashFTFont.h | 3 +- xpdf/splash/SplashFTFontEngine.cc | 40 +- xpdf/splash/SplashFTFontEngine.h | 1 + xpdf/splash/SplashFTFontFile.cc | 2 +- xpdf/splash/SplashFont.cc | 10 +- xpdf/splash/SplashFont.h | 10 +- xpdf/splash/SplashFontEngine.cc | 6 - xpdf/splash/SplashPath.cc | 11 +- xpdf/splash/SplashPath.h | 5 + xpdf/splash/SplashPattern.cc | 22 +- xpdf/splash/SplashPattern.h | 19 +- xpdf/splash/SplashScreen.cc | 110 +- xpdf/splash/SplashScreen.h | 12 +- xpdf/splash/SplashState.cc | 15 +- xpdf/splash/SplashState.h | 3 + xpdf/splash/SplashT1Font.cc | 23 +- xpdf/splash/SplashT1Font.h | 2 + xpdf/splash/SplashT1FontFile.cc | 4 +- xpdf/splash/SplashTypes.h | 141 +- xpdf/splash/SplashXPath.cc | 63 +- xpdf/splash/SplashXPathScanner.cc | 20 +- xpdf/xpdf/Annot.cc | 231 ++- xpdf/xpdf/Annot.h | 8 +- xpdf/xpdf/Array.cc | 2 +- xpdf/xpdf/BuiltinFont.cc | 2 +- xpdf/xpdf/CMap.cc | 36 +- xpdf/xpdf/Catalog.cc | 25 +- xpdf/xpdf/Catalog.h | 3 + xpdf/xpdf/CharCodeToUnicode.cc | 45 +- xpdf/xpdf/CharCodeToUnicode.h | 2 - xpdf/xpdf/Decrypt.cc | 24 +- xpdf/xpdf/Decrypt.h | 6 +- xpdf/xpdf/Dict.cc | 2 +- xpdf/xpdf/Function.cc | 91 +- xpdf/xpdf/Function.h | 42 + xpdf/xpdf/Gfx.cc | 693 +++++++- xpdf/xpdf/Gfx.h | 17 +- xpdf/xpdf/GfxFont.cc | 134 +- xpdf/xpdf/GfxState.cc | 1422 ++++++++++++++-- xpdf/xpdf/GfxState.h | 197 ++- xpdf/xpdf/GlobalParams.cc | 371 +++- xpdf/xpdf/GlobalParams.h | 39 +- xpdf/xpdf/JArithmeticDecoder.cc | 42 +- xpdf/xpdf/JArithmeticDecoder.h | 22 +- xpdf/xpdf/JBIG2Stream.cc | 93 +- xpdf/xpdf/JBIG2Stream.h | 2 +- xpdf/xpdf/JPXStream.cc | 314 +++- xpdf/xpdf/JPXStream.h | 25 +- xpdf/xpdf/Lexer.cc | 11 + xpdf/xpdf/Lexer.h | 3 + xpdf/xpdf/Link.cc | 70 +- xpdf/xpdf/Makefile.am | 2 +- xpdf/xpdf/NameToCharCode.cc | 4 +- xpdf/xpdf/NameToUnicodeTable.h | 170 +- xpdf/xpdf/Object.cc | 2 +- xpdf/xpdf/Outline.cc | 6 +- xpdf/xpdf/OutputDev.cc | 27 +- xpdf/xpdf/OutputDev.h | 45 +- xpdf/xpdf/PDFDoc.cc | 151 +- xpdf/xpdf/PDFDoc.h | 46 +- xpdf/xpdf/PSOutputDev.cc | 1519 ++++++++++++++--- xpdf/xpdf/PSOutputDev.h | 51 +- xpdf/xpdf/Page.cc | 116 +- xpdf/xpdf/Page.h | 21 +- xpdf/xpdf/Parser.cc | 39 +- xpdf/xpdf/Parser.h | 4 - xpdf/xpdf/SplashOutputDev.cc | 1523 +++++++++++++++-- xpdf/xpdf/SplashOutputDev.h | 65 +- xpdf/xpdf/Stream.cc | 744 +++++++- xpdf/xpdf/Stream.h | 34 +- xpdf/xpdf/TextOutputDev.cc | 270 ++- xpdf/xpdf/TextOutputDev.h | 20 +- xpdf/xpdf/UnicodeMap.cc | 6 +- xpdf/xpdf/UnicodeTypeTable.cc | 694 +++++++- xpdf/xpdf/UnicodeTypeTable.h | 2 + xpdf/xpdf/XRef.cc | 202 +-- xpdf/xpdf/XRef.h | 20 +- 102 files changed, 11433 insertions(+), 2593 deletions(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 3c2343c60..f7ce136f6 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -175,8 +175,8 @@ bool PDFGenerator::loadDocument( const QString & filePath, QVector & pagesVector.resize( pageCount ); for ( uint i = 0; i < pageCount ; i++ ) { - KPDFPage * page = new KPDFPage( i, pdfdoc->getPageWidth(i+1), - pdfdoc->getPageHeight(i+1), + KPDFPage * page = new KPDFPage( i, pdfdoc->getPageMediaWidth(i+1), + pdfdoc->getPageMediaHeight(i+1), pdfdoc->getPageRotate(i+1) ); addTransition( i, page ); pagesVector[i] = page; @@ -312,19 +312,20 @@ void PDFGenerator::generatePixmap( PixmapRequest * request ) // 1. Set OutputDev parameters and Generate contents // note: thread safety is set on 'false' for the GUI (this) thread - kpdfOutputDev->setParams( request->width, request->height, genTextPage, genObjectRects, genObjectRects, false ); - pdfdoc->displayPage( kpdfOutputDev, page->number() + 1, fakeDpiX, fakeDpiY, 0, true, genObjectRects ); + kpdfOutputDev->setParams( request->width, request->height, genObjectRects, genObjectRects, false ); + pdfdoc->displayPage( kpdfOutputDev, page->number() + 1, fakeDpiX, fakeDpiY, 0, false, true, genObjectRects ); // 2. Take data from outputdev and attach it to the Page page->setPixmap( request->id, kpdfOutputDev->takePixmap() ); - if ( genTextPage ) - page->setSearchPage( kpdfOutputDev->takeTextPage() ); if ( genObjectRects ) page->setObjectRects( kpdfOutputDev->takeObjectRects() ); // 3. UNLOCK [re-enables shared access] docLock.unlock(); + if ( genTextPage ) + generateSyncTextPage( page ); + // update ready state ready = true; @@ -334,12 +335,12 @@ void PDFGenerator::generatePixmap( PixmapRequest * request ) void PDFGenerator::generateSyncTextPage( KPDFPage * page ) { - // build a TextPage using the lightweight KPDFTextDev generator.. - KPDFTextDev td; + // build a TextPage... + TextOutputDev td(NULL, gTrue, gFalse, gFalse); docLock.lock(); - pdfdoc->displayPage( &td, page->number()+1, 72, 72, 0, true, false ); + pdfdoc->displayPage( &td, page->number()+1, 72, 72, 0, false, true, false ); // ..and attach it to the page - page->setSearchPage( td.takeTextPage() ); + page->setSearchPage( td.takeText() ); docLock.unlock(); } @@ -381,7 +382,7 @@ void PDFGenerator::putFontInfo(KListView *list) { scanFonts(resDict, list, &fonts, fontsLen, fontsSize); } - annots = new Annots(pdfdoc->getXRef(), page->getAnnots(&obj1)); + annots = new Annots(pdfdoc->getXRef(), pdfdoc->getCatalog(), page->getAnnots(&obj1)); obj1.free(); for (i = 0; i < annots->getNumAnnots(); ++i) { @@ -447,7 +448,7 @@ bool PDFGenerator::print( KPrinter& printer ) } docLock.lock(); - pdfdoc->displayPages(psOut, pages, 72, 72, 0, globalParams->getPSCrop(), gFalse); + pdfdoc->displayPages(psOut, pages, 72, 72, 0, false, globalParams->getPSCrop(), gFalse); docLock.unlock(); // needs to be here so that the file is flushed, do not merge with the one @@ -509,7 +510,9 @@ bool PDFGenerator::reparseConfig() { paperColor = color; SplashColor splashCol; - splashCol.rgb8 = splashMakeRGB8( paperColor.red(), paperColor.green(), paperColor.blue() ); + splashCol[0] = paperColor.red(); + splashCol[1] = paperColor.green(); + splashCol[2] = paperColor.blue(); // rebuild the output device using the new paper color and initialize it docLock.lock(); delete kpdfOutputDev; @@ -1089,10 +1092,10 @@ void PDFPixmapGeneratorThread::run() d->generator->docLock.lock(); // 1. set OutputDev parameters and Generate contents - d->generator->kpdfOutputDev->setParams( width, height, genTextPage, + d->generator->kpdfOutputDev->setParams( width, height, genObjectRects, genObjectRects, TRUE /*thread safety*/ ); d->generator->pdfdoc->displayPage( d->generator->kpdfOutputDev, page->number() + 1, - fakeDpiX, fakeDpiY, 0, true, genObjectRects ); + fakeDpiX, fakeDpiY, 0, false, true, genObjectRects ); // 2. grab data from the OutputDev and store it locally (note takeIMAGE) #ifndef NDEBUG @@ -1102,10 +1105,17 @@ void PDFPixmapGeneratorThread::run() kdDebug() << "PDFPixmapGeneratorThread: previous textpage not taken" << endl; #endif d->m_image = d->generator->kpdfOutputDev->takeImage(); - d->m_textPage = d->generator->kpdfOutputDev->takeTextPage(); d->m_rects = d->generator->kpdfOutputDev->takeObjectRects(); d->m_rectsTaken = false; + if ( genTextPage ) + { + TextOutputDev td(NULL, gTrue, gFalse, gFalse); + d->generator->pdfdoc->displayPage( &td, page->number()+1, 72, 72, 0, false, true, false ); + // ..and attach it to the page + d->m_textPage = td.takeText(); + } + // 3. [UNLOCK] mutex d->generator->docLock.unlock(); diff --git a/core/generator_pdf/gp_outputdev.cpp b/core/generator_pdf/gp_outputdev.cpp index 5a1bbe95d..4e621f556 100644 --- a/core/generator_pdf/gp_outputdev.cpp +++ b/core/generator_pdf/gp_outputdev.cpp @@ -38,8 +38,8 @@ /** KPDFOutputDev implementation **/ KPDFOutputDev::KPDFOutputDev( SplashColor paperColor ) - : SplashOutputDev( splashModeRGB8, false, paperColor ), - m_doc( 0 ), m_pixmap( 0 ), m_image( 0 ), m_text( 0 ) + : SplashOutputDev( splashModeRGB8, 4, false, paperColor ), + m_doc( 0 ), m_pixmap( 0 ), m_image( 0 ) { } @@ -54,7 +54,7 @@ void KPDFOutputDev::initDevice( PDFDoc * pdfDoc ) startDoc( pdfDoc->getXRef() ); } -void KPDFOutputDev::setParams( int width, int height, bool genT, bool genL, bool genI, bool safe ) +void KPDFOutputDev::setParams( int width, int height, bool genL, bool genI, bool safe ) { clear(); @@ -62,12 +62,8 @@ void KPDFOutputDev::setParams( int width, int height, bool genT, bool genL, bool m_pixmapHeight = height; m_qtThreadSafety = safe; - m_generateText = genT; m_generateLinks = genL; m_generateImages = genI; - - if ( m_generateText ) - m_text = new TextPage( gFalse ); } QPixmap * KPDFOutputDev::takePixmap() @@ -84,13 +80,6 @@ QImage * KPDFOutputDev::takeImage() return img; } -TextPage * KPDFOutputDev::takeTextPage() -{ - TextPage * text = m_text; - m_text = 0; - return text; -} - QList< ObjectRect * > KPDFOutputDev::takeObjectRects() { if ( m_rects.isEmpty() ) @@ -101,27 +90,29 @@ QList< ObjectRect * > KPDFOutputDev::takeObjectRects() } //BEGIN - OutputDev hooked calls -void KPDFOutputDev::startPage( int pageNum, GfxState *state ) -{ - if ( m_generateText ) - m_text->startPage( state ); - SplashOutputDev::startPage( pageNum, state ); -} - void KPDFOutputDev::endPage() { SplashOutputDev::endPage(); - if ( m_generateText ) - { - m_text->endPage(); - m_text->coalesce( gTrue ); - } int bh = getBitmap()->getHeight(), bw = getBitmap()->getWidth(); - SplashColorPtr dataPtr = getBitmap()->getDataPtr(); + // TODO The below loop can be avoided if using the code that is commented here and + // we change splashModeRGB8 to splashModeARGB8 the problem is that then bug101800.pdf + // does not work +/* SplashColorPtr dataPtr = getBitmap()->getDataPtr(); // construct a qimage SHARING the raw bitmap data in memory - QImage * img = new QImage( (uchar*)dataPtr.rgb8, bw, bh, 32, 0, 0, QImage::IgnoreEndian ); + QImage * img = new QImage( dataPtr, bw, bh, 32, 0, 0, QImage::IgnoreEndian );*/ + QImage * img = new QImage( bw, bh, 32 ); + SplashColorPtr pixel = new Guchar[4]; + for (int i = 0; i < bw; i++) + { + for (int j = 0; j < bh; j++) + { + getBitmap()->getPixel(i, j, pixel); + img->setPixel( i, j, qRgb( pixel[0], pixel[1], pixel[2] ) ); + } + } + delete pixel; // use the QImage or convert it immediately to QPixmap for better // handling and memory unloading @@ -180,27 +171,6 @@ void KPDFOutputDev::drawLink( Link * link, Catalog * catalog ) SplashOutputDev::drawLink( link, catalog ); } -void KPDFOutputDev::updateFont( GfxState *state ) -{ - if ( m_generateText ) - m_text->updateFont( state ); - SplashOutputDev::updateFont( state ); -} - -void KPDFOutputDev::drawChar( GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, Unicode *u, int uLen ) -{ - if ( m_generateText ) - m_text->addChar( state, x, y, dx, dy, code, u, uLen ); - SplashOutputDev::drawChar( state, x, y, dx, dy, originX, originY, code, u, uLen ); -} - -GBool KPDFOutputDev::beginType3Char( GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen ) -{ - if ( m_generateText ) - m_text->addChar( state, x, y, dx, dy, code, u, uLen ); - return SplashOutputDev::beginType3Char( state, x, y, dx, dy, code, u, uLen ); -} - void KPDFOutputDev::drawImage( GfxState *state, Object *ref, Stream *str, int _width, int _height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg ) { @@ -264,12 +234,6 @@ void KPDFOutputDev::clear() delete m_image; m_image = 0; } - // delete text - if ( m_text ) - { - delete m_text; - m_text = 0; - } } KPDFLink * KPDFOutputDev::generateLink( LinkAction * a ) @@ -423,45 +387,3 @@ DocumentViewport KPDFOutputDev::decodeViewport( GString * namedDest, LinkDest * } //END - private helpers - -/** KPDFTextDev implementation **/ - -KPDFTextDev::KPDFTextDev() -{ - m_text = new TextPage( gFalse ); -} - -KPDFTextDev::~KPDFTextDev() -{ - delete m_text; -} - -TextPage * KPDFTextDev::takeTextPage() -{ - TextPage * t = m_text; - m_text = 0; - return t; -} - -void KPDFTextDev::startPage( int, GfxState *state ) -{ - if ( !m_text ) - m_text = new TextPage( gFalse ); - m_text->startPage( state ); -} - -void KPDFTextDev::endPage() -{ - m_text->endPage(); - m_text->coalesce( gTrue ); -} - -void KPDFTextDev::updateFont( GfxState *state ) -{ - m_text->updateFont( state ); -} - -void KPDFTextDev::drawChar( GfxState *state, double x, double y, double dx, double dy, double /*originX*/, double /*originY*/, CharCode code, Unicode *u, int uLen ) -{ - m_text->addChar( state, x, y, dx, dy, code, u, uLen ); -} diff --git a/core/generator_pdf/gp_outputdev.h b/core/generator_pdf/gp_outputdev.h index 738d60c5d..ee8951687 100644 --- a/core/generator_pdf/gp_outputdev.h +++ b/core/generator_pdf/gp_outputdev.h @@ -24,7 +24,6 @@ #include "xpdf/SplashOutputDev.h" class QPixmap; -class TextPage; class KPDFLink; class ObjectRect; class DocumentViewport; @@ -49,27 +48,19 @@ class KPDFOutputDev : public SplashOutputDev // set parameters before rendering *each* page // @param qtThreadSafety: duplicate memory buffer (slow but safe) - void setParams( int pixmapWidth, int pixmapHeight, bool generateTextPage, + void setParams( int pixmapWidth, int pixmapHeight, bool decodeLinks, bool decodeImages, bool qtThreadSafety = false ); // takes pointers out of the class (so deletion it's up to others) QPixmap * takePixmap(); QImage * takeImage(); - TextPage * takeTextPage(); QList< ObjectRect * > takeObjectRects(); /** inherited from OutputDev */ - // Start a page. - virtual void startPage(int pageNum, GfxState *state); // End a page. virtual void endPage(); //----- link borders virtual void drawLink(Link *link, Catalog *catalog); - //----- update text state - virtual void updateFont(GfxState *state); - //----- text drawing - virtual void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, Unicode *u, int uLen); - virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen); //----- image drawing virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); @@ -84,7 +75,6 @@ class KPDFOutputDev : public SplashOutputDev // generator switches and parameters bool m_qtThreadSafety; - bool m_generateText; bool m_generateLinks; bool m_generateImages; int m_pixmapWidth; @@ -94,50 +84,7 @@ class KPDFOutputDev : public SplashOutputDev PDFDoc * m_doc; QPixmap * m_pixmap; QImage * m_image; - TextPage * m_text; // text page generated on demand QList< ObjectRect * > m_rects; // objectRects (links/images) }; - -/** - * @short Collect text into a takeable TextPage. - * - * This is the simplest OutputDev. It harvests text from currently - * rendered page and provides a method for getting the TextPage. - * Xpdf's textOutputDev can't return a textpage, unfortunately, and - * KPDFOutputDev is too heavy for sucha a simple task. - */ -class KPDFTextDev : public OutputDev -{ - public: - KPDFTextDev(); - virtual ~KPDFTextDev(); - - // takes pointers out of the class (so deletion it's up to others) - TextPage * takeTextPage(); - - /** inherited from OutputDev */ - // top left corner is (0,0) - virtual GBool upsideDown() { return gTrue; } - // use draw char to get text data - virtual GBool useDrawChar() { return gTrue; } - // use drawChar even for Type3 chars - virtual GBool interpretType3Chars() { return gFalse; } - // do not pass non-text to this device - virtual GBool needNonText() { return gFalse; } - - // Start a page. - virtual void startPage(int, GfxState *state); - // End a page. - virtual void endPage(); - //----- update text state - virtual void updateFont(GfxState *state); - //----- text drawing - virtual void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, Unicode *u, int uLen); - - private: - // text page generated by execution - TextPage * m_text; -}; - #endif diff --git a/core/page.cpp b/core/page.cpp index fe3b67b22..ecd512306 100644 --- a/core/page.cpp +++ b/core/page.cpp @@ -130,27 +130,17 @@ NormalizedRect * KPDFPage::findText( const QString & text, bool strictCase, Norm while ( !found ) { if ( dir == FromTop ) - found = m_text->findText( u.data(), len, gTrue, gTrue, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom ); + found = m_text->findText( u.data(), len, gTrue, gTrue, gFalse, gFalse, strictCase, gFalse, &sLeft, &sTop, &sRight, &sBottom ); else if ( dir == NextMatch ) - found = m_text->findText( u.data(), len, gFalse, gTrue, gTrue, gFalse, &sLeft, &sTop, &sRight, &sBottom ); + found = m_text->findText( u.data(), len, gFalse, gTrue, gTrue, gFalse, strictCase, gFalse, &sLeft, &sTop, &sRight, &sBottom ); else if ( dir == PrevMatch ) // FIXME: this doesn't work as expected (luckily backward search isn't yet used) - found = m_text->findText( u.data(), len, gTrue, gFalse, gFalse, gTrue, &sLeft, &sTop, &sRight, &sBottom ); + // TODO: check if the new xpdf 3.01 code is able of searching backwards + found = m_text->findText( u.data(), len, gTrue, gFalse, gFalse, gTrue, strictCase, gTrue, &sLeft, &sTop, &sRight, &sBottom ); // if not found (even in case unsensitive search), terminate if ( !found ) break; - - // check for case sensitivity - if ( strictCase ) - { - // since we're in 'Case sensitive' mode, check if words are identical - GString * realText = m_text->getText( sLeft, sTop, sRight, sBottom ); - found = QString::fromUtf8( realText->getCString() ) == text; - if ( !found && dir == FromTop ) - dir = NextMatch; - delete realText; - } } // if the page was found, return a new normalizedRect diff --git a/xpdf/aconf.h b/xpdf/aconf.h index e2424621f..f86ea517a 100644 --- a/xpdf/aconf.h +++ b/xpdf/aconf.h @@ -9,3 +9,6 @@ #define OPI_SUPPORT 0 #define TEXTOUT_WORD_LIST 0 #define HAVE_MKSTEMPS 1 //libkdefakes provides it +#define SPLASH_CMYK 0 +#define HAVE_XPDFCORE 0 +#define HAVE_WINPDFCORE 0 diff --git a/xpdf/fofi/FoFiTrueType.cc b/xpdf/fofi/FoFiTrueType.cc index 5430df9ac..4165b8cad 100644 --- a/xpdf/fofi/FoFiTrueType.cc +++ b/xpdf/fofi/FoFiTrueType.cc @@ -13,6 +13,7 @@ #endif #include +#include #include "gtypes.h" #include "gmem.h" #include "GString.h" @@ -77,6 +78,10 @@ //------------------------------------------------------------------------ +#define ttcfTag 0x74746366 + +//------------------------------------------------------------------------ + struct TrueTypeTable { Guint tag; Guint checksum; @@ -102,6 +107,7 @@ struct TrueTypeLoca { #define cmapTag 0x636d6170 #define glyfTag 0x676c7966 +#define headTag 0x68656164 #define locaTag 0x6c6f6361 #define nameTag 0x6e616d65 #define postTag 0x706f7374 @@ -156,6 +162,8 @@ static T42Table t42Tables[nT42Tables] = { #define t42HeadTable 3 #define t42LocaTable 6 #define t42GlyfTable 2 +#define t42VheaTable 9 +#define t42VmtxTable 10 //------------------------------------------------------------------------ @@ -277,7 +285,9 @@ FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceI FoFiTrueType::~FoFiTrueType() { gfree(tables); gfree(cmaps); + if (nameToGID) { delete nameToGID; + } } int FoFiTrueType::getNumCmaps() { @@ -433,7 +443,7 @@ void FoFiTrueType::convertToType42(char *psName, const char **encoding, // write the guts of the dictionary cvtEncoding(encoding, outputFunc, outputStream); cvtCharStrings(encoding, codeToGID, outputFunc, outputStream); - cvtSfnts(outputFunc, outputStream, NULL); + cvtSfnts(outputFunc, outputStream, NULL, gFalse); // end the dictionary and define the font (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); @@ -441,6 +451,7 @@ void FoFiTrueType::convertToType42(char *psName, const char **encoding, void FoFiTrueType::convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream) { char buf[512]; @@ -541,7 +552,7 @@ void FoFiTrueType::convertToCIDType2(char *psName, (*outputFunc)(outputStream, " end readonly def\n", 19); // write the guts of the dictionary - cvtSfnts(outputFunc, outputStream, NULL); + cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics); // end the dictionary and define the font (*outputFunc)(outputStream, @@ -550,6 +561,7 @@ void FoFiTrueType::convertToCIDType2(char *psName, } void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream) { char buf[512]; @@ -558,7 +570,7 @@ void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, // write the Type 42 sfnts array sfntsName = (new GString(psName))->append("_sfnts"); - cvtSfnts(outputFunc, outputStream, sfntsName); + cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics); delete sfntsName; // write the descendant Type 42 fonts @@ -621,18 +633,28 @@ void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, } void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, - void *outputStream) { - static char cmapTab[20] = { + void *outputStream, char *name, + Gushort *codeToGID) { + // this substitute cmap table maps char codes 0000-ffff directly to + // glyphs 0000-ffff + static char cmapTab[36] = { 0, 0, // table version number 0, 1, // number of encoding tables 0, 1, // platform ID 0, 0, // encoding ID 0, 0, 0, 12, // offset of subtable - 0, 0, // subtable format - 0, 1, // subtable length - 0, 1, // subtable version - 0, // map char 0 -> glyph 0 - 0 // pad to multiple of four bytes + 0, 4, // subtable format + 0, 24, // subtable length + 0, 0, // subtable version + 0, 2, // segment count * 2 + 0, 2, // 2 * 2 ^ floor(log2(segCount)) + 0, 0, // floor(log2(segCount)) + 0, 0, // 2*segCount - 2*2^floor(log2(segCount)) + (char)0xff, (char)0xff, // endCount[0] + 0, 0, // reserved + 0, 0, // startCount[0] + 0, 0, // idDelta[0] + 0, 0 // pad to a mulitple of four bytes }; static char nameTab[8] = { 0, 0, // format @@ -655,9 +677,11 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, int nZeroLengthTables; TrueTypeLoca *locaTable; TrueTypeTable *newTables; - int nNewTables, cmapIdx, cmapLen, glyfLen; + char *newNameTab, *newCmapTab; + int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next; + Guint locaChecksum, glyfChecksum, fileChecksum; char *tableDir; - char locaBuf[4]; + char locaBuf[4], checksumBuf[4]; GBool ok; Guint t; int pos, i, j, k, n; @@ -668,7 +692,7 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, missingPost = seekTable("post") < 0; // read the loca table, check to see if it's sorted - locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca)); + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); unsortedLoca = gFalse; i = seekTable("loca"); pos = tables[i].offset; @@ -711,7 +735,7 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, // if nothing is broken, just write the TTF file as is if (!missingCmap && !missingName && !missingPost && !unsortedLoca && - !badCmapLen && nZeroLengthTables == 0) { + !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) { (*outputFunc)(outputStream, (char *)file, len); goto done1; } @@ -743,46 +767,206 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, glyfLen = pos; } + // compute checksums for the loca and glyf tables + locaChecksum = glyfChecksum = 0; + if (unsortedLoca) { + if (locaFmt) { + for (j = 0; j <= nGlyphs; ++j) { + locaChecksum += locaTable[j].newOffset; + } + } else { + for (j = 0; j <= nGlyphs; j += 2) { + locaChecksum += locaTable[j].newOffset << 16; + if (j + 1 <= nGlyphs) { + locaChecksum += locaTable[j+1].newOffset; + } + } + } + pos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + n = locaTable[j].len; + if (n > 0) { + k = locaTable[j].origOffset; + if (checkRegion(pos + k, n)) { + glyfChecksum += computeTableChecksum(file + pos + k, n); + } + } + } + } + + // construct the new name table + if (name) { + n = strlen(name); + newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3; + newNameTab = (char *)gmalloc(newNameLen); + memset(newNameTab, 0, newNameLen); + newNameTab[0] = 0; // format selector + newNameTab[1] = 0; + newNameTab[2] = 0; // number of name records + newNameTab[3] = 4; + newNameTab[4] = 0; // offset to start of string storage + newNameTab[5] = 6 + 4*12; + next = 0; + for (i = 0; i < 4; ++i) { + newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft + newNameTab[6 + i*12 + 1] = 3; + newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode + newNameTab[6 + i*12 + 3] = 1; + newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English + newNameTab[6 + i*12 + 5] = 0x09; + newNameTab[6 + i*12 + 6] = 0; // name ID + newNameTab[6 + i*12 + 7] = i + 1; + newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length + newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff); + newNameTab[6 + i*12 + 10] = next >> 8; // string offset + newNameTab[6 + i*12 + 11] = next & 0xff; + if (i+1 == 2) { + memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14); + next += 14; + } else { + for (j = 0; j < n; ++j) { + newNameTab[6 + 4*12 + next + 2*j] = 0; + newNameTab[6 + 4*12 + next + 2*j + 1] = name[j]; + } + next += 2*n; + } + } + } else { + newNameLen = 0; + newNameTab = NULL; + } + + // construct the new cmap table + if (codeToGID) { + newCmapLen = 44 + 256 * 2; + newCmapTab = (char *)gmalloc(newCmapLen); + newCmapTab[0] = 0; // table version number = 0 + newCmapTab[1] = 0; + newCmapTab[2] = 0; // number of encoding tables = 1 + newCmapTab[3] = 1; + newCmapTab[4] = 0; // platform ID = Microsoft + newCmapTab[5] = 3; + newCmapTab[6] = 0; // encoding ID = Unicode + newCmapTab[7] = 1; + newCmapTab[8] = 0; // offset of subtable + newCmapTab[9] = 0; + newCmapTab[10] = 0; + newCmapTab[11] = 12; + newCmapTab[12] = 0; // subtable format = 4 + newCmapTab[13] = 4; + newCmapTab[14] = 0x02; // subtable length + newCmapTab[15] = 0x20; + newCmapTab[16] = 0; // subtable version = 0 + newCmapTab[17] = 0; + newCmapTab[18] = 0; // segment count * 2 + newCmapTab[19] = 4; + newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount)) + newCmapTab[21] = 4; + newCmapTab[22] = 0; // floor(log2(segCount)) + newCmapTab[23] = 1; + newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount)) + newCmapTab[25] = 0; + newCmapTab[26] = 0x00; // endCount[0] + newCmapTab[27] = (char)0xff; + newCmapTab[28] = (char)0xff; // endCount[1] + newCmapTab[29] = (char)0xff; + newCmapTab[30] = 0; // reserved + newCmapTab[31] = 0; + newCmapTab[32] = 0x00; // startCount[0] + newCmapTab[33] = 0x00; + newCmapTab[34] = (char)0xff; // startCount[1] + newCmapTab[35] = (char)0xff; + newCmapTab[36] = 0; // idDelta[0] + newCmapTab[37] = 0; + newCmapTab[38] = 0; // idDelta[1] + newCmapTab[39] = 1; + newCmapTab[40] = 0; // idRangeOffset[0] + newCmapTab[41] = 4; + newCmapTab[42] = 0; // idRangeOffset[1] + newCmapTab[43] = 0; + for (i = 0; i < 256; ++i) { + newCmapTab[44 + 2*i] = codeToGID[i] >> 8; + newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff; + } + } else { + newCmapLen = 0; + newCmapTab = NULL; + } + // construct the new table directory: // - keep all original tables with non-zero length // - fix the cmap table's length, if necessary // - add missing tables // - sort the table by tag // - compute new table positions, including 4-byte alignment + // - (re)compute table checksums nNewTables = nTables - nZeroLengthTables + (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + (missingPost ? 1 : 0); - newTables = (TrueTypeTable *)gmalloc(nNewTables * sizeof(TrueTypeTable)); + newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); j = 0; for (i = 0; i < nTables; ++i) { if (tables[i].len > 0) { newTables[j] = tables[i]; newTables[j].origOffset = tables[i].offset; - if (newTables[j].tag == cmapTag && badCmapLen) { + if (checkRegion(tables[i].offset, newTables[i].len)) { + newTables[j].checksum = + computeTableChecksum(file + tables[i].offset, tables[i].len); + if (tables[i].tag == headTag) { + // don't include the file checksum + newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); + } + } + if (newTables[j].tag == cmapTag && codeToGID) { + newTables[j].len = newCmapLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + } else if (newTables[j].tag == cmapTag && badCmapLen) { newTables[j].len = cmapLen; } else if (newTables[j].tag == locaTag && unsortedLoca) { newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); + newTables[j].checksum = locaChecksum; } else if (newTables[j].tag == glyfTag && unsortedLoca) { newTables[j].len = glyfLen; + newTables[j].checksum = glyfChecksum; + } else if (newTables[j].tag == nameTag && name) { + newTables[j].len = newNameLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); } ++j; } } if (missingCmap) { newTables[j].tag = cmapTag; - newTables[j].checksum = 0; //~ should compute the checksum + if (codeToGID) { + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + newTables[j].len = newCmapLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, + sizeof(cmapTab)); newTables[j].len = sizeof(cmapTab); + } ++j; } if (missingName) { newTables[j].tag = nameTag; - newTables[j].checksum = 0; //~ should compute the checksum + if (name) { + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); + newTables[j].len = newNameLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)nameTab, + sizeof(nameTab)); newTables[j].len = sizeof(nameTab); + } ++j; } if (missingPost) { newTables[j].tag = postTag; - newTables[j].checksum = 0; //~ should compute the checksum + newTables[j].checksum = computeTableChecksum((Guchar *)postTab, + sizeof(postTab)); newTables[j].len = sizeof(postTab); ++j; } @@ -836,10 +1020,38 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, } (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16); + // compute the file checksum + fileChecksum = computeTableChecksum((Guchar *)tableDir, + 12 + nNewTables * 16); + for (i = 0; i < nNewTables; ++i) { + fileChecksum += newTables[i].checksum; + } + fileChecksum = 0xb1b0afba - fileChecksum; + // write the tables for (i = 0; i < nNewTables; ++i) { - if (newTables[i].tag == cmapTag && missingCmap) { + if (newTables[i].tag == headTag) { + if (checkRegion(newTables[i].origOffset, newTables[i].len)) { + (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8); + checksumBuf[0] = fileChecksum >> 24; + checksumBuf[1] = fileChecksum >> 16; + checksumBuf[2] = fileChecksum >> 8; + checksumBuf[3] = fileChecksum; + (*outputFunc)(outputStream, checksumBuf, 4); + (*outputFunc)(outputStream, + (char *)file + newTables[i].origOffset + 12, + newTables[i].len - 12); + } else { + for (j = 0; j < newTables[i].len; ++j) { + (*outputFunc)(outputStream, "\0", 1); + } + } + } else if (newTables[i].tag == cmapTag && codeToGID) { + (*outputFunc)(outputStream, newCmapTab, newTables[i].len); + } else if (newTables[i].tag == cmapTag && missingCmap) { (*outputFunc)(outputStream, cmapTab, newTables[i].len); + } else if (newTables[i].tag == nameTag && name) { + (*outputFunc)(outputStream, newNameTab, newTables[i].len); } else if (newTables[i].tag == nameTag && missingName) { (*outputFunc)(outputStream, nameTab, newTables[i].len); } else if (newTables[i].tag == postTag && missingPost) { @@ -891,6 +1103,8 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, } } + gfree(newCmapTab); + gfree(newNameTab); gfree(tableDir); gfree(newTables); done1: @@ -975,7 +1189,8 @@ void FoFiTrueType::cvtCharStrings(const char **encoding, } void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, - void *outputStream, GString *name) { + void *outputStream, GString *name, + GBool needVerticalMetrics) { Guchar headData[54]; TrueTypeLoca *locaTable; Guchar *locaData; @@ -985,6 +1200,28 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, Guint checksum; int nNewTables; int length, pos, glyfPos, i, j, k; + Guchar vheaTab[36] = { + 0, 1, 0, 0, // table version number + 0, 0, // ascent + 0, 0, // descent + 0, 0, // reserved + 0, 0, // max advance height + 0, 0, // min top side bearing + 0, 0, // min bottom side bearing + 0, 0, // y max extent + 0, 0, // caret slope rise + 0, 1, // caret slope run + 0, 0, // caret offset + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // metric data format + 0, 1 // number of advance heights in vmtx table + }; + Guchar *vmtxTab; + GBool needVhea, needVmtx; + int advance; // construct the 'head' table, zero out the font checksum i = seekTable("head"); @@ -1002,7 +1239,7 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, // table, cmpTrueTypeLocaPos uses offset as its primary sort key, // and idx as its secondary key (ensuring that adjacent entries with // the same pos value remain in the same order) - locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca)); + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); i = seekTable("loca"); pos = tables[i].offset; ok = gTrue; @@ -1032,7 +1269,7 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, } // construct the new 'loca' table - locaData = (Guchar *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2)); + locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2)); for (i = 0; i <= nGlyphs; ++i) { pos = locaTable[i].newOffset; if (locaFmt) { @@ -1054,6 +1291,22 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, ++nNewTables; } } + vmtxTab = NULL; // make gcc happy + advance = 0; // make gcc happy + if (needVerticalMetrics) { + needVhea = seekTable("vhea") < 0; + needVmtx = seekTable("vmtx") < 0; + if (needVhea || needVmtx) { + i = seekTable("head"); + advance = getU16BE(tables[i].offset + 18, &ok); // units per em + if (needVhea) { + ++nNewTables; + } + if (needVmtx) { + ++nNewTables; + } + } + } // construct the new table headers, including table checksums // (pad each table out to a multiple of 4 bytes) @@ -1089,6 +1342,21 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, if (checkRegion(tables[j].offset, length)) { checksum = computeTableChecksum(file + tables[j].offset, length); } + } else if (needVerticalMetrics && i == t42VheaTable) { + vheaTab[10] = advance / 256; // max advance height + vheaTab[11] = advance % 256; + length = sizeof(vheaTab); + checksum = computeTableChecksum(vheaTab, length); + } else if (needVerticalMetrics && i == t42VmtxTable) { + length = 4 + (nGlyphs - 1) * 4; + vmtxTab = (Guchar *)gmalloc(length); + vmtxTab[0] = advance / 256; + vmtxTab[1] = advance % 256; + for (j = 2; j < length; j += 2) { + vmtxTab[j] = 0; + vmtxTab[j+1] = 0; + } + checksum = computeTableChecksum(vmtxTab, length); } else if (t42Tables[i].required) { //~ error(-1, "Embedded TrueType font is missing a required table ('%s')", //~ t42Tables[i].tag); @@ -1194,6 +1462,11 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, checkRegion(tables[j].offset, tables[j].len)) { dumpString(file + tables[j].offset, tables[j].len, outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VheaTable) { + dumpString(vheaTab, length, outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VmtxTable) { + dumpString(vmtxTab, length, outputFunc, outputStream); + gfree(vmtxTab); } } } @@ -1263,22 +1536,17 @@ Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { return checksum; } -#define toTag(a,b,c,d) (((unsigned int)(a)<<24) | ((unsigned int)(b)<<16) | ((unsigned int)(c)<<8) | (d)) - void FoFiTrueType::parse() { + Guint topTag; int pos, i, j; - unsigned int head; - parsedOk = gTrue; + parsedOk = true; - pos = 0; - // read the table directory - head = getU32BE(pos, &parsedOk); + // look for a collection (TTC) + topTag = getU32BE(0, &parsedOk); if (! parsedOk) return; - if (head == toTag('t','t','c','f')) { - /* TTC font */ -// unsigned int tableDir; + if (topTag == ttcfTag) { int dircount; dircount = getU32BE(8, &parsedOk); @@ -1294,16 +1562,17 @@ void FoFiTrueType::parse() { pos = getU32BE(12 + faceIndex * 4, &parsedOk); if (! parsedOk) return; + } else { + pos = 0; } - pos += 4; - nTables = getU16BE(pos, &parsedOk); + nTables = getU16BE(pos + 4, &parsedOk); if (!parsedOk) { return; } - pos += 8; - tables = (TrueTypeTable *)gmalloc(nTables * sizeof(TrueTypeTable)); + tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable)); + pos += 12; for (i = 0; i < nTables; ++i) { tables[i].tag = getU32BE(pos, &parsedOk); tables[i].checksum = getU32BE(pos + 4, &parsedOk); @@ -1339,7 +1608,7 @@ void FoFiTrueType::parse() { if (!parsedOk) { return; } - cmaps = (TrueTypeCmap *)gmalloc(nCmaps * sizeof(TrueTypeCmap)); + cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap)); for (j = 0; j < nCmaps; ++j) { cmaps[j].platform = getU16BE(pos, &parsedOk); cmaps[j].encoding = getU16BE(pos + 2, &parsedOk); @@ -1373,25 +1642,45 @@ void FoFiTrueType::parse() { return; } - // read the post table - readPostTable(); + // make sure the loca table is sane (correct length and entries are + // in bounds) + i = seekTable("loca"); + if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) { + parsedOk = gFalse; + return; + } + for (j = 0; j <= nGlyphs; ++j) { + if (locaFmt) { + pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk); + } else { + pos = getU16BE(tables[i].offset + j*2, &parsedOk); + } + if (pos < 0 || pos > len) { + parsedOk = gFalse; + } + } if (!parsedOk) { return; } + + // read the post table + readPostTable(); } void FoFiTrueType::readPostTable() { GString *name; int tablePos, postFmt, stringIdx, stringPos; + GBool ok; int i, j, n, m; + ok = gTrue; if ((i = seekTable("post")) < 0) { return; } tablePos = tables[i].offset; - postFmt = getU32BE(tablePos, &parsedOk); - if (!parsedOk) { - return; + postFmt = getU32BE(tablePos, &ok); + if (!ok) { + goto err; } if (postFmt == 0x00010000) { nameToGID = new GHash(gTrue); @@ -1400,9 +1689,9 @@ void FoFiTrueType::readPostTable() { } } else if (postFmt == 0x00020000) { nameToGID = new GHash(gTrue); - n = getU16BE(tablePos + 32, &parsedOk); - if (!parsedOk) { - return; + n = getU16BE(tablePos + 32, &ok); + if (!ok) { + goto err; } if (n > nGlyphs) { n = nGlyphs; @@ -1410,7 +1699,7 @@ void FoFiTrueType::readPostTable() { stringIdx = 0; stringPos = tablePos + 34 + 2*n; for (i = 0; i < n; ++i) { - j = getU16BE(tablePos + 34 + 2*i, &parsedOk); + j = getU16BE(tablePos + 34 + 2*i, &ok); if (j < 258) { nameToGID->removeInt(macGlyphNames[j]); nameToGID->add(new GString(macGlyphNames[j]), i); @@ -1419,15 +1708,14 @@ void FoFiTrueType::readPostTable() { if (j != stringIdx) { for (stringIdx = 0, stringPos = tablePos + 34 + 2*n; stringIdx < j; - ++stringIdx, stringPos += 1 + getU8(stringPos, &parsedOk)) ; - if (!parsedOk) { - return; + ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ; + if (!ok) { + goto err; } } - m = getU8(stringPos, &parsedOk); - if (!parsedOk || !checkRegion(stringPos + 1, m)) { - parsedOk = gFalse; - return; + m = getU8(stringPos, &ok); + if (!ok || !checkRegion(stringPos + 1, m)) { + goto err; } name = new GString((char *)&file[stringPos + 1], m); nameToGID->removeInt(name); @@ -1439,9 +1727,9 @@ void FoFiTrueType::readPostTable() { } else if (postFmt == 0x00028000) { nameToGID = new GHash(gTrue); for (i = 0; i < nGlyphs; ++i) { - j = getU8(tablePos + 32 + i, &parsedOk); - if (!parsedOk) { - return; + j = getU8(tablePos + 32 + i, &ok); + if (!ok) { + goto err; } if (j < 258) { nameToGID->removeInt(macGlyphNames[j]); @@ -1449,6 +1737,14 @@ void FoFiTrueType::readPostTable() { } } } + + return; + +err: + if (nameToGID) { + delete nameToGID; + nameToGID = NULL; + } } int FoFiTrueType::seekTable(const char *tag) { diff --git a/xpdf/fofi/FoFiTrueType.h b/xpdf/fofi/FoFiTrueType.h index b3f7d3aca..b1e0d979b 100644 --- a/xpdf/fofi/FoFiTrueType.h +++ b/xpdf/fofi/FoFiTrueType.h @@ -18,6 +18,7 @@ #include "gtypes.h" #include "FoFiBase.h" +class GString; class GHash; struct TrueTypeTable; struct TrueTypeCmap; @@ -84,6 +85,7 @@ public: // font). The array maps CIDs to GIDs; it has // entries. void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream); // Convert to a Type 0 (but non-CID) composite font, suitable for @@ -92,13 +94,17 @@ public: // table in the font). The array maps CIDs to GIDs; it has // entries. void convertToType0(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream); // Write a clean TTF file, filling in missing tables and correcting - // various other errors. If the font is complete and correct, it - // will be written unmodified. - void writeTTF(FoFiOutputFunc outputFunc, void *outputStream); - + // various other errors. If is non-NULL, the font is renamed + // to . If is non-NULL, the font is re-encoded, + // using a Windows Unicode cmap. If is NULL and the font is + // complete and correct, it will be written unmodified. + void writeTTF(FoFiOutputFunc outputFunc, void *outputStream, + char *name = NULL, Gushort *codeToGID = NULL); + private: void cvtEncoding(const char **encoding, @@ -109,7 +115,8 @@ private: FoFiOutputFunc outputFunc, void *outputStream); void cvtSfnts(FoFiOutputFunc outputFunc, - void *outputStream, GString *name); + void *outputStream, GString *name, + GBool needVerticalMetrics); void dumpString(Guchar *s, int length, FoFiOutputFunc outputFunc, void *outputStream); diff --git a/xpdf/fofi/FoFiType1.cc b/xpdf/fofi/FoFiType1.cc index 780368d65..a1ef85e55 100644 --- a/xpdf/fofi/FoFiType1.cc +++ b/xpdf/fofi/FoFiType1.cc @@ -108,6 +108,9 @@ void FoFiType1::writeEncoded(char **newEncoding, for (line = getNextLine(line); line && strncmp(line, "readonly def", 12); line = getNextLine(line)) ; + if (line) { + line = getNextLine(line); + } } if (line) { (*outputFunc)(outputStream, line, ((char *)file + len) - line); @@ -156,12 +159,13 @@ void FoFiType1::parse() { encoding = fofiType1StandardEncoding; } else if (!encoding && !strncmp(line, "/Encoding 256 array", 19)) { - encoding = (const char **)gmalloc(256 * sizeof(char *)); + encoding = (const char **)gmallocn(256, sizeof(char *)); for (j = 0; j < 256; ++j) { encoding[j] = NULL; } - line = getNextLine(line); - for (j = 0; j < 300 && line; ++j) { + for (j = 0, line = getNextLine(line); + j < 300 && line && (line1 = getNextLine(line)); + ++j, line = line1) { line1 = getNextLine(line); if ((n = line1 - line) > 255) { n = 255; @@ -186,22 +190,18 @@ void FoFiType1::parse() { } } } - } - - // Any line that begins with "def" or contains " def" - // terminates the encoding array. - if (!strcmp (p, "def") || strstr (buf, " def")) + } else { + if (strtok(buf, " \t") && + (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { break; - - line = line1; + } + } } //~ check for getinterval/putinterval junk } else { line = getNextLine(line); } - - ++i; } parsed = gTrue; diff --git a/xpdf/fofi/FoFiType1C.cc b/xpdf/fofi/FoFiType1C.cc index 9ad602cdd..67b36a208 100644 --- a/xpdf/fofi/FoFiType1C.cc +++ b/xpdf/fofi/FoFiType1C.cc @@ -120,7 +120,7 @@ Gushort *FoFiType1C::getCIDToGIDMap(int *nCIDs) { } } ++n; - map = (Gushort *)gmalloc(n * sizeof(Gushort)); + map = (Gushort *)gmallocn(n, sizeof(Gushort)); memset(map, 0, n * sizeof(Gushort)); for (i = 0; i < nGlyphs; ++i) { map[charset[i]] = i; @@ -403,7 +403,7 @@ void FoFiType1C::convertToCIDType0(char *psName, nCIDs = charset[i] + 1; } } - cidMap = (int *)gmalloc(nCIDs * sizeof(int)); + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); for (i = 0; i < nCIDs; ++i) { cidMap[i] = -1; } @@ -413,7 +413,7 @@ void FoFiType1C::convertToCIDType0(char *psName, // build the charstrings charStrings = new GString(); - charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int)); + charStringOffsets = (int *)gmallocn(nCIDs + 1, sizeof(int)); for (i = 0; i < nCIDs; ++i) { charStringOffsets[i] = charStrings->getLength(); if ((gid = cidMap[i]) >= 0) { @@ -476,10 +476,18 @@ void FoFiType1C::convertToCIDType0(char *psName, sprintf(buf, " /Supplement %d def\n", topDict.supplement); (*outputFunc)(outputStream, buf, strlen(buf)); (*outputFunc)(outputStream, "end def\n", 8); + if (topDict.hasFontMatrix) { sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], - topDict.fontMatrix[3], topDict.fontMatrix[4], topDict.fontMatrix[5]); + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); (*outputFunc)(outputStream, buf, strlen(buf)); + } else if (privateDicts[0].hasFontMatrix) { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } else { + (*outputFunc)(outputStream, + "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); + } sprintf(buf, "/FontBBox [%g %g %g %g] def\n", topDict.fontBBox[0], topDict.fontBBox[1], topDict.fontBBox[2], topDict.fontBBox[3]); @@ -509,7 +517,18 @@ void FoFiType1C::convertToCIDType0(char *psName, sprintf(buf, "dup %d 10 dict begin\n", i); (*outputFunc)(outputStream, buf, strlen(buf)); (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + if (privateDicts[i].hasFontMatrix) { + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", + privateDicts[i].fontMatrix[0], + privateDicts[i].fontMatrix[1], + privateDicts[i].fontMatrix[2], + privateDicts[i].fontMatrix[3], + privateDicts[i].fontMatrix[4], + privateDicts[i].fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } else { (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } sprintf(buf, "/PaintType %d def\n", topDict.paintType); (*outputFunc)(outputStream, buf, strlen(buf)); (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); @@ -670,7 +689,7 @@ void FoFiType1C::convertToType0(char *psName, nCIDs = charset[i] + 1; } } - cidMap = (int *)gmalloc(nCIDs * sizeof(int)); + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); for (i = 0; i < nCIDs; ++i) { cidMap[i] = -1; } @@ -699,11 +718,21 @@ void FoFiType1C::convertToType0(char *psName, sprintf(buf, "_%02x def\n", i >> 8); (*outputFunc)(outputStream, buf, strlen(buf)); (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + if (privateDicts[fd].hasFontMatrix) { sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], - topDict.fontMatrix[2], topDict.fontMatrix[3], - topDict.fontMatrix[4], topDict.fontMatrix[5]); + privateDicts[fd].fontMatrix[0], + privateDicts[fd].fontMatrix[1], + privateDicts[fd].fontMatrix[2], + privateDicts[fd].fontMatrix[3], + privateDicts[fd].fontMatrix[4], + privateDicts[fd].fontMatrix[5]); (*outputFunc)(outputStream, buf, strlen(buf)); + } else if (topDict.hasFontMatrix) { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } else { + (*outputFunc)(outputStream, + "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); + } sprintf(buf, "/FontBBox [%g %g %g %g] def\n", topDict.fontBBox[0], topDict.fontBBox[1], topDict.fontBBox[2], topDict.fontBBox[3]); @@ -887,7 +916,15 @@ void FoFiType1C::convertToType0(char *psName, (*outputFunc)(outputStream, psName, strlen(psName)); (*outputFunc)(outputStream, " def\n", 5); (*outputFunc)(outputStream, "/FontType 0 def\n", 16); + if (topDict.hasFontMatrix) { + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } else { (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); (*outputFunc)(outputStream, "/Encoding [\n", 12); for (i = 0; i < nCIDs; i += 256) { @@ -947,6 +984,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, nOps = 0; nHints = 0; firstOp = gTrue; + openPath = gFalse; } pos = offset; @@ -970,6 +1008,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, d = 0; dFP = gFalse; for (k = 0; k < nOps; k += 2) { + // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints if (ops[k+1].num < 0) { d += ops[k].num + ops[k+1].num; dFP |= ops[k].isFP | ops[k+1].isFP; @@ -999,6 +1038,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, d = 0; dFP = gFalse; for (k = 0; k < nOps; k += 2) { + // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints if (ops[k+1].num < 0) { d += ops[k].num + ops[k+1].num; dFP |= ops[k].isFP | ops[k+1].isFP; @@ -1022,6 +1062,10 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, cvtGlyphWidth(nOps == 2, charBuf, pDict); firstOp = gFalse; } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } if (nOps != 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); } @@ -1039,6 +1083,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, charBuf->append((char)5); } nOps = 0; + openPath = gTrue; break; case 0x0006: // hlineto if (nOps < 1) { @@ -1049,6 +1094,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, charBuf->append((char)((k & 1) ? 7 : 6)); } nOps = 0; + openPath = gTrue; break; case 0x0007: // vlineto if (nOps < 1) { @@ -1059,6 +1105,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, charBuf->append((char)((k & 1) ? 6 : 7)); } nOps = 0; + openPath = gTrue; break; case 0x0008: // rrcurveto if (nOps < 6 || nOps % 6 != 0) { @@ -1074,6 +1121,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, charBuf->append((char)8); } nOps = 0; + openPath = gTrue; break; case 0x000a: // callsubr if (nOps >= 1) { @@ -1099,6 +1147,10 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, cvtGlyphWidth(nOps == 1 || nOps == 5, charBuf, pDict); firstOp = gFalse; } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } if (nOps == 4) { cvtNum(0, gFalse, charBuf); cvtNum(ops[0].num, ops[0].isFP, charBuf); @@ -1174,6 +1226,10 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, cvtGlyphWidth(nOps == 3, charBuf, pDict); firstOp = gFalse; } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } if (nOps != 2) { //~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); } @@ -1187,6 +1243,10 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, cvtGlyphWidth(nOps == 2, charBuf, pDict); firstOp = gFalse; } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } if (nOps != 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); } @@ -1223,6 +1283,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, cvtNum(ops[k+1].num, ops[k].isFP, charBuf); charBuf->append((char)5); nOps = 0; + openPath = gTrue; break; case 0x0019: // rlinecurve if (nOps < 8 || (nOps - 6) % 2 != 0) { @@ -1241,6 +1302,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); charBuf->append((char)8); nOps = 0; + openPath = gTrue; break; case 0x001a: // vvcurveto if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { @@ -1268,6 +1330,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, charBuf->append((char)8); } nOps = 0; + openPath = gTrue; break; case 0x001b: // hhcurveto if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { @@ -1295,6 +1358,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, charBuf->append((char)8); } nOps = 0; + openPath = gTrue; break; case 0x001d: // callgsubr if (nOps >= 1) { @@ -1348,6 +1412,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, charBuf->append((char)8); } nOps = 0; + openPath = gTrue; break; case 0x001f: // hvcurveto if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { @@ -1387,6 +1452,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, charBuf->append((char)8); } nOps = 0; + openPath = gTrue; break; case 0x0c00: // dotsection (should be Type 1 only?) // ignored @@ -1436,6 +1502,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, cvtNum(0, gFalse, charBuf); charBuf->append((char)8); nOps = 0; + openPath = gTrue; break; case 0x0c23: // flex if (nOps != 13) { @@ -1456,6 +1523,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, cvtNum(ops[11].num, ops[11].isFP, charBuf); charBuf->append((char)8); nOps = 0; + openPath = gTrue; break; case 0x0c24: // hflex1 if (nOps != 9) { @@ -1477,6 +1545,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, ops[1].isFP | ops[3].isFP | ops[7].isFP, charBuf); charBuf->append((char)8); nOps = 0; + openPath = gTrue; break; case 0x0c25: // flex1 if (nOps != 11) { @@ -1506,6 +1575,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, } charBuf->append((char)8); nOps = 0; + openPath = gTrue; break; default: //~ error(-1, "Illegal Type 2 charstring op: %04x", @@ -1692,7 +1762,7 @@ GBool FoFiType1C::parse() { } nFDs = fdIdx.len; privateDicts = (Type1CPrivateDict *) - gmalloc(nFDs * sizeof(Type1CPrivateDict)); + gmallocn(nFDs, sizeof(Type1CPrivateDict)); for (i = 0; i < nFDs; ++i) { getIndexVal(&fdIdx, i, &val, &parsedOk); if (!parsedOk) { @@ -1773,6 +1843,7 @@ void FoFiType1C::readTopDict() { topDict.fontMatrix[3] = 0.001; topDict.fontMatrix[4] = 0; topDict.fontMatrix[5] = 0; + topDict.hasFontMatrix = gFalse; topDict.uniqueID = 0; topDict.fontBBox[0] = 0; topDict.fontBBox[1] = 0; @@ -1821,7 +1892,8 @@ void FoFiType1C::readTopDict() { topDict.fontMatrix[2] = ops[2].num; topDict.fontMatrix[3] = ops[3].num; topDict.fontMatrix[4] = ops[4].num; - topDict.fontMatrix[5] = ops[5].num; break; + topDict.fontMatrix[5] = ops[5].num; + topDict.hasFontMatrix = gTrue; break; case 0x000d: topDict.uniqueID = (int)ops[0].num; break; case 0x0005: topDict.fontBBox[0] = ops[0].num; topDict.fontBBox[1] = ops[1].num; @@ -1845,10 +1917,14 @@ void FoFiType1C::readTopDict() { } // Read a CID font dict (FD) - this pulls out the private dict -// pointer, and reads the private dict. +// pointer, and reads the private dict. It also pulls the FontMatrix +// (if any) out of the FD. void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) { int pos, pSize, pOffset; + double fontMatrix[6]; + GBool hasFontMatrix; + hasFontMatrix = gFalse; pSize = pOffset = 0; pos = offset; nOps = 0; @@ -1866,17 +1942,35 @@ void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) { pSize = (int)ops[0].num; pOffset = (int)ops[1].num; break; + } else if (ops[nOps - 1].op == 0x0c07) { + fontMatrix[0] = ops[0].num; + fontMatrix[1] = ops[1].num; + fontMatrix[2] = ops[2].num; + fontMatrix[3] = ops[3].num; + fontMatrix[4] = ops[4].num; + fontMatrix[5] = ops[5].num; + hasFontMatrix = gTrue; } nOps = 0; } } readPrivateDict(pOffset, pSize, pDict); + if (hasFontMatrix) { + pDict->fontMatrix[0] = fontMatrix[0]; + pDict->fontMatrix[1] = fontMatrix[1]; + pDict->fontMatrix[2] = fontMatrix[2]; + pDict->fontMatrix[3] = fontMatrix[3]; + pDict->fontMatrix[4] = fontMatrix[4]; + pDict->fontMatrix[5] = fontMatrix[5]; + pDict->hasFontMatrix = gTrue; + } } void FoFiType1C::readPrivateDict(int offset, int length, Type1CPrivateDict *pDict) { int pos; + pDict->hasFontMatrix = gFalse; pDict->nBlueValues = 0; pDict->nOtherBlues = 0; pDict->nFamilyBlues = 0; @@ -1895,9 +1989,9 @@ void FoFiType1C::readPrivateDict(int offset, int length, pDict->initialRandomSeed = 0; pDict->subrsOffset = 0; pDict->defaultWidthX = 0; - pDict->defaultWidthXFP = 0; + pDict->defaultWidthXFP = gFalse; pDict->nominalWidthX = 0; - pDict->nominalWidthXFP = 0; + pDict->nominalWidthXFP = gFalse; // no dictionary if (offset == 0 || length == 0) { @@ -1976,9 +2070,11 @@ void FoFiType1C::readPrivateDict(int offset, int length, break; case 0x0014: pDict->defaultWidthX = ops[0].num; + pDict->defaultWidthXFP = ops[0].isFP; break; case 0x0015: pDict->nominalWidthX = ops[0].num; + pDict->nominalWidthXFP = ops[0].isFP; break; } nOps = 0; @@ -2049,7 +2145,7 @@ void FoFiType1C::buildEncoding() { encoding = fofiType1ExpertEncoding; } else { - encoding = (const char **)gmalloc(256 * sizeof(char *)); + encoding = (const char **)gmallocn(256, sizeof(char *)); for (i = 0; i < 256; ++i) { encoding[i] = NULL; } @@ -2136,7 +2232,7 @@ GBool FoFiType1C::readCharset() { } else if (topDict.charsetOffset == 2) { charset = fofiType1CExpertSubsetCharset; } else { - charset = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort)); + charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort)); for (i = 0; i < nGlyphs; ++i) { charset[i] = 0; } @@ -2321,9 +2417,9 @@ void FoFiType1C::getIndex(int pos, Type1CIndex *idx, GBool *ok) { idx->pos = pos; idx->len = getU16BE(pos, ok); if (idx->len == 0) { - // empty indexes are legal + // empty indexes are legal and contain just the length field idx->offSize = 0; - idx->startPos = idx->endPos = 0; + idx->startPos = idx->endPos = pos + 2; } else { idx->offSize = getU8(pos + 2, ok); if (idx->offSize < 1 || idx->offSize > 4) { @@ -2353,7 +2449,7 @@ void FoFiType1C::getIndexVal(Type1CIndex *idx, int i, idx->offSize, ok); pos1 = idx->startPos + getUVarBE(idx->pos + 3 + (i + 1) * idx->offSize, idx->offSize, ok); - if (pos0 < idx->startPos || pos0 >= idx->endPos || + if (pos0 < idx->startPos || pos0 > idx->endPos || pos1 <= idx->startPos || pos1 > idx->endPos || pos1 < pos0) { *ok = gFalse; @@ -2371,7 +2467,7 @@ char *FoFiType1C::getString(int sid, char *buf, GBool *ok) { } else { sid -= 391; getIndexVal(&stringIdx, sid, &val, ok); - if (ok) { + if (*ok) { if ((n = val.len) > 255) { n = 255; } diff --git a/xpdf/fofi/FoFiType1C.h b/xpdf/fofi/FoFiType1C.h index 1b980c7ea..a6c027388 100644 --- a/xpdf/fofi/FoFiType1C.h +++ b/xpdf/fofi/FoFiType1C.h @@ -51,6 +51,9 @@ struct Type1CTopDict { int paintType; int charstringType; double fontMatrix[6]; + GBool hasFontMatrix; // CID fonts are allowed to put their + // FontMatrix in the FD instead of the + // top dict int uniqueID; double fontBBox[4]; double strokeWidth; @@ -73,6 +76,8 @@ struct Type1CTopDict { #define type1CMaxStemSnap 12 struct Type1CPrivateDict { + double fontMatrix[6]; + GBool hasFontMatrix; int blueValues[type1CMaxBlueValues]; int nBlueValues; int otherBlues[type1CMaxOtherBlues]; @@ -221,6 +226,7 @@ private: int nOps; // number of operands int nHints; // number of hints for the current glyph GBool firstOp; // true if we haven't hit the first op yet + GBool openPath; // true if there is an unclosed path }; #endif diff --git a/xpdf/goo/GHash.cc b/xpdf/goo/GHash.cc index 21646873d..1a88f4e21 100644 --- a/xpdf/goo/GHash.cc +++ b/xpdf/goo/GHash.cc @@ -39,7 +39,7 @@ GHash::GHash(GBool deleteKeysA) { deleteKeys = deleteKeysA; size = 7; - tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *)); + tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); for (h = 0; h < size; ++h) { tab[h] = NULL; } @@ -101,6 +101,30 @@ void GHash::add(GString *key, int val) { ++len; } +void GHash::replace(GString *key, void *val) { + GHashBucket *p; + int h; + + if ((p = find(key, &h))) { + p->val.p = val; + delete key; + } else { + add(key, val); + } +} + +void GHash::replace(GString *key, int val) { + GHashBucket *p; + int h; + + if ((p = find(key, &h))) { + p->val.i = val; + delete key; + } else { + add(key, val); + } +} + void *GHash::lookup(GString *key) { GHashBucket *p; int h; @@ -292,7 +316,7 @@ void GHash::expand() { oldSize = size; oldTab = tab; size = 2*size + 1; - tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *)); + tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); for (h = 0; h < size; ++h) { tab[h] = NULL; } diff --git a/xpdf/goo/GHash.h b/xpdf/goo/GHash.h index 6461d7650..f64a13a51 100644 --- a/xpdf/goo/GHash.h +++ b/xpdf/goo/GHash.h @@ -30,6 +30,8 @@ public: ~GHash(); void add(GString *key, void *val); void add(GString *key, int val); + void replace(GString *key, void *val); + void replace(GString *key, int val); void *lookup(GString *key); int lookupInt(GString *key); void *lookup(char *key); diff --git a/xpdf/goo/GList.cc b/xpdf/goo/GList.cc index 9534232e8..fb5fd6284 100644 --- a/xpdf/goo/GList.cc +++ b/xpdf/goo/GList.cc @@ -12,6 +12,7 @@ #pragma implementation #endif +#include #include #include "gmem.h" #include "GList.h" @@ -22,14 +23,14 @@ GList::GList() { size = 8; - data = (void **)gmalloc(size * sizeof(void*)); + data = (void **)gmallocn(size, sizeof(void*)); length = 0; inc = 0; } GList::GList(int sizeA) { size = sizeA; - data = (void **)gmalloc(size * sizeof(void*)); + data = (void **)gmallocn(size, sizeof(void*)); length = 0; inc = 0; } @@ -81,12 +82,16 @@ void *GList::del(int i) { return p; } +void GList::sort(int (*cmp)(const void *obj1, const void *obj2)) { + qsort(data, length, sizeof(void *), cmp); +} + void GList::expand() { size += (inc > 0) ? inc : size; - data = (void **)grealloc(data, size * sizeof(void*)); + data = (void **)greallocn(data, size, sizeof(void*)); } void GList::shrink() { size -= (inc > 0) ? inc : size/2; - data = (void **)grealloc(data, size * sizeof(void*)); + data = (void **)greallocn(data, size, sizeof(void*)); } diff --git a/xpdf/goo/GList.h b/xpdf/goo/GList.h index 4c52489f3..e4d8ff8f1 100644 --- a/xpdf/goo/GList.h +++ b/xpdf/goo/GList.h @@ -58,6 +58,11 @@ public: // Assumes 0 <= i < length. void *del(int i); + // Sort the list accoring to the given comparison function. + // NB: this sorts an array of pointers, so the pointer args need to + // be double-dereferenced. + void sort(int (*cmp)(const void *ptr1, const void *ptr2)); + //----- control // Set allocation increment to . If inc > 0, that many diff --git a/xpdf/goo/GString.cc b/xpdf/goo/GString.cc index 7653fd06e..049dcf38d 100644 --- a/xpdf/goo/GString.cc +++ b/xpdf/goo/GString.cc @@ -35,7 +35,12 @@ inline void GString::resize(int length1) { s = new char[size(length1)]; } else if (size(length1) != size(length)) { s1 = new char[size(length1)]; - memcpy(s1, s, length + 1); + if (length1 < length) { + memcpy(s1, s, length1); + s1[length1] = '\0'; + } else { + memcpy(s1, s, length + 1); + } delete[] s; s = s1; } @@ -234,3 +239,81 @@ GString *GString::lowerCase() { } return this; } + +int GString::cmp(GString *str) { + int n1, n2, i, x; + char *p1, *p2; + + n1 = length; + n2 = str->length; + for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + return n1 - n2; +} + +int GString::cmpN(GString *str, int n) { + int n1, n2, i, x; + char *p1, *p2; + + n1 = length; + n2 = str->length; + for (i = 0, p1 = s, p2 = str->s; + i < n1 && i < n2 && i < n; + ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i == n) { + return 0; + } + return n1 - n2; +} + +int GString::cmp(const char *sA) { + int n1, i, x; + const char *p1, *p2; + + n1 = length; + for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i < n1) { + return 1; + } + if (*p2) { + return -1; + } + return 0; +} + +int GString::cmpN(const char *sA, int n) { + int n1, i, x; + const char *p1, *p2; + + n1 = length; + for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i == n) { + return 0; + } + if (i < n1) { + return 1; + } + if (*p2) { + return -1; + } + return 0; +} diff --git a/xpdf/goo/GString.h b/xpdf/goo/GString.h index 2083802b3..f4ff7c6a9 100644 --- a/xpdf/goo/GString.h +++ b/xpdf/goo/GString.h @@ -17,8 +17,6 @@ #pragma interface #endif -#include - class GString { public: @@ -83,11 +81,10 @@ public: GString *lowerCase(); // Compare two strings: -1:< 0:= +1:> - // These functions assume the strings do not contain null characters. - int cmp(GString *str) { return strcmp(s, str->getCString()); } - int cmpN(GString *str, int n) { return strncmp(s, str->getCString(), n); } - int cmp(const char *sA) { return strcmp(s, sA); } - int cmpN(const char *sA, int n) { return strncmp(s, sA, n); } + int cmp(GString *str); + int cmpN(GString *str, int n); + int cmp(const char *sA); + int cmpN(const char *sA, int n); private: diff --git a/xpdf/goo/gmem.c b/xpdf/goo/gmem.c index 036beb8a3..00cbbda27 100644 --- a/xpdf/goo/gmem.c +++ b/xpdf/goo/gmem.c @@ -50,6 +50,7 @@ static GMemHdr *gMemList[gMemNLists] = { static int gMemIndex = 0; static int gMemAlloc = 0; +static int gMemInUse = 0; #endif /* DEBUG_MEM */ @@ -78,6 +79,7 @@ void *gmalloc(size_t size) { hdr->next = gMemList[lst]; gMemList[lst] = hdr; ++gMemAlloc; + gMemInUse += size; for (p = (unsigned long *)data; p <= trl; ++p) *p = gMemDeadVal; return data; @@ -135,6 +137,28 @@ void *grealloc(void *p, size_t size) { #endif } +void *gmallocn(int nObjs, int objSize) { + int n; + + n = nObjs * objSize; + if (objSize == 0 || n / objSize != nObjs) { + fprintf(stderr, "Bogus memory allocation size\n"); + exit(1); + } + return gmalloc(n); +} + +void *greallocn(void *p, int nObjs, int objSize) { + int n; + + n = nObjs * objSize; + if (objSize == 0 || n / objSize != nObjs) { + fprintf(stderr, "Bogus memory allocation size\n"); + exit(1); + } + return grealloc(p, n); +} + void gfree(void *p) { #ifdef DEBUG_MEM size_t size; @@ -156,6 +180,7 @@ void gfree(void *p) { else gMemList[lst] = hdr->next; --gMemAlloc; + gMemInUse -= hdr->size; size = gMemDataSize(hdr->size); trl = (unsigned long *)((char *)hdr + gMemHdrSize + size); if (*trl != gMemDeadVal) { diff --git a/xpdf/goo/gmem.h b/xpdf/goo/gmem.h index 3d38907ff..e853b4739 100644 --- a/xpdf/goo/gmem.h +++ b/xpdf/goo/gmem.h @@ -27,6 +27,15 @@ extern void *gmalloc(size_t size); */ extern void *grealloc(void *p, size_t size); +/* + * These are similar to gmalloc and grealloc, but take an object count + * and size. The result is similar to allocating nObjs * objSize + * bytes, but there is an additional error check that the total size + * doesn't overflow an int. + */ +extern void *gmallocn(int nObjs, int objSize); +extern void *greallocn(void *p, int nObjs, int objSize); + /* * Same as free, but checks for and ignores NULL pointers. */ diff --git a/xpdf/splash/Splash.cc b/xpdf/splash/Splash.cc index 916786a58..a1a609477 100644 --- a/xpdf/splash/Splash.cc +++ b/xpdf/splash/Splash.cc @@ -22,11 +22,21 @@ #include "SplashXPathScanner.h" #include "SplashPattern.h" #include "SplashScreen.h" -#include "SplashClip.h" #include "SplashFont.h" #include "SplashGlyphBitmap.h" #include "Splash.h" +//------------------------------------------------------------------------ + +static void blendNormal(SplashColorPtr src, SplashColorPtr /*dest*/, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = src[i]; + } +} + //------------------------------------------------------------------------ // Splash //------------------------------------------------------------------------ @@ -34,6 +44,8 @@ Splash::Splash(SplashBitmap *bitmapA) { bitmap = bitmapA; state = new SplashState(bitmap->width, bitmap->height); + softMask = NULL; + clearModRegion(); debugMode = gFalse; } @@ -42,13 +54,15 @@ Splash::~Splash() { restoreState(); } delete state; + if (softMask) { + delete softMask; + } } //------------------------------------------------------------------------ // state read //------------------------------------------------------------------------ - SplashPattern *Splash::getStrokePattern() { return state->strokePattern; } @@ -61,6 +75,18 @@ SplashScreen *Splash::getScreen() { return state->screen; } +SplashBlendFunc Splash::getBlendFunc() { + return state->blendFunc; +} + +SplashCoord Splash::getStrokeAlpha() { + return state->strokeAlpha; +} + +SplashCoord Splash::getFillAlpha() { + return state->fillAlpha; +} + SplashCoord Splash::getLineWidth() { return state->lineWidth; } @@ -113,6 +139,18 @@ void Splash::setScreen(SplashScreen *screen) { state->setScreen(screen); } +void Splash::setBlendFunc(SplashBlendFunc func) { + state->blendFunc = func; +} + +void Splash::setStrokeAlpha(SplashCoord alpha) { + state->strokeAlpha = alpha; +} + +void Splash::setFillAlpha(SplashCoord alpha) { + state->fillAlpha = alpha; +} + void Splash::setLineWidth(SplashCoord lineWidth) { state->lineWidth = lineWidth; } @@ -180,52 +218,173 @@ SplashError Splash::restoreState() { return splashOk; } +//------------------------------------------------------------------------ +// soft mask +//------------------------------------------------------------------------ + +void Splash::setSoftMask(SplashBitmap *softMaskA) { + if (softMask) { + delete softMask; + } + softMask = softMaskA; +} + +//------------------------------------------------------------------------ +// modified region +//------------------------------------------------------------------------ + +void Splash::clearModRegion() { + modXMin = bitmap->getWidth(); + modYMin = bitmap->getHeight(); + modXMax = -1; + modYMax = -1; +} + +inline void Splash::updateModX(int x) { + if (x < modXMin) { + modXMin = x; + } + if (x > modXMax) { + modXMax = x; + } +} + +inline void Splash::updateModY(int y) { + if (y < modYMin) { + modYMin = y; + } + if (y > modYMax) { + modYMax = y; + } +} + //------------------------------------------------------------------------ // drawing operations //------------------------------------------------------------------------ -void Splash::clear(SplashColor color) { - SplashMono1P *mono1; - SplashMono8 *mono8; - SplashRGB8 *rgb8; - SplashBGR8P *bgr8line, *bgr8; - SplashMono1 data; - int n, i, x, y; +void Splash::clear(SplashColorPtr color) { + SplashColorPtr row, p; + Guchar mono; + int x, y; switch (bitmap->mode) { case splashModeMono1: - n = ((bitmap->width + 7) >> 3) * bitmap->height; - data = color.mono1 ? 0xff : 0x00; - for (i = 0, mono1 = bitmap->data.mono1; i < n; ++i, ++mono1) { - *mono1 = data; + mono = color[0] ? 0xff : 0x00; + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + mono, -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, mono, bitmap->rowSize * bitmap->height); } break; case splashModeMono8: - n = bitmap->width * bitmap->height; - for (i = 0, mono8 = bitmap->data.mono8; i < n; ++i, ++mono8) { - *mono8 = color.mono8; + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + break; + case splashModeAMono8: + if (color[0] == color[1]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + } + row += bitmap->rowSize; + } } break; case splashModeRGB8: - n = bitmap->width * bitmap->height; - for (i = 0, rgb8 = bitmap->data.rgb8; i < n; ++i, ++rgb8) { - *rgb8 = color.rgb8; + case splashModeBGR8: + if (color[0] == color[1] && color[1] == color[2]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + } + row += bitmap->rowSize; + } + } + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + *p++ = color[3]; + } + row += bitmap->rowSize; + } } break; - case splashModeBGR8Packed: - bgr8line = bitmap->data.bgr8; +#if SPLASH_CMYK + case splashModeACMYK8: + if (color[0] == color[1] && color[1] == color[2] && + color[2] == color[3] && color[3] == color[4]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; for (y = 0; y < bitmap->height; ++y) { - bgr8 = bgr8line; + p = row; for (x = 0; x < bitmap->width; ++x) { - bgr8[2] = splashBGR8R(color.bgr8); - bgr8[1] = splashBGR8G(color.bgr8); - bgr8[0] = splashBGR8B(color.bgr8); - bgr8 += 3; + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + *p++ = color[3]; + *p++ = color[4]; + } + row += bitmap->rowSize; } - bgr8line += bitmap->rowSize; } break; +#endif } + + updateModX(0); + updateModY(0); + updateModX(bitmap->width - 1); + updateModY(bitmap->height - 1); } SplashError Splash::stroke(SplashPath *path) { @@ -233,15 +392,15 @@ SplashError Splash::stroke(SplashPath *path) { if (debugMode) { printf("stroke [dash:%d] [width:%.2f]:\n", - state->lineDashLength, state->lineWidth); + state->lineDashLength, (double)state->lineWidth); dumpPath(path); } + opClipRes = splashClipAllOutside; if (path->length == 0) { return splashErrEmptyPath; } xPath = new SplashXPath(path, state->flatness, gFalse); - if (!xPath->segs) - { + if (xPath->length == 0) { delete xPath; return splashErrEmptyPath; } @@ -264,6 +423,7 @@ void Splash::strokeNarrow(SplashXPath *xPath) { int x0, x1, x2, x3, y0, y1, x, y, t; SplashCoord dx, dy, dxdy; SplashClipResult clipRes; + int nClipRes[3]; int i; for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { @@ -280,7 +440,7 @@ void Splash::strokeNarrow(SplashXPath *xPath) { } if ((clipRes = state->clip->testSpan(x0, x1, y0)) != splashClipAllOutside) { - drawSpan(x0, x1, y0, state->strokePattern, + drawSpan(x0, x1, y0, state->strokePattern, state->strokeAlpha, clipRes == splashClipAllInside); } @@ -300,24 +460,32 @@ void Splash::strokeNarrow(SplashXPath *xPath) { != splashClipAllOutside) { if (dx > 0) { x2 = x0; - for (y = y0; y < y1; ++y) { - x3 = splashFloor(seg->x0 + (y + 1 - seg->y0) * dxdy); + x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy); + drawSpan(x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0, state->strokePattern, + state->strokeAlpha, clipRes == splashClipAllInside); + x2 = x3; + for (y = y0 + 1; y <= y1 - 1; ++y) { + x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy); drawSpan(x2, x3 - 1, y, state->strokePattern, - clipRes == splashClipAllInside); + state->strokeAlpha, clipRes == splashClipAllInside); x2 = x3; } - drawSpan(x2, x1, y, state->strokePattern, - clipRes == splashClipAllInside); + drawSpan(x2, x2 <= x1 ? x1 : x2, y1, state->strokePattern, + state->strokeAlpha, clipRes == splashClipAllInside); } else { x2 = x0; - for (y = y0; y < y1; ++y) { - x3 = splashFloor(seg->x0 + (y + 1 - seg->y0) * dxdy); + x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy); + drawSpan((x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0, state->strokePattern, + state->strokeAlpha, clipRes == splashClipAllInside); + x2 = x3; + for (y = y0 + 1; y <= y1 - 1; ++y) { + x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy); drawSpan(x3 + 1, x2, y, state->strokePattern, - clipRes == splashClipAllInside); + state->strokeAlpha, clipRes == splashClipAllInside); x2 = x3; } - drawSpan(x1, x2, y, state->strokePattern, - clipRes == splashClipAllInside); + drawSpan(x1, (x1 <= x2) ? x2 : x1, y1, state->strokePattern, + state->strokeAlpha, clipRes == splashClipAllInside); } } @@ -325,18 +493,32 @@ void Splash::strokeNarrow(SplashXPath *xPath) { } else { dxdy = seg->dxdy; if (y0 > y1) { + t = x0; x0 = x1; x1 = t; t = y0; y0 = y1; y1 = t; } if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, x0 <= x1 ? x1 : x0, y1)) != splashClipAllOutside) { - for (y = y0; y <= y1; ++y) { - x = splashFloor(seg->x0 + (y - seg->y0) * dxdy); - drawPixel(x, y, state->strokePattern, + drawPixel(x0, y0, state->strokePattern, state->strokeAlpha, + clipRes == splashClipAllInside); + for (y = y0 + 1; y <= y1 - 1; ++y) { + x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy); + drawPixel(x, y, state->strokePattern, state->strokeAlpha, + clipRes == splashClipAllInside); + } + drawPixel(x1, y1, state->strokePattern, state->strokeAlpha, clipRes == splashClipAllInside); } } + ++nClipRes[clipRes]; } + if (nClipRes[splashClipPartial] || + (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) { + opClipRes = splashClipPartial; + } else if (nClipRes[splashClipAllInside]) { + opClipRes = splashClipAllInside; + } else { + opClipRes = splashClipAllOutside; } } @@ -364,12 +546,12 @@ void Splash::strokeWide(SplashXPath *xPath) { dxPrev = 0; dyPrev = 1; } else { - d = 1 / d; + d = (SplashCoord)1 / d; dxPrev = d * (seg2->x1 - seg2->x0); dyPrev = d * (seg2->y1 - seg2->y0); } - wdxPrev = 0.5 * state->lineWidth * dxPrev; - wdyPrev = 0.5 * state->lineWidth * dyPrev; + wdxPrev = (SplashCoord)0.5 * state->lineWidth * dxPrev; + wdyPrev = (SplashCoord)0.5 * state->lineWidth * dyPrev; break; } } @@ -388,12 +570,12 @@ void Splash::strokeWide(SplashXPath *xPath) { dx = 0; dy = 1; } else { - d = 1 / d; + d = (SplashCoord)1 / d; dx = d * (seg->x1 - seg->x0); dy = d * (seg->y1 - seg->y0); } - wdx = 0.5 * state->lineWidth * dx; - wdy = 0.5 * state->lineWidth * dy; + wdx = (SplashCoord)0.5 * state->lineWidth * dx; + wdy = (SplashCoord)0.5 * state->lineWidth * dy; // initialize the path (which will be filled) widePath = new SplashPath(); @@ -444,7 +626,7 @@ void Splash::strokeWide(SplashXPath *xPath) { widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); // fill the segment - fillWithPattern(widePath, gTrue, state->strokePattern); + fillWithPattern(widePath, gTrue, state->strokePattern, state->strokeAlpha); delete widePath; // draw the line join @@ -453,10 +635,10 @@ void Splash::strokeWide(SplashXPath *xPath) { switch (state->lineJoin) { case splashLineJoinMiter: dotprod = -(dx * dxPrev + dy * dyPrev); - if (dotprod != 1) { + if (splashAbs(splashAbs(dotprod) - 1) > 0.01) { widePath = new SplashPath(); widePath->moveTo(seg->x0, seg->y0); - miter = 2 / (1 - dotprod); + miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod); if (splashSqrt(miter) <= state->miterLimit) { miter = splashSqrt(miter - 1); if (dy * dxPrev > dx * dyPrev) { @@ -499,7 +681,8 @@ void Splash::strokeWide(SplashXPath *xPath) { break; } if (widePath) { - fillWithPattern(widePath, gTrue, state->strokePattern); + fillWithPattern(widePath, gTrue, state->strokePattern, + state->strokeAlpha); delete widePath; } } @@ -525,7 +708,7 @@ SplashXPath *Splash::makeDashedPath(SplashXPath *xPath) { } lineDashStartPhase = state->lineDashPhase; i = splashFloor(lineDashStartPhase / lineDashTotal); - lineDashStartPhase -= i * lineDashTotal; + lineDashStartPhase -= (SplashCoord)i * lineDashTotal; lineDashStartOn = gTrue; lineDashStartIdx = 0; while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { @@ -623,26 +806,22 @@ SplashError Splash::fill(SplashPath *path, GBool eo) { printf("fill [eo:%d]:\n", eo); dumpPath(path); } - return fillWithPattern(path, eo, state->fillPattern); + return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha); } SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, - SplashPattern *pattern) { + SplashPattern *pattern, + SplashCoord alpha) { SplashXPath *xPath; SplashXPathScanner *scanner; int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; SplashClipResult clipRes, clipRes2; - if (path->length == 0 || path->length == 1) { + if (path->length == 0) { return splashErrEmptyPath; } xPath = new SplashXPath(path, state->flatness, gTrue); xPath->sort(); - if (!&xPath->segs[0]) - { - delete xPath; - return splashErrEmptyPath; - } scanner = new SplashXPathScanner(xPath, eo); // get the min and max x and y values @@ -652,18 +831,34 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) { + // limit the y range + if (yMinI < state->clip->getYMin()) { + yMinI = state->clip->getYMin(); + } + if (yMaxI > state->clip->getYMax()) { + yMaxI = state->clip->getYMax(); + } + // draw the spans for (y = yMinI; y <= yMaxI; ++y) { while (scanner->getNextSpan(y, &x0, &x1)) { if (clipRes == splashClipAllInside) { - drawSpan(x0, x1, y, pattern, gTrue); + drawSpan(x0, x1, y, pattern, alpha, gTrue); } else { + // limit the x range + if (x0 < state->clip->getXMin()) { + x0 = state->clip->getXMin(); + } + if (x1 > state->clip->getXMax()) { + x1 = state->clip->getXMax(); + } clipRes2 = state->clip->testSpan(x0, x1, y); - drawSpan(x0, x1, y, pattern, clipRes2 == splashClipAllInside); + drawSpan(x0, x1, y, pattern, alpha, clipRes2 == splashClipAllInside); } } } } + opClipRes = clipRes; delete scanner; delete xPath; @@ -690,12 +885,27 @@ SplashError Splash::xorFill(SplashPath *path, GBool eo) { if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) { + // limit the y range + if (yMinI < state->clip->getYMin()) { + yMinI = state->clip->getYMin(); + } + if (yMaxI > state->clip->getYMax()) { + yMaxI = state->clip->getYMax(); + } + // draw the spans for (y = yMinI; y <= yMaxI; ++y) { while (scanner->getNextSpan(y, &x0, &x1)) { if (clipRes == splashClipAllInside) { xorSpan(x0, x1, y, state->fillPattern, gTrue); } else { + // limit the x range + if (x0 < state->clip->getXMin()) { + x0 = state->clip->getXMin(); + } + if (x1 > state->clip->getXMax()) { + x1 = state->clip->getXMax(); + } clipRes2 = state->clip->testSpan(x0, x1, y); xorSpan(x0, x1, y, state->fillPattern, clipRes2 == splashClipAllInside); @@ -703,273 +913,1060 @@ SplashError Splash::xorFill(SplashPath *path, GBool eo) { } } } + opClipRes = clipRes; delete scanner; delete xPath; return splashOk; } -void Splash::drawPixel(int x, int y, SplashColor *color, GBool noClip) { - SplashMono1P *mono1; - SplashBGR8P *bgr8; +void Splash::drawPixel(int x, int y, SplashColorPtr color, + SplashCoord alpha, GBool noClip) { + SplashBlendFunc blendFunc; + SplashColorPtr p; + SplashColor dest, blend; + int alpha2, ialpha2; + Guchar t; if (noClip || state->clip->test(x, y)) { + if (alpha != 1 || softMask || state->blendFunc) { + blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; + if (softMask) { + alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]); + } else { + alpha2 = (int)(alpha * 255); + } + ialpha2 = 255 - alpha2; switch (bitmap->mode) { case splashModeMono1: - mono1 = &bitmap->data.mono8[y * bitmap->rowSize + (x >> 3)]; - if (color->mono1) { - *mono1 |= 0x80 >> (x & 7); + p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; + dest[0] = (*p >> (7 - (x & 7))) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= 0x80 >> (x & 7); } else { - *mono1 &= ~(0x80 >> (x & 7)); + *p &= ~(0x80 >> (x & 7)); } break; case splashModeMono8: - bitmap->data.mono8[y * bitmap->width + x] = color->mono8; + p = &bitmap->data[y * bitmap->rowSize + x]; + (*blendFunc)(color, p, blend, bitmap->mode); + // note: floor(x / 255) = x >> 8 (for 16-bit x) + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; break; - case splashModeRGB8: - bitmap->data.rgb8[y * bitmap->width + x] = color->rgb8; + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; break; - case splashModeBGR8Packed: - bgr8 = &bitmap->data.bgr8[y * bitmap->rowSize + 3 * x]; - bgr8[2] = splashBGR8R(color->bgr8); - bgr8[1] = splashBGR8G(color->bgr8); - bgr8[0] = splashBGR8B(color->bgr8); + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; break; +#endif + } + } else { + switch (bitmap->mode) { + case splashModeMono1: + p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; + if (color[0]) { + *p |= 0x80 >> (x & 7); + } else { + *p &= ~(0x80 >> (x & 7)); } + break; + case splashModeMono8: + p = &bitmap->data[y * bitmap->rowSize + x]; + p[0] = color[0]; + break; + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x]; + p[0] = color[0]; + p[1] = color[1]; + break; + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + p[4] = color[4]; + break; +#endif + } + } + updateModX(x); + updateModY(y); } } -void Splash::drawPixel(int x, int y, SplashPattern *pattern, GBool noClip) { +void Splash::drawPixel(int x, int y, SplashPattern *pattern, + SplashCoord alpha, GBool noClip) { + SplashBlendFunc blendFunc; SplashColor color; - SplashMono1P *mono1; - SplashBGR8P *bgr8; + SplashColorPtr p; + SplashColor dest, blend; + int alpha2, ialpha2; + Guchar t; if (noClip || state->clip->test(x, y)) { - color = pattern->getColor(x, y); + if (alpha != 1 || softMask || state->blendFunc) { + blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; + pattern->getColor(x, y, color); + if (softMask) { + alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]); + } else { + alpha2 = (int)(alpha * 255); + } + ialpha2 = 255 - alpha2; switch (bitmap->mode) { case splashModeMono1: - mono1 = &bitmap->data.mono8[y * bitmap->rowSize + (x >> 3)]; - if (color.mono1) { - *mono1 |= 0x80 >> (x & 7); + p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; + dest[0] = (*p >> (7 - (x & 7))) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= 0x80 >> (x & 7); } else { - *mono1 &= ~(0x80 >> (x & 7)); + *p &= ~(0x80 >> (x & 7)); } break; case splashModeMono8: - bitmap->data.mono8[y * bitmap->width + x] = color.mono8; + p = &bitmap->data[y * bitmap->rowSize + x]; + (*blendFunc)(color, p, blend, bitmap->mode); + // note: floor(x / 255) = x >> 8 (for 16-bit x) + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + break; + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; break; case splashModeRGB8: - bitmap->data.rgb8[y * bitmap->width + x] = color.rgb8; + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; + break; +#endif + } + } else { + pattern->getColor(x, y, color); + switch (bitmap->mode) { + case splashModeMono1: + p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; + if (color[0]) { + *p |= 0x80 >> (x & 7); + } else { + *p &= ~(0x80 >> (x & 7)); + } + break; + case splashModeMono8: + p = &bitmap->data[y * bitmap->rowSize + x]; + p[0] = color[0]; + break; + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x]; + p[0] = color[0]; + p[1] = color[1]; break; - case splashModeBGR8Packed: - bgr8 = &bitmap->data.bgr8[y * bitmap->rowSize + 3 * x]; - bgr8[2] = splashBGR8R(color.bgr8); - bgr8[1] = splashBGR8G(color.bgr8); - bgr8[0] = splashBGR8B(color.bgr8); + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + p[4] = color[4]; break; +#endif + } } + updateModX(x); + updateModY(y); } } void Splash::drawSpan(int x0, int x1, int y, SplashPattern *pattern, - GBool noClip) { + SplashCoord alpha, GBool noClip) { + SplashBlendFunc blendFunc; SplashColor color; - SplashMono1P *mono1; - SplashMono8 *mono8; - SplashRGB8 *rgb8; - SplashBGR8P *bgr8; - SplashMono1 mask1; + SplashColorPtr p; + SplashColor dest, blend; + Guchar mask, t; + int alpha2, ialpha2; int i, j, n; n = x1 - x0 + 1; + if (noClip) { + updateModX(x0); + updateModX(x1); + updateModY(y); + } + + if (alpha != 1 || softMask || state->blendFunc) { + blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; + if (softMask) { + alpha2 = ialpha2 = 0; // make gcc happy + } else { + alpha2 = (int)(alpha * 255); + ialpha2 = 255 - alpha2; + } switch (bitmap->mode) { case splashModeMono1: - mono1 = &bitmap->data.mono8[y * bitmap->rowSize + (x0 >> 3)]; + p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; i = 0; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); if ((j = x0 & 7)) { - mask1 = 0x80 >> j; - for (j = x0 & 7; j < 8 && i < n; ++i, ++j) { + mask = 0x80 >> j; + for (; j < 8 && i < n; ++i, ++j) { if (noClip || state->clip->test(x0 + i, y)) { - color = pattern->getColor(x0 + i, y); - if (color.mono1) { - *mono1 |= mask1; + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + dest[0] = (*p >> (7 - j)) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= mask; } else { - *mono1 &= ~mask1; + *p &= ~mask; } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); } - mask1 >>= 1; } - ++mono1; + mask >>= 1; + } + ++p; } while (i < n) { - mask1 = 0x80; + mask = 0x80; for (j = 0; j < 8 && i < n; ++i, ++j) { if (noClip || state->clip->test(x0 + i, y)) { - color = pattern->getColor(x0 + i, y); - if (color.mono1) { - *mono1 |= mask1; + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + dest[0] = (*p >> (7 - j)) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } } else { - *mono1 &= ~mask1; + if ((j = x0 & 7)) { + mask = 0x80 >> j; + for (; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + dest[0] = (*p >> (7 - j)) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + while (i < n) { + mask = 0x80; + for (j = 0; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + dest[0] = (*p >> (7 - j)) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); } } - mask1 >>= 1; + mask >>= 1; + } + ++p; } - ++mono1; } break; case splashModeMono8: - mono8 = &bitmap->data.mono8[y * bitmap->width + x0]; + p = &bitmap->data[y * bitmap->rowSize + x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + ++p; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + ++p; + } + } + break; + + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 2; + } + } else { for (i = 0; i < n; ++i) { if (noClip || state->clip->test(x0 + i, y)) { - color = pattern->getColor(x0 + i, y); - *mono8 = color.mono8; + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 2; } - ++mono8; } break; case splashModeRGB8: - rgb8 = &bitmap->data.rgb8[y * bitmap->width + x0]; + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 3; + } + } else { for (i = 0; i < n; ++i) { if (noClip || state->clip->test(x0 + i, y)) { - color = pattern->getColor(x0 + i, y); - *rgb8 = color.rgb8; + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 3; } - ++rgb8; } break; - case splashModeBGR8Packed: - bgr8 = &bitmap->data.bgr8[y * bitmap->rowSize + 3 * x0]; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } else { for (i = 0; i < n; ++i) { if (noClip || state->clip->test(x0 + i, y)) { - color = pattern->getColor(x0 + i, y); - bgr8[2] = splashBGR8R(color.bgr8); - bgr8[1] = splashBGR8G(color.bgr8); - bgr8[0] = splashBGR8B(color.bgr8); + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; } - bgr8 += 3; } break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } + break; +#endif } -} - -void Splash::xorSpan(int x0, int x1, int y, SplashPattern *pattern, - GBool noClip) { - SplashColor color; - SplashMono1P *mono1; - SplashMono8 *mono8; - SplashRGB8 *rgb8; - SplashBGR8P *bgr8; - SplashMono1 mask1; - int i, j, n; - - n = x1 - x0 + 1; + } else { switch (bitmap->mode) { case splashModeMono1: - mono1 = &bitmap->data.mono8[y * bitmap->rowSize + (x0 >> 3)]; + p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; i = 0; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + if ((j = x0 & 7)) { + mask = 0x80 >> j; + for (; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + if (color[0]) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + while (i < n) { + mask = 0x80; + for (j = 0; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + if (color[0]) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + } else { if ((j = x0 & 7)) { - mask1 = 0x80 >> j; - for (j = x0 & 7; j < 8 && i < n; ++i, ++j) { + mask = 0x80 >> j; + for (; j < 8 && i < n; ++i, ++j) { if (noClip || state->clip->test(x0 + i, y)) { - color = pattern->getColor(x0 + i, y); - if (color.mono1) { - *mono1 ^= mask1; + pattern->getColor(x0 + i, y, color); + if (color[0]) { + *p |= mask; + } else { + *p &= ~mask; } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); } - mask1 >>= 1; } - ++mono1; + mask >>= 1; + } + ++p; } while (i < n) { - mask1 = 0x80; + mask = 0x80; for (j = 0; j < 8 && i < n; ++i, ++j) { if (noClip || state->clip->test(x0 + i, y)) { - color = pattern->getColor(x0 + i, y); - if (color.mono1) { - *mono1 ^= mask1; + pattern->getColor(x0 + i, y, color); + if (color[0]) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); } } - mask1 >>= 1; + mask >>= 1; + } + ++p; } - ++mono1; } break; case splashModeMono8: - mono8 = &bitmap->data.mono8[y * bitmap->width + x0]; + p = &bitmap->data[y * bitmap->rowSize + x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); for (i = 0; i < n; ++i) { if (noClip || state->clip->test(x0 + i, y)) { - color = pattern->getColor(x0 + i, y); - *mono8 ^= color.mono8; + *p = color[0]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); } - ++mono8; } - break; - - case splashModeRGB8: - rgb8 = &bitmap->data.rgb8[y * bitmap->width + x0]; + ++p; + } + } else { for (i = 0; i < n; ++i) { if (noClip || state->clip->test(x0 + i, y)) { - color = pattern->getColor(x0 + i, y); - *rgb8 ^= color.rgb8; + pattern->getColor(x0 + i, y, color); + *p = color[0]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + ++p; } - ++rgb8; } break; - case splashModeBGR8Packed: - bgr8 = &bitmap->data.bgr8[y * bitmap->rowSize + 3 * x0]; + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); for (i = 0; i < n; ++i) { if (noClip || state->clip->test(x0 + i, y)) { - color = pattern->getColor(x0 + i, y); - bgr8[2] ^= splashBGR8R(color.bgr8); - bgr8[1] ^= splashBGR8G(color.bgr8); - bgr8[0] ^= splashBGR8B(color.bgr8); - } - bgr8 += 3; + p[0] = color[0]; + p[1] = color[1]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); } - break; - } -} - -void Splash::getPixel(int x, int y, SplashColor *pixel) { - SplashBGR8P *bgr8; - - if (y < 0 || y >= bitmap->height || x < 0 || x >= bitmap->width) { - return; } - switch (bitmap->mode) { - case splashModeMono1: - pixel->mono1 = (bitmap->data.mono1[y * bitmap->rowSize + (x >> 3)] - >> (7 - (x & 7))) & 1; - break; - case splashModeMono8: - pixel->mono8 = bitmap->data.mono8[y * bitmap->width + x]; - break; - case splashModeRGB8: - pixel->rgb8 = bitmap->data.rgb8[y * bitmap->width + x]; - break; - case splashModeBGR8Packed: - bgr8 = &bitmap->data.bgr8[y * bitmap->rowSize + 3 * x]; - pixel->bgr8 = splashMakeBGR8(bgr8[2], bgr8[1], bgr8[0]); - break; + p += 2; } -} - -SplashError Splash::fillChar(SplashCoord x, SplashCoord y, - int c, SplashFont *font) { - SplashGlyphBitmap glyph; + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] = color[0]; + p[1] = color[1]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 2; + } + } + break; + + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 3; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 3; + } + } + break; + + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + p[4] = color[4]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + p[4] = color[4]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } + break; +#endif + } + } +} + +void Splash::xorSpan(int x0, int x1, int y, SplashPattern *pattern, + GBool noClip) { + SplashColor color; + SplashColorPtr p; + Guchar mask; + int i, j, n; + + n = x1 - x0 + 1; + + if (noClip) { + updateModX(x0); + updateModX(x1); + updateModY(y); + } + + switch (bitmap->mode) { + case splashModeMono1: + p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; + i = 0; + if ((j = x0 & 7)) { + mask = 0x80 >> j; + for (; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (color[0]) { + *p ^= mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + while (i < n) { + mask = 0x80; + for (j = 0; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (color[0]) { + *p ^= mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + break; + + case splashModeMono8: + p = &bitmap->data[y * bitmap->rowSize + x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + *p ^= color[0]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + ++p; + } + break; + + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] ^= color[0]; + p[1] ^= color[1]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 2; + } + break; + + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] ^= color[0]; + p[1] ^= color[1]; + p[2] ^= color[2]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 3; + } + break; + + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] ^= color[0]; + p[1] ^= color[1]; + p[2] ^= color[2]; + p[3] ^= color[3]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] ^= color[0]; + p[1] ^= color[1]; + p[2] ^= color[2]; + p[3] ^= color[3]; + p[4] ^= color[4]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + break; +#endif + } +} + +SplashError Splash::fillChar(SplashCoord x, SplashCoord y, + int c, SplashFont *font) { + SplashGlyphBitmap glyph; int x0, y0, xFrac, yFrac; SplashError err; if (debugMode) { printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n", - x, y, c, c, c); + (double)x, (double)y, c, c, c); } x0 = splashFloor(x); xFrac = splashFloor((x - x0) * splashFontFraction); @@ -987,17 +1984,14 @@ SplashError Splash::fillChar(SplashCoord x, SplashCoord y, SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y, SplashGlyphBitmap *glyph) { - int alpha, ialpha; + SplashBlendFunc blendFunc; + int alpha0, alpha, ialpha; Guchar *p; - SplashColor fg; - SplashMono1P *mono1Ptr; - SplashMono8 *mono8Ptr; - SplashRGB8 *rgb8Ptr; - SplashBGR8P *bgr8Ptr; - SplashMono8 bgMono8; - int bgR, bgG, bgB; + SplashColor fg, dest, blend; + SplashColorPtr pix; SplashClipResult clipRes; GBool noClip; + Guchar t; int x0, y0, x1, y1, xx, xx1, yy; x0 = splashFloor(x); @@ -1010,55 +2004,243 @@ SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y, != splashClipAllOutside) { noClip = clipRes == splashClipAllInside; + if (noClip) { + updateModX(x0 - glyph->x); + updateModX(x0 - glyph->x + glyph->w - 1); + updateModY(y0 - glyph->y); + updateModY(y0 - glyph->y + glyph->h - 1); + } + //~ optimize this + if (state->fillAlpha != 1 || softMask || state->blendFunc) { + blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; if (glyph->aa) { p = glyph->data; for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) { alpha = *p++; + if (softMask) { + alpha = (int)(alpha * state->fillAlpha * + softMask->data[y1 * softMask->rowSize + x1]); + } else { + alpha = (int)(alpha * state->fillAlpha); + } if (alpha > 0) { if (noClip || state->clip->test(x1, y1)) { ialpha = 255 - alpha; - fg = state->fillPattern->getColor(x1, y1); + state->fillPattern->getColor(x1, y1, fg); switch (bitmap->mode) { case splashModeMono1: - if (alpha >= 0x80) { - mono1Ptr = &bitmap->data.mono1[y1 * bitmap->rowSize + - (x1 >> 3)]; - if (fg.mono1) { - *mono1Ptr |= 0x80 >> (x1 & 7); + pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; + dest[0] = (*pix >> (7 - (x1 & 7))) & 1; + (*blendFunc)(fg, dest, blend, bitmap->mode); + t = (alpha * blend[0] + ialpha * dest[0]) >> 8; + if (t) { + *pix |= 0x80 >> (x1 & 7); } else { - *mono1Ptr &= ~(0x80 >> (x1 & 7)); + *pix &= ~(0x80 >> (x1 & 7)); } + break; + case splashModeMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + // note: floor(x / 255) = x >> 8 (for 16-bit x) + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + break; + case splashModeAMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + break; + case splashModeRGB8: + case splashModeBGR8: + pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; + pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8; + break; +#endif } + if (!noClip) { + updateModX(x1); + updateModY(y1); + } + } + } + } + } + + } else { + p = glyph->data; + for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { + for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) { + alpha0 = *p++; + for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) { + if (alpha0 & 0x80) { + if (noClip || state->clip->test(x1, y1)) { + if (softMask) { + alpha = (int)(state->fillAlpha * + softMask->data[y1 * softMask->rowSize + x1]); + } else { + alpha = (int)(state->fillAlpha * 255); + } + ialpha = 255 - alpha; + state->fillPattern->getColor(x1, y1, fg); + switch (bitmap->mode) { + case splashModeMono1: + pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; + dest[0] = (*pix >> (7 - (x1 & 7))) & 1; + (*blendFunc)(fg, dest, blend, bitmap->mode); + t = (alpha * blend[0] + ialpha * dest[0]) >> 8; + if (t) { + *pix |= 0x80 >> (x1 & 7); + } else { + *pix &= ~(0x80 >> (x1 & 7)); + } break; case splashModeMono8: - mono8Ptr = &bitmap->data.mono8[y1 * bitmap->width + x1]; - bgMono8 = *mono8Ptr; + pix = &bitmap->data[y1 * bitmap->rowSize + x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); // note: floor(x / 255) = x >> 8 (for 16-bit x) - *mono8Ptr = (alpha * fg.mono8 + ialpha * bgMono8) >> 8; + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + break; + case splashModeAMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; break; case splashModeRGB8: - rgb8Ptr = &bitmap->data.rgb8[y1 * bitmap->width + x1]; - bgR = splashRGB8R(*rgb8Ptr); - bgG = splashRGB8G(*rgb8Ptr); - bgB = splashRGB8B(*rgb8Ptr); - *rgb8Ptr = splashMakeRGB8((alpha * splashRGB8R(fg.rgb8) + - ialpha * bgR) >> 8, - (alpha * splashRGB8G(fg.rgb8) + - ialpha * bgG) >> 8, - (alpha * splashRGB8B(fg.rgb8) + - ialpha * bgB) >> 8); - break; - case splashModeBGR8Packed: - bgr8Ptr = &bitmap->data.bgr8[y1 * bitmap->rowSize + 3 * x1]; - bgr8Ptr[2] = - (alpha * splashBGR8R(fg.bgr8) + ialpha * bgr8Ptr[2]) >> 8; - bgr8Ptr[1] = - (alpha * splashBGR8G(fg.bgr8) + ialpha * bgr8Ptr[1]) >> 8; - bgr8Ptr[0] = - (alpha * splashBGR8B(fg.bgr8) + ialpha * bgr8Ptr[0]) >> 8; + case splashModeBGR8: + pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; + pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8; + break; +#endif + } + if (!noClip) { + updateModX(x1); + updateModY(y1); + } + } + } + alpha0 <<= 1; + } + } + } + } + + } else { + if (glyph->aa) { + p = glyph->data; + for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { + for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) { + alpha = *p++; + if (alpha > 0) { + if (noClip || state->clip->test(x1, y1)) { + ialpha = 255 - alpha; + state->fillPattern->getColor(x1, y1, fg); + switch (bitmap->mode) { + case splashModeMono1: + if (alpha >= 0x80) { + pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; + if (fg[0]) { + *pix |= 0x80 >> (x1 & 7); + } else { + *pix &= ~(0x80 >> (x1 & 7)); + } + } + break; + case splashModeMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + x1]; + // note: floor(x / 255) = x >> 8 (for 16-bit x) + pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; + break; + case splashModeAMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; + pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; break; + case splashModeRGB8: + case splashModeBGR8: + pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; + pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; + pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; + pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8; + pix[4] = (alpha * fg[4] + ialpha * pix[4]) >> 8; + break; +#endif + } + if (!noClip) { + updateModX(x1); + updateModY(y1); } } } @@ -1069,42 +2251,72 @@ SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y, p = glyph->data; for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) { - alpha = *p++; + alpha0 = *p++; for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) { - if (alpha & 0x80) { + if (alpha0 & 0x80) { if (noClip || state->clip->test(x1, y1)) { - fg = state->fillPattern->getColor(x1, y1); + state->fillPattern->getColor(x1, y1, fg); switch (bitmap->mode) { case splashModeMono1: - mono1Ptr = &bitmap->data.mono1[y1 * bitmap->rowSize + - (x1 >> 3)]; - if (fg.mono1) { - *mono1Ptr |= 0x80 >> (x1 & 7); + pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; + if (fg[0]) { + *pix |= 0x80 >> (x1 & 7); } else { - *mono1Ptr &= ~(0x80 >> (x1 & 7)); + *pix &= ~(0x80 >> (x1 & 7)); } break; case splashModeMono8: - bitmap->data.mono8[y1 * bitmap->width + x1] = fg.mono8; + pix = &bitmap->data[y1 * bitmap->rowSize + x1]; + pix[0] = fg[0]; + break; + case splashModeAMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; + pix[0] = fg[0]; + pix[1] = fg[1]; break; case splashModeRGB8: - bitmap->data.rgb8[y1 * bitmap->width + x1] = fg.rgb8; + case splashModeBGR8: + pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; + pix[0] = fg[0]; + pix[1] = fg[1]; + pix[2] = fg[2]; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; + pix[0] = fg[0]; + pix[1] = fg[1]; + pix[2] = fg[2]; + pix[3] = fg[3]; break; - case splashModeBGR8Packed: - bgr8Ptr = &bitmap->data.bgr8[y1 * bitmap->rowSize + 3 * x1]; - bgr8Ptr[2] = splashBGR8R(fg.bgr8); - bgr8Ptr[1] = splashBGR8G(fg.bgr8); - bgr8Ptr[0] = splashBGR8B(fg.bgr8); +#if SPLASH_CMYK + case splashModeACMYK8: + pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; + pix[0] = fg[0]; + pix[1] = fg[1]; + pix[2] = fg[2]; + pix[3] = fg[3]; + pix[4] = fg[4]; break; +#endif } + if (!noClip) { + updateModX(x1); + updateModY(y1); } } - alpha <<= 1; } + alpha0 <<= 1; } } } } + } + } + opClipRes = clipRes; return splashOk; } @@ -1112,8 +2324,8 @@ SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y, SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, int w, int h, SplashCoord *mat) { GBool rot; - SplashCoord xScale, yScale, xShear, yShear; - int tx, ty, scaledWidth, scaledHeight, xSign, ySign; + SplashCoord xScale, yScale, xShear, yShear, yShear1; + int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign; int ulx, uly, llx, lly, urx, ury, lrx, lry; int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; int xMin, xMax, yMin, yMax; @@ -1121,17 +2333,17 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, int yp, yq, yt, yStep, lastYStep; int xp, xq, xt, xStep, xSrc; int k1, spanXMin, spanXMax, spanY; - SplashMono1 *pixBuf; - SplashMono1 *p; + SplashColorPtr pixBuf, p; int pixAcc; SplashCoord alpha; - SplashColor fg, bg, pix; - int x, y, x1, y1, x2, y2; + int x, y, x1, x2, y2; + SplashCoord y1; int n, m, i, j; if (debugMode) { printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", - w, h, mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + w, h, (double)mat[0], (double)mat[1], (double)mat[2], + (double)mat[3], (double)mat[4], (double)mat[5]); } // check for singular matrix @@ -1152,23 +2364,52 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, xShear = mat[2] / yScale; yShear = mat[1] / mat[0]; } - tx = splashRound(mat[4]); - ty = splashRound(mat[5]); - scaledWidth = abs(splashRound(mat[4] + xScale) - tx) + 1; - scaledHeight = abs(splashRound(mat[5] + yScale) - ty) + 1; + // the +/-0.01 in these computations is to avoid floating point + // precision problems which can lead to gaps between image stripes + // (it can cause image stripes to overlap, but that's a much less + // visible problem) + if (xScale >= 0) { + tx = splashRound(mat[4] - 0.01); + tx2 = splashRound(mat[4] + xScale + 0.01) - 1; + } else { + tx = splashRound(mat[4] + 0.01) - 1; + tx2 = splashRound(mat[4] + xScale - 0.01); + } + scaledWidth = abs(tx2 - tx) + 1; + if (scaledWidth == 0) { + // technically, this should draw nothing, but it generally seems + // better to draw a one-pixel-wide stripe rather than throwing it + // away + scaledWidth = 1; + } + if (yScale >= 0) { + ty = splashRound(mat[5] - 0.01); + ty2 = splashRound(mat[5] + yScale + 0.01) - 1; + } else { + ty = splashRound(mat[5] + 0.01) - 1; + ty2 = splashRound(mat[5] + yScale - 0.01); + } + scaledHeight = abs(ty2 - ty) + 1; + if (scaledHeight == 0) { + // technically, this should draw nothing, but it generally seems + // better to draw a one-pixel-wide stripe rather than throwing it + // away + scaledHeight = 1; + } xSign = (xScale < 0) ? -1 : 1; ySign = (yScale < 0) ? -1 : 1; + yShear1 = (SplashCoord)xSign * yShear; // clipping ulx1 = 0; uly1 = 0; urx1 = xSign * (scaledWidth - 1); - ury1 = splashRound(yShear * urx1); + ury1 = (int)(yShear * urx1); llx1 = splashRound(xShear * ySign * (scaledHeight - 1)); - lly1 = ySign * (scaledHeight - 1) + splashRound(yShear * llx1); + lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1); lrx1 = xSign * (scaledWidth - 1) + splashRound(xShear * ySign * (scaledHeight - 1)); - lry1 = ySign * (scaledHeight - 1) + splashRound(yShear * lrx1); + lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1); if (rot) { ulx = tx + uly1; uly = ty - ulx1; urx = tx + ury1; ury = ty - urx1; @@ -1197,6 +2438,7 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, : (ury > lly) ? (ury > lry) ? ury : lry : (lly > lry) ? lly : lry; clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); + opClipRes = clipRes; // compute Bresenham parameters for x and y scaling yp = h / scaledHeight; @@ -1205,7 +2447,7 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, xq = w % scaledWidth; // allocate pixel buffer - pixBuf = (SplashMono1 *)gmalloc((yp + 1) * w * sizeof(SplashMono1)); + pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w); // init y scale Bresenham yt = 0; @@ -1226,9 +2468,8 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, if (n > 0) { p = pixBuf; for (i = 0; i < n; ++i) { - for (j = 0; j < w; ++j) { - (*src)(srcData, p++); - } + (*src)(srcData, p); + p += w; } } lastYStep = yStep; @@ -1239,8 +2480,8 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, // clipping test if (clipRes != splashClipAllInside && !rot && - splashRound(yShear * k1) == - splashRound(yShear * (xSign * (scaledWidth - 1) + k1))) { + (int)(yShear * k1) == + (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { if (xSign > 0) { spanXMin = tx + k1; spanXMax = spanXMin + (scaledWidth - 1); @@ -1248,7 +2489,7 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, spanXMax = tx + k1; spanXMin = spanXMax - (scaledWidth - 1); } - spanY = ty + ySign * y + splashRound(xShear * ySign * y); + spanY = ty + ySign * y + (int)(yShear * k1); clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); if (clipRes2 == splashClipAllOutside) { continue; @@ -1261,6 +2502,21 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, xt = 0; xSrc = 0; + // x shear + x1 = k1; + + // y shear + y1 = (SplashCoord)ySign * y + yShear * x1; + // this is a kludge: if yShear1 is negative, then (int)y1 would + // change immediately after the first pixel, which is not what we + // want + if (yShear1 < 0) { + y1 += 0.999; + } + + // loop-invariant constants + n = yStep > 0 ? yStep : 1; + for (x = 0; x < scaledWidth; ++x) { // x scale Bresenham @@ -1271,24 +2527,17 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, ++xStep; } - // x shear - x1 = xSign * x + k1; - - // y shear - y1 = ySign * y + splashRound(yShear * x1); - // rotation if (rot) { - x2 = y1; + x2 = (int)y1; y2 = -x1; } else { x2 = x1; - y2 = y1; + y2 = (int)y1; } // compute the alpha value for (x,y) after the x and y scaling // operations - n = yStep > 0 ? yStep : 1; m = xStep > 0 ? xStep : 1; p = pixBuf + xSrc; pixAcc = 0; @@ -1301,46 +2550,25 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, // blend fill color with background if (pixAcc != 0) { - fg = state->fillPattern->getColor(tx + x2, ty + y2); if (pixAcc == n * m) { - pix = fg; + drawPixel(tx + x2, ty + y2, state->fillPattern, state->fillAlpha, + clipRes2 == splashClipAllInside); } else { - getPixel(tx + x2, ty + y2, &bg); alpha = (SplashCoord)pixAcc / (SplashCoord)(n * m); - switch (bitmap->mode) { - case splashModeMono1: - pix.mono1 = splashRound(alpha * fg.mono1 + - (1 - alpha) * bg.mono1); - break; - case splashModeMono8: - pix.mono8 = splashRound(alpha * fg.mono8 + - (1 - alpha) * bg.mono8); - break; - case splashModeRGB8: - pix.rgb8 = splashMakeRGB8( - splashRound(alpha * splashRGB8R(fg.rgb8) + - (1 - alpha) * splashRGB8R(bg.rgb8)), - splashRound(alpha * splashRGB8G(fg.rgb8) + - (1 - alpha) * splashRGB8G(bg.rgb8)), - splashRound(alpha * splashRGB8B(fg.rgb8) + - (1 - alpha) * splashRGB8B(bg.rgb8))); - break; - case splashModeBGR8Packed: - pix.bgr8 = splashMakeBGR8( - splashRound(alpha * splashBGR8R(fg.bgr8) + - (1 - alpha) * splashBGR8R(bg.bgr8)), - splashRound(alpha * splashBGR8G(fg.bgr8) + - (1 - alpha) * splashBGR8G(bg.bgr8)), - splashRound(alpha * splashBGR8B(fg.bgr8) + - (1 - alpha) * splashBGR8B(bg.bgr8))); - break; - } + drawPixel(tx + x2, ty + y2, state->fillPattern, + state->fillAlpha * alpha, + clipRes2 == splashClipAllInside); } - drawPixel(tx + x2, ty + y2, &pix, clipRes2 == splashClipAllInside); } // x scale Bresenham xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; } } @@ -1353,9 +2581,9 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, SplashError Splash::drawImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, int w, int h, SplashCoord *mat) { - GBool ok, rot, halftone; - SplashCoord xScale, yScale, xShear, yShear; - int tx, ty, scaledWidth, scaledHeight, xSign, ySign; + GBool ok, rot, halftone, srcAlpha; + SplashCoord xScale, yScale, xShear, yShear, yShear1; + int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign; int ulx, uly, llx, lly, urx, ury, lrx, lry; int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; int xMin, xMax, yMin, yMax; @@ -1363,40 +2591,78 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, int yp, yq, yt, yStep, lastYStep; int xp, xq, xt, xStep, xSrc; int k1, spanXMin, spanXMax, spanY; - SplashColor *pixBuf, *p; - Guchar *alphaBuf, *q; + SplashColorPtr pixBuf, p; SplashColor pix; - SplashCoord pixAcc[splashMaxColorComps]; +#if SPLASH_CMYK + int pixAcc0, pixAcc1, pixAcc2, pixAcc3; +#else + int pixAcc0, pixAcc1, pixAcc2; +#endif int alphaAcc; SplashCoord pixMul, alphaMul, alpha; - int x, y, x1, y1, x2, y2; - int n, m, i, j; + int x, y, x1, x2, y2; + SplashCoord y1; + int nComps, n, m, i, j; if (debugMode) { printf("drawImage: srcMode=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", - srcMode, w, h, mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + srcMode, w, h, (double)mat[0], (double)mat[1], (double)mat[2], + (double)mat[3], (double)mat[4], (double)mat[5]); } // check color modes ok = gFalse; // make gcc happy + nComps = 0; // make gcc happy + halftone = gFalse; + srcAlpha = gFalse; switch (bitmap->mode) { case splashModeMono1: - ok = srcMode == splashModeMono1 || srcMode == splashModeMono8; + ok = srcMode == splashModeMono1 || srcMode == splashModeMono8 || + srcMode == splashModeAMono8; + halftone = srcMode == splashModeMono8 || srcMode == splashModeAMono8; + srcAlpha = srcMode == splashModeAMono8; + nComps = srcAlpha ? 2 : 1; break; case splashModeMono8: - ok = srcMode == splashModeMono8; + ok = srcMode == splashModeMono8 || srcMode == splashModeAMono8; + srcAlpha = srcMode == splashModeAMono8; + nComps = srcAlpha ? 2 : 1; + break; + case splashModeAMono8: + //~ not implemented yet + ok = gFalse; + nComps = 2; break; case splashModeRGB8: - ok = srcMode == splashModeRGB8; + ok = srcMode == splashModeRGB8 || srcMode == splashModeARGB8; + srcAlpha = srcMode == splashModeARGB8; + nComps = srcAlpha ? 4 : 3; break; - case splashModeBGR8Packed: - ok = srcMode == splashModeBGR8Packed; + case splashModeBGR8: + ok = srcMode == splashModeBGR8 || srcMode == splashModeBGRA8; + srcAlpha = srcMode == splashModeBGRA8; + nComps = srcAlpha ? 4 : 3; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + ok = srcMode == splashModeCMYK8 || srcMode == splashModeACMYK8; + srcAlpha = srcMode == splashModeACMYK8; + nComps = srcAlpha ? 5 : 4; + break; +#endif + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ not implemented yet + ok = gFalse; + nComps = 4; break; } if (!ok) { return splashErrModeMismatch; } - halftone = bitmap->mode == splashModeMono1 && srcMode == splashModeMono8; // check for singular matrix if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) { @@ -1416,23 +2682,52 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, xShear = mat[2] / yScale; yShear = mat[1] / mat[0]; } - tx = splashRound(mat[4]); - ty = splashRound(mat[5]); - scaledWidth = abs(splashRound(mat[4] + xScale) - tx) + 1; - scaledHeight = abs(splashRound(mat[5] + yScale) - ty) + 1; + // the +/-0.01 in these computations is to avoid floating point + // precision problems which can lead to gaps between image stripes + // (it can cause image stripes to overlap, but that's a much less + // visible problem) + if (xScale >= 0) { + tx = splashRound(mat[4] - 0.01); + tx2 = splashRound(mat[4] + xScale + 0.01) - 1; + } else { + tx = splashRound(mat[4] + 0.01) - 1; + tx2 = splashRound(mat[4] + xScale - 0.01); + } + scaledWidth = abs(tx2 - tx) + 1; + if (scaledWidth == 0) { + // technically, this should draw nothing, but it generally seems + // better to draw a one-pixel-wide stripe rather than throwing it + // away + scaledWidth = 1; + } + if (yScale >= 0) { + ty = splashRound(mat[5] - 0.01); + ty2 = splashRound(mat[5] + yScale + 0.01) - 1; + } else { + ty = splashRound(mat[5] + 0.01) - 1; + ty2 = splashRound(mat[5] + yScale - 0.01); + } + scaledHeight = abs(ty2 - ty) + 1; + if (scaledHeight == 0) { + // technically, this should draw nothing, but it generally seems + // better to draw a one-pixel-wide stripe rather than throwing it + // away + scaledHeight = 1; + } xSign = (xScale < 0) ? -1 : 1; ySign = (yScale < 0) ? -1 : 1; + yShear1 = (SplashCoord)xSign * yShear; // clipping ulx1 = 0; uly1 = 0; urx1 = xSign * (scaledWidth - 1); - ury1 = splashRound(yShear * urx1); + ury1 = (int)(yShear * urx1); llx1 = splashRound(xShear * ySign * (scaledHeight - 1)); - lly1 = ySign * (scaledHeight - 1) + splashRound(yShear * llx1); + lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1); lrx1 = xSign * (scaledWidth - 1) + splashRound(xShear * ySign * (scaledHeight - 1)); - lry1 = ySign * (scaledHeight - 1) + splashRound(yShear * lrx1); + lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1); if (rot) { ulx = tx + uly1; uly = ty - ulx1; urx = tx + ury1; ury = ty - urx1; @@ -1460,8 +2755,9 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, : (lly > lry) ? lly : lry : (ury > lly) ? (ury > lry) ? ury : lry : (lly > lry) ? lly : lry; - if ((clipRes = state->clip->testRect(xMin, yMin, xMax, yMax)) - == splashClipAllOutside) { + clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); + opClipRes = clipRes; + if (clipRes == splashClipAllOutside) { return splashOk; } @@ -1472,8 +2768,14 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, xq = w % scaledWidth; // allocate pixel buffer - pixBuf = (SplashColor *)gmalloc((yp + 1) * w * sizeof(SplashColor)); - alphaBuf = (Guchar *)gmalloc((yp + 1) * w * sizeof(Guchar)); + pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w * nComps); + + pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy +#if SPLASH_CMYK + pixAcc3 = 0; // make gcc happy +#endif + + if (srcAlpha) { // init y scale Bresenham yt = 0; @@ -1493,11 +2795,9 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, n = (yp > 0) ? yStep : lastYStep; if (n > 0) { p = pixBuf; - q = alphaBuf; for (i = 0; i < n; ++i) { - for (j = 0; j < w; ++j) { - (*src)(srcData, p++, q++); - } + (*src)(srcData, p); + p += w * nComps; } } lastYStep = yStep; @@ -1508,8 +2808,8 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, // clipping test if (clipRes != splashClipAllInside && !rot && - splashRound(yShear * k1) == - splashRound(yShear * (xSign * (scaledWidth - 1) + k1))) { + (int)(yShear * k1) == + (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { if (xSign > 0) { spanXMin = tx + k1; spanXMax = spanXMin + (scaledWidth - 1); @@ -1517,7 +2817,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, spanXMax = tx + k1; spanXMin = spanXMax - (scaledWidth - 1); } - spanY = ty + ySign * y + splashRound(xShear * ySign * y); + spanY = ty + ySign * y + (int)(yShear * k1); clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); if (clipRes2 == splashClipAllOutside) { continue; @@ -1530,6 +2830,21 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, xt = 0; xSrc = 0; + // x shear + x1 = k1; + + // y shear + y1 = (SplashCoord)ySign * y + yShear * x1; + // this is a kludge: if yShear1 is negative, then (int)y1 would + // change immediately after the first pixel, which is not what + // we want + if (yShear1 < 0) { + y1 += 0.999; + } + + // loop-invariant constants + n = yStep > 0 ? yStep : 1; + for (x = 0; x < scaledWidth; ++x) { // x scale Bresenham @@ -1540,106 +2855,306 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, ++xStep; } - // x shear - x1 = xSign * x + k1; - - // y shear - y1 = ySign * y + splashRound(yShear * x1); - // rotation if (rot) { - x2 = y1; + x2 = (int)y1; y2 = -x1; } else { x2 = x1; - y2 = y1; + y2 = (int)y1; } // compute the filtered pixel at (x,y) after the x and y scaling // operations - n = yStep > 0 ? yStep : 1; m = xStep > 0 ? xStep : 1; - p = pixBuf + xSrc; - q = alphaBuf + xSrc; - for (i = 0; i < splashMaxColorComps; ++i) { - pixAcc[i] = 0; - } alphaAcc = 0; + switch (srcMode) { + case splashModeAMono8: + p = pixBuf + xSrc * 2; + pixAcc0 = 0; for (i = 0; i < n; ++i) { for (j = 0; j < m; ++j) { - switch (srcMode) { - case splashModeMono1: - pixAcc[0] += p->mono1; - break; - case splashModeMono8: - pixAcc[0] += p->mono8; + alphaAcc += *p++; + pixAcc0 += *p++; + } + p += 2 * (w - m); + } break; - case splashModeRGB8: - pixAcc[0] += splashRGB8R(p->rgb8); - pixAcc[1] += splashRGB8G(p->rgb8); - pixAcc[2] += splashRGB8B(p->rgb8); + case splashModeARGB8: + p = pixBuf + xSrc * 4; + pixAcc0 = pixAcc1 = pixAcc2 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + alphaAcc += *p++; + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + } + p += 4 * (w - m); + } break; - case splashModeBGR8Packed: - pixAcc[0] += splashBGR8R(p->bgr8); - pixAcc[1] += splashBGR8G(p->bgr8); - pixAcc[2] += splashBGR8B(p->bgr8); + case splashModeBGRA8: + p = pixBuf + xSrc * 4; + pixAcc0 = pixAcc1 = pixAcc2 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + alphaAcc += *p++; + } + p += 4 * (w - m); + } break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = pixBuf + xSrc * 5; + pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + alphaAcc += *p++; + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + pixAcc3 += *p++; } - ++p; - alphaAcc += *q++; + p += 5 * (w - m); } - p += w - m; - q += w - m; + break; +#endif + default: // make gcc happy + break; } - alphaMul = 1 / (SplashCoord)(n * m); + pixMul = (SplashCoord)1 / (SplashCoord)(n * m); + alphaMul = pixMul * (1.0 / 256.0); + alpha = (SplashCoord)alphaAcc * alphaMul; + + if (alpha > 0) { + // mono8 -> mono1 conversion, with halftoning if (halftone) { - pixMul = (SplashCoord)alphaMul / 256.0; + pix[0] = state->screen->test(tx + x2, ty + y2, + (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0)); + + // no conversion, no halftoning } else { - pixMul = alphaMul; + switch (bitmap->mode) { +#if SPLASH_CMYK + case splashModeCMYK8: + pix[3] = (int)((SplashCoord)pixAcc3 * pixMul); + // fall through +#endif + case splashModeRGB8: + case splashModeBGR8: + pix[2] = (int)((SplashCoord)pixAcc2 * pixMul); + pix[1] = (int)((SplashCoord)pixAcc1 * pixMul); + // fall through + case splashModeMono1: + case splashModeMono8: + pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); + break; + default: // make gcc happy + break; + } + } + + // set pixel + drawPixel(tx + x2, ty + y2, pix, alpha * state->fillAlpha, + clipRes2 == splashClipAllInside); + } + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + } + + } else { + + // init y scale Bresenham + yt = 0; + lastYStep = 1; + + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + + // read row(s) from image + n = (yp > 0) ? yStep : lastYStep; + if (n > 0) { + p = pixBuf; + for (i = 0; i < n; ++i) { + (*src)(srcData, p); + p += w * nComps; + } + } + lastYStep = yStep; + + // loop-invariant constants + k1 = splashRound(xShear * ySign * y); + + // clipping test + if (clipRes != splashClipAllInside && + !rot && + (int)(yShear * k1) == + (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { + if (xSign > 0) { + spanXMin = tx + k1; + spanXMax = spanXMin + (scaledWidth - 1); + } else { + spanXMax = tx + k1; + spanXMin = spanXMax - (scaledWidth - 1); + } + spanY = ty + ySign * y + (int)(yShear * k1); + clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); + if (clipRes2 == splashClipAllOutside) { + continue; + } + } else { + clipRes2 = clipRes; + } + + // init x scale Bresenham + xt = 0; + xSrc = 0; + + // x shear + x1 = k1; + + // y shear + y1 = (SplashCoord)ySign * y + yShear * x1; + // this is a kludge: if yShear1 is negative, then (int)y1 would + // change immediately after the first pixel, which is not what + // we want + if (yShear1 < 0) { + y1 += 0.999; } - alpha = (SplashCoord)alphaAcc * alphaMul; - //~ this should blend if 0 < alpha < 1 - if (alpha > 0.75) { + // loop-invariant constants + n = yStep > 0 ? yStep : 1; + + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the filtered pixel at (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + switch (srcMode) { + case splashModeMono1: + case splashModeMono8: + p = pixBuf + xSrc; + pixAcc0 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + } + p += w - m; + } + break; + case splashModeRGB8: + case splashModeBGR8: + p = pixBuf + xSrc * 3; + pixAcc0 = pixAcc1 = pixAcc2 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + } + p += 3 * (w - m); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + p = pixBuf + xSrc * 4; + pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + pixAcc3 += *p++; + } + p += 4 * (w - m); + } + break; +#endif + default: // make gcc happy + break; + } + pixMul = (SplashCoord)1 / (SplashCoord)(n * m); // mono8 -> mono1 conversion, with halftoning if (halftone) { - pix.mono1 = state->screen->test(tx + x2, ty + y2, - pixAcc[0] * pixMul); + pix[0] = state->screen->test(tx + x2, ty + y2, + (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0)); // no conversion, no halftoning } else { switch (bitmap->mode) { +#if SPLASH_CMYK + case splashModeCMYK8: + pix[3] = (int)((SplashCoord)pixAcc3 * pixMul); + // fall through +#endif + case splashModeRGB8: + case splashModeBGR8: + pix[2] = (int)((SplashCoord)pixAcc2 * pixMul); + pix[1] = (int)((SplashCoord)pixAcc1 * pixMul); + // fall through case splashModeMono1: - pix.mono1 = splashRound(pixAcc[0] * pixMul); - break; case splashModeMono8: - pix.mono8 = splashRound(pixAcc[0] * pixMul); + pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); break; - case splashModeRGB8: - pix.rgb8 = splashMakeRGB8(splashRound(pixAcc[0] * pixMul), - splashRound(pixAcc[1] * pixMul), - splashRound(pixAcc[2] * pixMul)); - break; - case splashModeBGR8Packed: - pix.bgr8 = splashMakeBGR8(splashRound(pixAcc[0] * pixMul), - splashRound(pixAcc[1] * pixMul), - splashRound(pixAcc[2] * pixMul)); + default: // make gcc happy break; } } // set pixel - drawPixel(tx + x2, ty + y2, &pix, clipRes2 == splashClipAllInside); - } + drawPixel(tx + x2, ty + y2, pix, state->fillAlpha, + clipRes2 == splashClipAllInside); // x scale Bresenham xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } } + } gfree(pixBuf); - gfree(alphaBuf); return splashOk; } @@ -1649,7 +3164,7 @@ void Splash::dumpPath(SplashPath *path) { for (i = 0; i < path->length; ++i) { printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s%s\n", - i, path->pts[i].x, path->pts[i].y, + i, (double)path->pts[i].x, (double)path->pts[i].y, (path->flags[i] & splashPathFirst) ? " first" : "", (path->flags[i] & splashPathLast) ? " last" : "", (path->flags[i] & splashPathClosed) ? " closed" : "", @@ -1657,3 +3172,20 @@ void Splash::dumpPath(SplashPath *path) { (path->flags[i] & splashPathArcCW) ? " arcCW" : ""); } } + +void Splash::dumpXPath(SplashXPath *path) { + int i; + + for (i = 0; i < path->length; ++i) { + printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n", + i, (double)path->segs[i].x0, (double)path->segs[i].y0, + (double)path->segs[i].x1, (double)path->segs[i].y1, + (path->segs[i].flags & splashXPathFirst) ? "F" : " ", + (path->segs[i].flags & splashXPathLast) ? "L" : " ", + (path->segs[i].flags & splashXPathEnd0) ? "0" : " ", + (path->segs[i].flags & splashXPathEnd1) ? "1" : " ", + (path->segs[i].flags & splashXPathHoriz) ? "H" : " ", + (path->segs[i].flags & splashXPathVert) ? "V" : " ", + (path->segs[i].flags & splashXPathFlip) ? "P" : " "); + } +} diff --git a/xpdf/splash/Splash.h b/xpdf/splash/Splash.h index efcbdabcb..fd3ec80da 100644 --- a/xpdf/splash/Splash.h +++ b/xpdf/splash/Splash.h @@ -14,29 +14,28 @@ #endif #include "SplashTypes.h" +#include "SplashClip.h" class SplashBitmap; -class SplashGlyphBitmap; +struct SplashGlyphBitmap; class SplashState; class SplashPattern; class SplashScreen; class SplashPath; class SplashXPath; -class SplashClip; class SplashFont; //------------------------------------------------------------------------ -// Retrieves the next pixel in an image mask. Normally, fills in -// * and returns true. If the image stream is exhausted, -// returns false. -typedef GBool (*SplashImageMaskSource)(void *data, SplashMono1 *pixel); +// Retrieves the next line of pixels in an image mask. Normally, +// fills in * and returns true. If the image stream is +// exhausted, returns false. +typedef GBool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel); -// Retrieves the next pixel in an image. Normally, fills in * -// (pixel color) and * (1 for opaque, 0 for transparent), and -// returns true. If the image stream is exhausted, returns false. -typedef GBool (*SplashImageSource)(void *data, SplashColor *pixel, - Guchar *alpha); +// Retrieves the next line of pixels in an image. Normally, fills in +// * and returns true. If the image stream is exhausted, +// returns false. +typedef GBool (*SplashImageSource)(void *data, SplashColorPtr line); //------------------------------------------------------------------------ // Splash @@ -55,6 +54,9 @@ public: SplashPattern *getStrokePattern(); SplashPattern *getFillPattern(); SplashScreen *getScreen(); + SplashBlendFunc getBlendFunc(); + SplashCoord getStrokeAlpha(); + SplashCoord getFillAlpha(); SplashCoord getLineWidth(); int getLineCap(); int getLineJoin(); @@ -70,6 +72,9 @@ public: void setStrokePattern(SplashPattern *strokeColor); void setFillPattern(SplashPattern *fillColor); void setScreen(SplashScreen *screen); + void setBlendFunc(SplashBlendFunc func); + void setStrokeAlpha(SplashCoord alpha); + void setFillAlpha(SplashCoord alpha); void setLineWidth(SplashCoord lineWidth); void setLineCap(int lineCap); void setLineJoin(int lineJoin); @@ -89,10 +94,14 @@ public: void saveState(); SplashError restoreState(); + //----- soft mask + + void setSoftMask(SplashBitmap *softMaskA); + //----- drawing operations // Fill the bitmap with . This is not subject to clipping. - void clear(SplashColor color); + void clear(SplashColorPtr color); // Stroke a path using the current stroke pattern. SplashError stroke(SplashPath *path); @@ -111,10 +120,10 @@ public: SplashError fillGlyph(SplashCoord x, SplashCoord y, SplashGlyphBitmap *glyph); - // Draws an image mask using the fill color. This will read * - // pixels from , in raster order, starting with the top line. - // "1" pixels will be drawn with the current fill color; "0" pixels - // are transparent. The matrix: + // Draws an image mask using the fill color. This will read + // lines of pixels from , starting with the top line. "1" + // pixels will be drawn with the current fill color; "0" pixels are + // transparent. The matrix: // [ mat[0] mat[1] 0 ] // [ mat[2] mat[3] 0 ] // [ mat[4] mat[5] 1 ] @@ -127,49 +136,68 @@ public: SplashError fillImageMask(SplashImageMaskSource src, void *srcData, int w, int h, SplashCoord *mat); - // Draw an image. This will read * pixels from , in - // raster order, starting with the top line. These pixels are - // assumed to be in the source mode, . The following - // combinations of source and target modes are supported: + // Draw an image. This will read lines of pixels from + // , starting with the top line. These pixels are assumed to + // be in the source mode, . The following combinations of + // source and target modes are supported: // source target // ------ ------ // Mono1 Mono1 // Mono8 Mono1 -- with dithering // Mono8 Mono8 // RGB8 RGB8 - // BGR8packed BGR8Packed + // BGR8 BGR8 + // ARGB8 RGB8 -- with source alpha (masking) + // BGRA8 BGR8 -- with source alpha (masking) // The matrix behaves as for fillImageMask. SplashError drawImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, int w, int h, SplashCoord *mat); - //~ drawMaskedImage - //----- misc // Return the associated bitmap. SplashBitmap *getBitmap() { return bitmap; } + // Get a bounding box which includes all modifications since the + // last call to clearModRegion. + void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax) + { *xMin = modXMin; *yMin = modYMin; *xMax = modXMax; *yMax = modYMax; } + + // Clear the modified region bounding box. + void clearModRegion(); + + // Get clipping status for the last drawing operation subject to + // clipping. + SplashClipResult getClipRes() { return opClipRes; } + // Toggle debug mode on or off. void setDebugMode(GBool debugModeA) { debugMode = debugModeA; } private: + void updateModX(int x); + void updateModY(int y); void strokeNarrow(SplashXPath *xPath); void strokeWide(SplashXPath *xPath); SplashXPath *makeDashedPath(SplashXPath *xPath); SplashError fillWithPattern(SplashPath *path, GBool eo, - SplashPattern *pattern); - void drawPixel(int x, int y, SplashColor *color, GBool noClip); - void drawPixel(int x, int y, SplashPattern *pattern, GBool noClip); - void drawSpan(int x0, int x1, int y, SplashPattern *pattern, GBool noClip); + SplashPattern *pattern, SplashCoord alpha); + void drawPixel(int x, int y, SplashColorPtr color, + SplashCoord alpha, GBool noClip); + void drawPixel(int x, int y, SplashPattern *pattern, + SplashCoord alpha, GBool noClip); + void drawSpan(int x0, int x1, int y, SplashPattern *pattern, + SplashCoord alpha, GBool noClip); void xorSpan(int x0, int x1, int y, SplashPattern *pattern, GBool noClip); - void putPixel(int x, int y, SplashColor *pixel); - void getPixel(int x, int y, SplashColor *pixel); void dumpPath(SplashPath *path); + void dumpXPath(SplashXPath *path); SplashBitmap *bitmap; SplashState *state; + SplashBitmap *softMask; + int modXMin, modYMin, modXMax, modYMax; + SplashClipResult opClipRes; GBool debugMode; }; diff --git a/xpdf/splash/SplashBitmap.cc b/xpdf/splash/SplashBitmap.cc index 5ea304fb0..30702bcf8 100644 --- a/xpdf/splash/SplashBitmap.cc +++ b/xpdf/splash/SplashBitmap.cc @@ -19,57 +19,59 @@ // SplashBitmap //------------------------------------------------------------------------ -SplashBitmap::SplashBitmap(int widthA, int heightA, SplashColorMode modeA) { +SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, + SplashColorMode modeA, GBool topDown) { width = widthA; height = heightA; mode = modeA; switch (mode) { case splashModeMono1: rowSize = (width + 7) >> 3; - data.mono1 = (SplashMono1P *) - gmalloc(rowSize * height * sizeof(SplashMono1P)); break; case splashModeMono8: rowSize = width; - data.mono8 = (SplashMono8 *) - gmalloc(width * height * sizeof(SplashMono8)); + break; + case splashModeAMono8: + rowSize = width * 2; break; case splashModeRGB8: - rowSize = width << 2; - data.rgb8 = (SplashRGB8 *) - gmalloc(width * height * sizeof(SplashRGB8)); - break; - case splashModeBGR8Packed: - rowSize = (width * 3 + 3) & ~3; - data.bgr8 = (SplashBGR8P *) - gmalloc(rowSize * height * sizeof(SplashMono1P)); + case splashModeBGR8: + rowSize = width * 3; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + rowSize = width * 4; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + rowSize = width * 5; + break; +#endif + } + rowSize += rowPad - 1; + rowSize -= rowSize % rowPad; + data = (SplashColorPtr)gmalloc(rowSize * height); + if (!topDown) { + data += (height - 1) * rowSize; + rowSize = -rowSize; } } SplashBitmap::~SplashBitmap() { - switch (mode) { - case splashModeMono1: - gfree(data.mono1); - break; - case splashModeMono8: - gfree(data.mono8); - break; - case splashModeRGB8: - gfree(data.rgb8); - break; - case splashModeBGR8Packed: - gfree(data.bgr8); - break; + if (rowSize < 0) { + gfree(data + (height - 1) * rowSize); + } else { + gfree(data); } } SplashError SplashBitmap::writePNMFile(char *fileName) { FILE *f; - SplashMono1P *mono1; - SplashMono8 *mono8; - SplashRGB8 *rgb8; - SplashBGR8P *bgr8line, *bgr8; + SplashColorPtr row, p; int x, y; if (!(f = fopen(fileName, "wb"))) { @@ -80,55 +82,162 @@ SplashError SplashBitmap::writePNMFile(char *fileName) { case splashModeMono1: fprintf(f, "P4\n%d %d\n", width, height); - mono1 = data.mono1; + row = data; for (y = 0; y < height; ++y) { + p = row; for (x = 0; x < width; x += 8) { - fputc(*mono1 ^ 0xff, f); - ++mono1; + fputc(*p ^ 0xff, f); + ++p; } + row += rowSize; } break; case splashModeMono8: fprintf(f, "P5\n%d %d\n255\n", width, height); - mono8 = data.mono8; + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(*p, f); + ++p; + } + row += rowSize; + } + break; + + case splashModeAMono8: + fprintf(f, "P5\n%d %d\n255\n", width, height); + row = data; for (y = 0; y < height; ++y) { + p = row; for (x = 0; x < width; ++x) { - fputc(*mono8, f); - ++mono8; + fputc(splashAMono8M(p), f); + p += 2; } + row += rowSize; } break; case splashModeRGB8: fprintf(f, "P6\n%d %d\n255\n", width, height); - rgb8 = data.rgb8; + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashRGB8R(p), f); + fputc(splashRGB8G(p), f); + fputc(splashRGB8B(p), f); + p += 3; + } + row += rowSize; + } + break; + + case splashModeBGR8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashBGR8R(p), f); + fputc(splashBGR8G(p), f); + fputc(splashBGR8B(p), f); + p += 3; + } + row += rowSize; + } + break; + + case splashModeARGB8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; for (y = 0; y < height; ++y) { + p = row; for (x = 0; x < width; ++x) { - fputc(splashRGB8R(*rgb8), f); - fputc(splashRGB8G(*rgb8), f); - fputc(splashRGB8B(*rgb8), f); - ++rgb8; + fputc(splashARGB8R(p), f); + fputc(splashARGB8G(p), f); + fputc(splashARGB8B(p), f); + p += 4; } + row += rowSize; } break; - case splashModeBGR8Packed: + case splashModeBGRA8: fprintf(f, "P6\n%d %d\n255\n", width, height); - bgr8line = data.bgr8; + row = data; for (y = 0; y < height; ++y) { - bgr8 = bgr8line; + p = row; for (x = 0; x < width; ++x) { - fputc(bgr8[2], f); - fputc(bgr8[1], f); - fputc(bgr8[0], f); - bgr8 += 3; + fputc(splashBGRA8R(p), f); + fputc(splashBGRA8G(p), f); + fputc(splashBGRA8B(p), f); + p += 4; } - bgr8line += rowSize; + row += rowSize; } break; + +#if SPLASH_CMYK + case splashModeCMYK8: + case splashModeACMYK8: + // PNM doesn't support CMYK + break; +#endif } fclose(f); return splashOk; } + +void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { + SplashColorPtr p; + + if (y < 0 || y >= height || x < 0 || x >= width) { + return; + } + switch (mode) { + case splashModeMono1: + p = &data[y * rowSize + (x >> 3)]; + pixel[0] = (p[0] >> (7 - (x & 7))) & 1; + break; + case splashModeMono8: + p = &data[y * rowSize + x]; + pixel[0] = p[0]; + break; + case splashModeAMono8: + p = &data[y * rowSize + 2 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + break; + case splashModeRGB8: + case splashModeBGR8: + p = &data[y * rowSize + 3 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &data[y * rowSize + 4 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + pixel[3] = p[3]; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &data[y * rowSize + 5 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + pixel[3] = p[3]; + pixel[4] = p[4]; + break; +#endif + } +} diff --git a/xpdf/splash/SplashBitmap.h b/xpdf/splash/SplashBitmap.h index 75e3217d0..0f2270da1 100644 --- a/xpdf/splash/SplashBitmap.h +++ b/xpdf/splash/SplashBitmap.h @@ -22,8 +22,12 @@ class SplashBitmap { public: - // Create a new bitmap. - SplashBitmap(int widthA, int heightA, SplashColorMode modeA); + // Create a new bitmap. It will have x pixels in + // color mode . Rows will be padded out to a multiple of + // bytes. If is false, the bitmap will be stored + // upside-down, i.e., with the last row first in memory. + SplashBitmap(int widthA, int heightA, int rowPad, + SplashColorMode modeA, GBool topDown = gTrue); ~SplashBitmap(); @@ -35,12 +39,15 @@ public: SplashError writePNMFile(char *fileName); + void getPixel(int x, int y, SplashColorPtr pixel); + private: int width, height; // size of bitmap int rowSize; // size of one row of data, in bytes + // - negative for bottom-up bitmaps SplashColorMode mode; // color mode - SplashColorPtr data; + SplashColorPtr data; // pointer to row zero of the bitmap data friend class Splash; }; diff --git a/xpdf/splash/SplashClip.cc b/xpdf/splash/SplashClip.cc index 4c70c03a5..07f740715 100644 --- a/xpdf/splash/SplashClip.cc +++ b/xpdf/splash/SplashClip.cc @@ -61,10 +61,10 @@ SplashClip::SplashClip(SplashClip *clip) { yMax = clip->yMax; length = clip->length; size = clip->size; - paths = (SplashXPath **)gmalloc(size * sizeof(SplashXPath *)); - flags = (Guchar *)gmalloc(size * sizeof(Guchar)); + paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *)); + flags = (Guchar *)gmallocn(size, sizeof(Guchar)); scanners = (SplashXPathScanner **) - gmalloc(size * sizeof(SplashXPathScanner *)); + gmallocn(size, sizeof(SplashXPathScanner *)); for (i = 0; i < length; ++i) { paths[i] = clip->paths[i]->copy(); flags[i] = clip->flags[i]; @@ -92,10 +92,10 @@ void SplashClip::grow(int nPaths) { while (size < length + nPaths) { size *= 2; } - paths = (SplashXPath **)grealloc(paths, size * sizeof(SplashXPath *)); - flags = (Guchar *)grealloc(flags, size * sizeof(Guchar)); + paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *)); + flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); scanners = (SplashXPathScanner **) - grealloc(scanners, size * sizeof(SplashXPathScanner *)); + greallocn(scanners, size, sizeof(SplashXPathScanner *)); } } diff --git a/xpdf/splash/SplashClip.h b/xpdf/splash/SplashClip.h index 34a4cc591..7f302ced6 100644 --- a/xpdf/splash/SplashClip.h +++ b/xpdf/splash/SplashClip.h @@ -73,6 +73,15 @@ public: // Similar to testRect, but tests a horizontal span. SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY); + // Get the rectangle part of the clip region. + int getXMin() { return xMin; } + int getXMax() { return xMax; } + int getYMin() { return yMin; } + int getYMax() { return yMax; } + + // Get the number of arbitrary paths used by the clip region. + int getNumPaths() { return length; } + private: SplashClip(SplashClip *clip); diff --git a/xpdf/splash/SplashFTFont.cc b/xpdf/splash/SplashFTFont.cc index b416fa6b8..95ff56562 100644 --- a/xpdf/splash/SplashFTFont.cc +++ b/xpdf/splash/SplashFTFont.cc @@ -12,8 +12,9 @@ #pragma implementation #endif -#include "freetype/ftoutln.h" -#include "freetype/internal/ftobjs.h" // needed for FT_New_Size decl +#include +#include FT_OUTLINE_H +#include FT_INTERNAL_OBJECTS_H // needed for FT_New_Size decl #include "gmem.h" #include "SplashMath.h" #include "SplashGlyphBitmap.h" @@ -111,7 +112,7 @@ SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA): } if (yMax == yMin) { yMin = 0; - yMax = (int)(1.2 * size); + yMax = (int)((SplashCoord)1.2 * size); } // compute the transform matrix @@ -142,7 +143,7 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int /*yFrac*/, ff = (SplashFTFontFile *)fontFile; ff->face->size = sizeObj; - offset.x = (FT_Pos)(xFrac * splashFontFractionMul * 64); + offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64); offset.y = 0; FT_Set_Transform(ff->face, &matrix, &offset); slot = ff->face->glyph; @@ -196,6 +197,11 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int /*yFrac*/, return gTrue; } +struct SplashFTFontPath { + SplashPath *path; + GBool needClose; +}; + SplashPath *SplashFTFont::getGlyphPath(int c) { static FT_Outline_Funcs outlineFuncs = { &glyphPathMoveTo, @@ -205,7 +211,7 @@ SplashPath *SplashFTFont::getGlyphPath(int c) { 0, 0 }; SplashFTFontFile *ff; - SplashPath *path; + SplashFTFontPath path; FT_GlyphSlot slot; FT_UInt gid; FT_Glyph glyph; @@ -225,26 +231,41 @@ SplashPath *SplashFTFont::getGlyphPath(int c) { if (FT_Get_Glyph(slot, &glyph)) { return NULL; } - path = new SplashPath(); + path.path = new SplashPath(); + path.needClose = gFalse; FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, - &outlineFuncs, path); - return path; + &outlineFuncs, &path); + if (path.needClose) { + path.path->close(); + } + FT_Done_Glyph(glyph); + return path.path; } static int glyphPathMoveTo(FT_Vector *pt, void *path) { - ((SplashPath *)path)->moveTo(pt->x / 64.0, -pt->y / 64.0); + SplashFTFontPath *p = (SplashFTFontPath *)path; + + if (p->needClose) { + p->path->close(); + p->needClose = gFalse; + } + p->path->moveTo(pt->x / 64.0, -pt->y / 64.0); return 0; } static int glyphPathLineTo(FT_Vector *pt, void *path) { - ((SplashPath *)path)->lineTo(pt->x / 64.0, -pt->y / 64.0); + SplashFTFontPath *p = (SplashFTFontPath *)path; + + p->path->lineTo(pt->x / 64.0, -pt->y / 64.0); + p->needClose = gTrue; return 0; } static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc; - if (!((SplashPath *)path)->getCurPt(&x0, &y0)) { + if (!p->path->getCurPt(&x0, &y0)) { return 0; } xc = ctrl->x / 64.0; @@ -268,20 +289,24 @@ static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path) { // p1 = (1/3) * (p0 + 2pc) // p2 = (1/3) * (2pc + p3) - x1 = (1.0 / 3.0) * (x0 + 2 * xc); - y1 = (1.0 / 3.0) * (y0 + 2 * yc); - x2 = (1.0 / 3.0) * (2 * xc + x3); - y2 = (1.0 / 3.0) * (2 * yc + y3); + x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc); + y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc); + x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3); + y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3); - ((SplashPath *)path)->curveTo(x1, y1, x2, y2, x3, y3); + p->path->curveTo(x1, y1, x2, y2, x3, y3); + p->needClose = gTrue; return 0; } static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, FT_Vector *pt, void *path) { - ((SplashPath *)path)->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0, + SplashFTFontPath *p = (SplashFTFontPath *)path; + + p->path->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0, ctrl2->x / 64.0, -ctrl2->y / 64.0, pt->x / 64.0, -pt->y / 64.0); + p->needClose = gTrue; return 0; } diff --git a/xpdf/splash/SplashFTFont.h b/xpdf/splash/SplashFTFont.h index 7628a2bad..efd0eda7b 100644 --- a/xpdf/splash/SplashFTFont.h +++ b/xpdf/splash/SplashFTFont.h @@ -15,7 +15,8 @@ #pragma interface #endif -#include +#include +#include FT_FREETYPE_H #include "SplashFont.h" class SplashFTFontFile; diff --git a/xpdf/splash/SplashFTFontEngine.cc b/xpdf/splash/SplashFTFontEngine.cc index b47ba24e2..6c9ba337d 100644 --- a/xpdf/splash/SplashFTFontEngine.cc +++ b/xpdf/splash/SplashFTFontEngine.cc @@ -42,8 +42,15 @@ static void FT_fileWrite(void *stream, const char *data, int len) { //------------------------------------------------------------------------ SplashFTFontEngine::SplashFTFontEngine(GBool aaA, FT_Library libA) { + FT_Int major, minor, patch; + aa = aaA; lib = libA; + + // as of FT 2.1.8, CID fonts are indexed by CID instead of GID + FT_Library_Version(lib, &major, &minor, &patch); + useCIDs = major > 2 || + (major == 2 && (minor > 1 || (minor == 1 && patch > 7))); } SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA) { @@ -78,25 +85,28 @@ SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, SplashFontFile *ret; // check for a CFF font -#if HAVE_FREETYPE_217_OR_OLDER - FoFiType1C *ff; - if (src->isFile) { - ff = FoFiType1C::load(src->fileName->getCString()); - } else { - ff = new FoFiType1C(src->buf, src->bufLen, gFalse); + if (!useCIDs) + { + FoFiType1C *ff; + if (src->isFile) { + ff = FoFiType1C::load(src->fileName->getCString()); + } else { + ff = new FoFiType1C(src->buf, src->bufLen, gFalse); + } + if (ff) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + delete ff; + } else { + cidToGIDMap = NULL; + nCIDs = 0; + } } - if (ff) { - cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); - delete ff; - } else { + else + { + // Freetype 2.1.8 and up treats all CID fonts the same way cidToGIDMap = NULL; nCIDs = 0; } -#else - // Freetype 2.1.8 and up treats all CID fonts the same way - cidToGIDMap = NULL; - nCIDs = 0; -#endif ret = SplashFTFontFile::loadCIDFont(this, idA, src, cidToGIDMap, nCIDs); if (!ret) { gfree(cidToGIDMap); diff --git a/xpdf/splash/SplashFTFontEngine.h b/xpdf/splash/SplashFTFontEngine.h index 34e572be9..05dc94bf0 100644 --- a/xpdf/splash/SplashFTFontEngine.h +++ b/xpdf/splash/SplashFTFontEngine.h @@ -48,6 +48,7 @@ private: GBool aa; FT_Library lib; + GBool useCIDs; friend class SplashFTFontFile; friend class SplashFTFont; diff --git a/xpdf/splash/SplashFTFontFile.cc b/xpdf/splash/SplashFTFontFile.cc index 4a6e615fb..043903547 100644 --- a/xpdf/splash/SplashFTFontFile.cc +++ b/xpdf/splash/SplashFTFontFile.cc @@ -38,7 +38,7 @@ SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA)) return NULL; } - codeToGIDA = (Gushort *)gmalloc(256 * sizeof(int)); + codeToGIDA = (Gushort *)gmallocn(256, sizeof(int)); for (i = 0; i < 256; ++i) { codeToGIDA[i] = 0; if ((name = encA[i])) { diff --git a/xpdf/splash/SplashFont.cc b/xpdf/splash/SplashFont.cc index 461c981be..8db3c51d5 100644 --- a/xpdf/splash/SplashFont.cc +++ b/xpdf/splash/SplashFont.cc @@ -70,8 +70,8 @@ void SplashFont::initCache() { } else { cacheSets = 1; } - cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize); - cacheTags = (SplashFontCacheTag *)gmalloc(cacheSets * cacheAssoc * + cache = (Guchar *)gmallocn(cacheSets* cacheAssoc, glyphSize); + cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, sizeof(SplashFontCacheTag)); for (i = 0; i < cacheSets * cacheAssoc; ++i) { cacheTags[i].mru = i & (cacheAssoc - 1); @@ -95,6 +95,12 @@ GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, Guchar *p; int i, j, k; + // no fractional coordinates for large glyphs or non-anti-aliased + // glyphs + if (!aa || glyphH > 50) { + xFrac = yFrac = 0; + } + // check the cache i = (c & (cacheSets - 1)) * cacheAssoc; for (j = 0; j < cacheAssoc; ++j) { diff --git a/xpdf/splash/SplashFont.h b/xpdf/splash/SplashFont.h index 49e36c2a3..980154d65 100644 --- a/xpdf/splash/SplashFont.h +++ b/xpdf/splash/SplashFont.h @@ -27,7 +27,8 @@ class SplashPath; // decimal points. #define splashFontFractionBits 2 #define splashFontFraction (1 << splashFontFractionBits) -#define splashFontFractionMul (1 / (SplashCoord)splashFontFraction) +#define splashFontFractionMul \ + ((SplashCoord)1 / (SplashCoord)splashFontFraction) //------------------------------------------------------------------------ // SplashFont @@ -71,6 +72,13 @@ public: // Return the path for a glyph. virtual SplashPath *getGlyphPath(int c) = 0; + // Return the font transform matrix. + SplashCoord *getMatrix() { return mat; } + + // Return the glyph bounding box. + void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + protected: SplashFontFile *fontFile; diff --git a/xpdf/splash/SplashFontEngine.cc b/xpdf/splash/SplashFontEngine.cc index 152fd3b89..a655c55f0 100644 --- a/xpdf/splash/SplashFontEngine.cc +++ b/xpdf/splash/SplashFontEngine.cc @@ -28,12 +28,6 @@ #include "SplashFont.h" #include "SplashFontEngine.h" -#ifdef VMS -#if (__VMS_VER < 70000000) -extern "C" int unlink(char *filename); -#endif -#endif - //------------------------------------------------------------------------ // SplashFontEngine //------------------------------------------------------------------------ diff --git a/xpdf/splash/SplashPath.cc b/xpdf/splash/SplashPath.cc index 465990f61..12f79b7e5 100644 --- a/xpdf/splash/SplashPath.cc +++ b/xpdf/splash/SplashPath.cc @@ -40,8 +40,8 @@ SplashPath::SplashPath() { SplashPath::SplashPath(SplashPath *path) { length = path->length; size = path->size; - pts = (SplashPathPoint *)gmalloc(size * sizeof(SplashPathPoint)); - flags = (Guchar *)gmalloc(size * sizeof(Guchar)); + pts = (SplashPathPoint *)gmallocn(size, sizeof(SplashPathPoint)); + flags = (Guchar *)gmallocn(size, sizeof(Guchar)); memcpy(pts, path->pts, length * sizeof(SplashPathPoint)); memcpy(flags, path->flags, length * sizeof(Guchar)); curSubpath = path->curSubpath; @@ -61,8 +61,8 @@ void SplashPath::grow(int nPts) { while (size < length + nPts) { size *= 2; } - pts = (SplashPathPoint *)grealloc(pts, size * sizeof(SplashPathPoint)); - flags = (Guchar *)grealloc(flags, size * sizeof(Guchar)); + pts = (SplashPathPoint *)greallocn(pts, size, sizeof(SplashPathPoint)); + flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); } } @@ -148,7 +148,8 @@ SplashError SplashPath::close() { if (noCurrentPoint()) { return splashErrNoCurPt; } - if (pts[length - 1].x != pts[curSubpath].x || + if (curSubpath == length - 1 || + pts[length - 1].x != pts[curSubpath].x || pts[length - 1].y != pts[curSubpath].y) { lineTo(pts[curSubpath].x, pts[curSubpath].y); } diff --git a/xpdf/splash/SplashPath.h b/xpdf/splash/SplashPath.h index 8aa1a8bc2..e06d6de3f 100644 --- a/xpdf/splash/SplashPath.h +++ b/xpdf/splash/SplashPath.h @@ -84,6 +84,11 @@ public: // Add (, ) to every point on this path. void offset(SplashCoord dx, SplashCoord dy); + // Get the points on the path. + int getLength() { return length; } + void getPoint(int i, double *x, double *y, Guchar *f) + { *x = pts[i].x; *y = pts[i].y; *f = flags[i]; } + // Get the current point. GBool getCurPt(SplashCoord *x, SplashCoord *y); diff --git a/xpdf/splash/SplashPattern.cc b/xpdf/splash/SplashPattern.cc index fb9fc1fa8..76d4bdfc3 100644 --- a/xpdf/splash/SplashPattern.cc +++ b/xpdf/splash/SplashPattern.cc @@ -28,25 +28,25 @@ SplashPattern::~SplashPattern() { // SplashSolidColor //------------------------------------------------------------------------ -SplashSolidColor::SplashSolidColor(SplashColor colorA) { - color = colorA; +SplashSolidColor::SplashSolidColor(SplashColorPtr colorA) { + splashColorCopy(color, colorA); } SplashSolidColor::~SplashSolidColor() { } -SplashColor SplashSolidColor::getColor(int /*x*/, int /*y*/) { - return color; +void SplashSolidColor::getColor(int /*x*/, int /*y*/, SplashColorPtr c) { + splashColorCopy(c, color); } //------------------------------------------------------------------------ // SplashHalftone //------------------------------------------------------------------------ -SplashHalftone::SplashHalftone(SplashColor color0A, SplashColor color1A, +SplashHalftone::SplashHalftone(SplashColorPtr color0A, SplashColorPtr color1A, SplashScreen *screenA, SplashCoord valueA) { - color0 = color0A; - color1 = color1A; + splashColorCopy(color0, color0A); + splashColorCopy(color1, color1A); screen = screenA; value = valueA; } @@ -59,6 +59,10 @@ SplashHalftone::~SplashHalftone() { delete screen; } -SplashColor SplashHalftone::getColor(int x, int y) { - return screen->test(x, y, value) ? color1 : color0; +void SplashHalftone::getColor(int x, int y, SplashColorPtr c) { + splashColorCopy(c, screen->test(x, y, value) ? color1 : color0); +} + +GBool SplashHalftone::isStatic() { + return screen->isStatic(value); } diff --git a/xpdf/splash/SplashPattern.h b/xpdf/splash/SplashPattern.h index 4bf447785..fb633dac9 100644 --- a/xpdf/splash/SplashPattern.h +++ b/xpdf/splash/SplashPattern.h @@ -30,7 +30,12 @@ public: virtual ~SplashPattern(); - virtual SplashColor getColor(int x, int y) = 0; + // Return the color value for a specific pixel. + virtual void getColor(int x, int y, SplashColorPtr c) = 0; + + // Returns true if this pattern object will return the same color + // value for all pixels. + virtual GBool isStatic() = 0; private: }; @@ -42,13 +47,15 @@ private: class SplashSolidColor: public SplashPattern { public: - SplashSolidColor(SplashColor colorA); + SplashSolidColor(SplashColorPtr colorA); virtual SplashPattern *copy() { return new SplashSolidColor(color); } virtual ~SplashSolidColor(); - virtual SplashColor getColor(int x, int y); + virtual void getColor(int x, int y, SplashColorPtr c); + + virtual GBool isStatic() { return gTrue; } private: @@ -62,14 +69,16 @@ private: class SplashHalftone: public SplashPattern { public: - SplashHalftone(SplashColor color0A, SplashColor color1A, + SplashHalftone(SplashColorPtr color0A, SplashColorPtr color1A, SplashScreen *screenA, SplashCoord valueA); virtual SplashPattern *copy(); virtual ~SplashHalftone(); - virtual SplashColor getColor(int x, int y); + virtual void getColor(int x, int y, SplashColorPtr c); + + virtual GBool isStatic(); private: diff --git a/xpdf/splash/SplashScreen.cc b/xpdf/splash/SplashScreen.cc index 423085642..27c341c72 100644 --- a/xpdf/splash/SplashScreen.cc +++ b/xpdf/splash/SplashScreen.cc @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include "gmem.h" #include "SplashMath.h" #include "SplashScreen.h" @@ -23,85 +24,118 @@ // Gamma correction (gamma = 1 / 1.33) is also computed here. SplashScreen::SplashScreen(int sizeA) { SplashCoord *dist; - SplashCoord u, v, d; - int x, y, x1, y1, i; + SplashCoord u, v, d, val; + int size2, x, y, x1, y1, i; - size = sizeA >> 1; - if (size < 1) { - size = 1; + size2 = sizeA >> 1; + if (size2 < 1) { + size2 = 1; } + size = size2 << 1; // initialize the threshold matrix - mat = (SplashCoord *)gmalloc(2 * size * size * sizeof(SplashCoord)); - for (y = 0; y < 2 * size; ++y) { + mat = (SplashCoord *)gmallocn(size * size, sizeof(SplashCoord)); + for (y = 0; y < size; ++y) { for (x = 0; x < size; ++x) { mat[y * size + x] = -1; } } // build the distance matrix - dist = (SplashCoord *)gmalloc(2 * size * size * sizeof(SplashCoord)); - for (y = 0; y < size; ++y) { - for (x = 0; x < size; ++x) { - if (x + y < size - 1) { - u = (SplashCoord)x + 0.5 - 0; //~ (-0.5); + dist = (SplashCoord *)gmallocn(size * size2, sizeof(SplashCoord)); + for (y = 0; y < size2; ++y) { + for (x = 0; x < size2; ++x) { + if (x + y < size2 - 1) { + u = (SplashCoord)x + 0.5 - 0; v = (SplashCoord)y + 0.5 - 0; } else { - u = (SplashCoord)x + 0.5 - (SplashCoord)size; //~ ((SplashCoord)size - 0.5); - v = (SplashCoord)y + 0.5 - (SplashCoord)size; + u = (SplashCoord)x + 0.5 - (SplashCoord)size2; + v = (SplashCoord)y + 0.5 - (SplashCoord)size2; } - dist[y * size + x] = u*u + v*v; + dist[y * size2 + x] = u*u + v*v; } } - for (y = 0; y < size; ++y) { - for (x = 0; x < size; ++x) { + for (y = 0; y < size2; ++y) { + for (x = 0; x < size2; ++x) { if (x < y) { - u = (SplashCoord)x + 0.5 - 0; //~ (-0.5); - v = (SplashCoord)y + 0.5 - (SplashCoord)size; + u = (SplashCoord)x + 0.5 - 0; + v = (SplashCoord)y + 0.5 - (SplashCoord)size2; } else { - u = (SplashCoord)x + 0.5 - (SplashCoord)size; //~ ((SplashCoord)size - 0.5); + u = (SplashCoord)x + 0.5 - (SplashCoord)size2; v = (SplashCoord)y + 0.5 - 0; } - dist[(size + y) * size + x] = u*u + v*v; + dist[(size2 + y) * size2 + x] = u*u + v*v; } } // build the threshold matrix + minVal = 1; + maxVal = 0; x1 = y1 = 0; // make gcc happy - for (i = 1; i <= 2 * size * size; ++i) { - d = 2 * size * size; - for (y = 0; y < 2 * size; ++y) { - for (x = 0; x < size; ++x) { + for (i = 1; i <= size * size2; ++i) { + d = size * size2; + for (y = 0; y < size; ++y) { + for (x = 0; x < size2; ++x) { if (mat[y * size + x] < 0 && - dist[y * size + x] < d) { + dist[y * size2 + x] < d) { x1 = x; y1 = y; - d = dist[y1 * size + x1]; + d = dist[y1 * size2 + x1]; + } + } + } + u = (SplashCoord)1 - (SplashCoord)i / (SplashCoord)(size * size2 + 1); + val = splashPow(u, 1.33); + if (val < minVal) { + minVal = val; } + if (val > maxVal) { + maxVal = val; } + mat[y1 * size + x1] = val; + if (y1 < size2) { + mat[(y1 + size2) * size + x1 + size2] = val; + } else { + mat[(y1 - size2) * size + x1 + size2] = val; } - u = 1.0 - (SplashCoord)i / (SplashCoord)(2 * size * size + 1); - mat[y1 * size + x1] = splashPow(u, 1.33); } gfree(dist); } +SplashScreen::SplashScreen(SplashScreen *screen) { + int n; + + size = screen->size; + n = size * size * sizeof(SplashCoord); + mat = (SplashCoord *)gmalloc(n); + memcpy(mat, screen->mat, n); + minVal = screen->minVal; + maxVal = screen->maxVal; +} + SplashScreen::~SplashScreen() { gfree(mat); } int SplashScreen::test(int x, int y, SplashCoord value) { - SplashCoord *mat1; int xx, yy; - xx = x % (2 * size); - yy = y % (2 * size); - mat1 = mat; - if ((xx / size) ^ (yy / size)) { - mat1 += size * size; + if (value < minVal) { + return 0; + } + if (value >= maxVal) { + return 1; } - xx %= size; - yy %= size; - return value < mat1[yy * size + xx] ? 0 : 1; + if ((xx = x % size) < 0) { + xx = -xx; + } + if ((yy = y % size) < 0) { + yy = -yy; + } + return value < mat[yy * size + xx] ? 0 : 1; +} + +GBool SplashScreen::isStatic(SplashCoord value) { + return value < minVal || value >= maxVal; } diff --git a/xpdf/splash/SplashScreen.h b/xpdf/splash/SplashScreen.h index 33024bbbc..66f7c4898 100644 --- a/xpdf/splash/SplashScreen.h +++ b/xpdf/splash/SplashScreen.h @@ -23,18 +23,28 @@ class SplashScreen { public: SplashScreen(int sizeA); + SplashScreen(SplashScreen *screen); ~SplashScreen(); - SplashScreen *copy() { return new SplashScreen(size << 1); } + SplashScreen *copy() { return new SplashScreen(this); } // Return the computed pixel value (0=black, 1=white) for the gray // level at (, ). int test(int x, int y, SplashCoord value); + // Returns true if value is above the white threshold or below the + // black threshold, i.e., if the corresponding halftone will be + // solid white or black. + GBool isStatic(SplashCoord value); + private: SplashCoord *mat; // threshold matrix int size; // size of the threshold matrix + SplashCoord minVal; // any pixel value below minVal generates + // solid black + SplashCoord maxVal; // any pixel value above maxVal generates + // solid white }; #endif diff --git a/xpdf/splash/SplashState.cc b/xpdf/splash/SplashState.cc index 7d5dc8366..3fd17e172 100644 --- a/xpdf/splash/SplashState.cc +++ b/xpdf/splash/SplashState.cc @@ -21,6 +21,11 @@ // SplashState //------------------------------------------------------------------------ +// number of components in each color mode +int splashColorModeNComps[] = { + 1, 1, 2, 3, 3, 4, 4 +}; + SplashState::SplashState(int width, int height) { SplashColor color; @@ -28,6 +33,9 @@ SplashState::SplashState(int width, int height) { strokePattern = new SplashSolidColor(color); fillPattern = new SplashSolidColor(color); screen = new SplashScreen(10); + blendFunc = NULL; + strokeAlpha = 1; + fillAlpha = 1; lineWidth = 0; lineCap = splashLineCapButt; lineJoin = splashLineJoinMiter; @@ -44,6 +52,9 @@ SplashState::SplashState(SplashState *state) { strokePattern = state->strokePattern->copy(); fillPattern = state->fillPattern->copy(); screen = state->screen->copy(); + blendFunc = state->blendFunc; + strokeAlpha = state->strokeAlpha; + fillAlpha = state->fillAlpha; lineWidth = state->lineWidth; lineCap = state->lineCap; lineJoin = state->lineJoin; @@ -51,7 +62,7 @@ SplashState::SplashState(SplashState *state) { flatness = state->flatness; if (state->lineDash) { lineDashLength = state->lineDashLength; - lineDash = (SplashCoord *)gmalloc(lineDashLength * sizeof(SplashCoord)); + lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); memcpy(lineDash, state->lineDash, lineDashLength * sizeof(SplashCoord)); } else { lineDash = NULL; @@ -90,7 +101,7 @@ void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA, gfree(lineDash); lineDashLength = lineDashLengthA; if (lineDashLength > 0) { - lineDash = (SplashCoord *)gmalloc(lineDashLength * sizeof(SplashCoord)); + lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); memcpy(lineDash, lineDashA, lineDashLength * sizeof(SplashCoord)); } else { lineDash = NULL; diff --git a/xpdf/splash/SplashState.h b/xpdf/splash/SplashState.h index 8fcb54b07..ba00d2da0 100644 --- a/xpdf/splash/SplashState.h +++ b/xpdf/splash/SplashState.h @@ -70,6 +70,9 @@ private: SplashPattern *strokePattern; SplashPattern *fillPattern; SplashScreen *screen; + SplashBlendFunc blendFunc; + SplashCoord strokeAlpha; + SplashCoord fillAlpha; SplashCoord lineWidth; int lineCap; int lineJoin; diff --git a/xpdf/splash/SplashT1Font.cc b/xpdf/splash/SplashT1Font.cc index 55d3c34a3..d94f4af51 100644 --- a/xpdf/splash/SplashT1Font.cc +++ b/xpdf/splash/SplashT1Font.cc @@ -159,10 +159,10 @@ SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA): } // transform the font - matrix.cxx = mat[0] / size; - matrix.cxy = mat[1] / size; - matrix.cyx = mat[2] / size; - matrix.cyy = mat[3] / size; + matrix.cxx = (double)mat[0] / size; + matrix.cxy = (double)mat[1] / size; + matrix.cyx = (double)mat[2] / size; + matrix.cyy = (double)mat[3] / size; T1_TransformFont(t1libID, &matrix); } @@ -215,14 +215,22 @@ SplashPath *SplashT1Font::getGlyphPath(int c) { T1_PATHSEGMENT *seg; T1_BEZIERSEGMENT *bez; SplashCoord x, y, x1, y1; + GBool needClose; path = new SplashPath(); - outline = T1_GetCharOutline(t1libID, c, size, NULL); + if (!(outline = T1_GetCharOutline(t1libID, c, size, NULL))) { + return path; + } x = 0; y = 0; + needClose = gFalse; for (seg = outline; seg; seg = seg->link) { switch (seg->type) { case T1_PATHTYPE_MOVE: + if (needClose) { + path->close(); + needClose = gFalse; + } x += seg->dest.x / 65536.0; y += seg->dest.y / 65536.0; path->moveTo(x, y); @@ -231,6 +239,7 @@ SplashPath *SplashT1Font::getGlyphPath(int c) { x += seg->dest.x / 65536.0; y += seg->dest.y / 65536.0; path->lineTo(x, y); + needClose = gTrue; break; case T1_PATHTYPE_BEZIER: bez = (T1_BEZIERSEGMENT *)seg; @@ -241,9 +250,13 @@ SplashPath *SplashT1Font::getGlyphPath(int c) { x1, y1); x = x1; y = y1; + needClose = gTrue; break; } } + if (needClose) { + path->close(); + } T1_FreeOutline(outline); return path; } diff --git a/xpdf/splash/SplashT1Font.h b/xpdf/splash/SplashT1Font.h index e745e07c8..353f37608 100644 --- a/xpdf/splash/SplashT1Font.h +++ b/xpdf/splash/SplashT1Font.h @@ -17,6 +17,8 @@ #include "SplashFont.h" +class SplashT1FontFile; + //------------------------------------------------------------------------ // SplashT1Font //------------------------------------------------------------------------ diff --git a/xpdf/splash/SplashT1FontFile.cc b/xpdf/splash/SplashT1FontFile.cc index 210726eca..c87eeeb98 100644 --- a/xpdf/splash/SplashT1FontFile.cc +++ b/xpdf/splash/SplashT1FontFile.cc @@ -65,8 +65,8 @@ SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA, encStrSize += strlen(encA[i]) + 1; } } - encTmp = (const char **)gmalloc(257 * sizeof(char *)); - encStrTmp = (char *)gmalloc(encStrSize * sizeof(char)); + encTmp = (const char **)gmallocn(257, sizeof(char *)); + encStrTmp = (char *)gmallocn(encStrSize, sizeof(char)); encPtr = encStrTmp; for (i = 0; i < 256; ++i) { if (encA[i]) { diff --git a/xpdf/splash/SplashTypes.h b/xpdf/splash/SplashTypes.h index 91b120f8d..04dd9f7ba 100644 --- a/xpdf/splash/SplashTypes.h +++ b/xpdf/splash/SplashTypes.h @@ -21,52 +21,109 @@ typedef double SplashCoord; //------------------------------------------------------------------------ enum SplashColorMode { - splashModeMono1, - splashModeMono8, - splashModeRGB8, - splashModeBGR8Packed + splashModeMono1, // 1 bit per component, 8 pixels per byte, + // MSbit is on the left + splashModeMono8, // 1 byte per component, 1 byte per pixel + splashModeAMono8, // 1 byte per component, 2 bytes per pixel: + // AMAM... + splashModeRGB8, // 1 byte per component, 3 bytes per pixel: + // RGBRGB... + splashModeBGR8, // 1 byte per component, 3 bytes per pixel: + // BGRBGR... + splashModeARGB8, // 1 byte per component, 4 bytes per pixel: + // ARGBARGB... + splashModeBGRA8 // 1 byte per component, 4 bytes per pixel: + // BGRABGRA... +#if SPLASH_CMYK + , + splashModeCMYK8, // 1 byte per component, 4 bytes per pixel: + // CMYKCMYK... + splashModeACMYK8 // 1 byte per component, 5 bytes per pixel: + // ACMYKACMYK +#endif }; +// number of components in each color mode +// (defined in SplashState.cc) +extern int splashColorModeNComps[]; + // max number of components in any SplashColor -#define splashMaxColorComps 3 - -// 1-bit gray or alpha -typedef Guchar SplashMono1; -typedef Guchar SplashMono1P; // packed - -// 8-bit gray or alpha -typedef Guchar SplashMono8; - -// 3x8-bit RGB: (MSB) 00RRGGBB (LSB) -typedef Guint SplashRGB8; -#define splashRGB8R(rgb8) (((rgb8) >> 16) & 0xff) -#define splashRGB8G(rgb8) (((rgb8) >> 8) & 0xff) -#define splashRGB8B(rgb8) ((rgb8) & 0xff) -#define splashMakeRGB8(r, g, b) \ - ((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff)) - -// 3x8-bit RGB: (MSB) 00BBGGRR (LSB) -typedef Guint SplashBGR8; -typedef Guchar SplashBGR8P; // packed -#define splashBGR8R(bgr8) ((bgr8) & 0xff) -#define splashBGR8G(bgr8) (((bgr8) >> 8) & 0xff) -#define splashBGR8B(bgr8) (((bgr8) >> 16) & 0xff) -#define splashMakeBGR8(r, g, b) \ - ((((b) & 0xff) << 16) | (((g) & 0xff) << 8) | ((r) & 0xff)) - -union SplashColor { - SplashMono1 mono1; - SplashMono8 mono8; - SplashRGB8 rgb8; - SplashBGR8 bgr8; -}; +#if SPLASH_CMYK +# define splashMaxColorComps 5 +#else +# define splashMaxColorComps 4 +#endif -union SplashColorPtr { - SplashMono1P *mono1; - SplashMono8 *mono8; - SplashRGB8 *rgb8; - SplashBGR8P *bgr8; -}; +typedef Guchar SplashColor[splashMaxColorComps]; +typedef Guchar *SplashColorPtr; + +// AMono8 +static inline Guchar splashAMono8A(SplashColorPtr am8) { return am8[0]; } +static inline Guchar splashAMono8M(SplashColorPtr am8) { return am8[1]; } + +// RGB8 +static inline Guchar splashRGB8R(SplashColorPtr rgb8) { return rgb8[0]; } +static inline Guchar splashRGB8G(SplashColorPtr rgb8) { return rgb8[1]; } +static inline Guchar splashRGB8B(SplashColorPtr rgb8) { return rgb8[2]; } + +// BGR8 +static inline Guchar splashBGR8R(SplashColorPtr bgr8) { return bgr8[2]; } +static inline Guchar splashBGR8G(SplashColorPtr bgr8) { return bgr8[1]; } +static inline Guchar splashBGR8B(SplashColorPtr bgr8) { return bgr8[0]; } + +// ARGB8 +static inline Guchar splashARGB8A(SplashColorPtr argb8) { return argb8[0]; } +static inline Guchar splashARGB8R(SplashColorPtr argb8) { return argb8[1]; } +static inline Guchar splashARGB8G(SplashColorPtr argb8) { return argb8[2]; } +static inline Guchar splashARGB8B(SplashColorPtr argb8) { return argb8[3]; } + +// ARGB8 +static inline Guchar splashBGRA8A(SplashColorPtr bgra8) { return bgra8[3]; } +static inline Guchar splashBGRA8R(SplashColorPtr bgra8) { return bgra8[2]; } +static inline Guchar splashBGRA8G(SplashColorPtr bgra8) { return bgra8[1]; } +static inline Guchar splashBGRA8B(SplashColorPtr bgra8) { return bgra8[0]; } + +#if SPLASH_CMYK +// CMYK8 +static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; } +static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; } +static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; } +static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; } + +// ACMYK8 +static inline Guchar splashACMYK8A(SplashColorPtr acmyk8) { return acmyk8[0]; } +static inline Guchar splashACMYK8C(SplashColorPtr acmyk8) { return acmyk8[1]; } +static inline Guchar splashACMYK8M(SplashColorPtr acmyk8) { return acmyk8[2]; } +static inline Guchar splashACMYK8Y(SplashColorPtr acmyk8) { return acmyk8[3]; } +static inline Guchar splashACMYK8K(SplashColorPtr acmyk8) { return acmyk8[4]; } +#endif + +static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; +#if SPLASH_CMYK + dest[4] = src[4]; +#endif +} + +static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) { + dest[0] ^= src[0]; + dest[1] ^= src[1]; + dest[2] ^= src[2]; + dest[3] ^= src[3]; +#if SPLASH_CMYK + dest[4] ^= src[4]; +#endif +} + +//------------------------------------------------------------------------ +// blend functions +//------------------------------------------------------------------------ + +typedef void (*SplashBlendFunc)(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm); //------------------------------------------------------------------------ // error results diff --git a/xpdf/splash/SplashXPath.cc b/xpdf/splash/SplashXPath.cc index e1a3afbaa..145e9ea2e 100644 --- a/xpdf/splash/SplashXPath.cc +++ b/xpdf/splash/SplashXPath.cc @@ -34,8 +34,7 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness, GBool closeSubpaths) { SplashCoord xc, yc, dx, dy, r, x0, y0, x1, y1; int quad0, quad1, quad; - int i, curSubpath; - GBool last; + int curSubpath, n, i, j; segs = NULL; length = size = 0; @@ -93,39 +92,28 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness, } else { quad1 = 3; } + n = 0; // make gcc happy + if (quad0 == quad1) { + switch (quad0) { + case 0: + case 1: n = path->pts[i-1].x < path->pts[i+1].x ? 0 : 4; break; + case 2: + case 3: n = path->pts[i-1].x > path->pts[i+1].x ? 0 : 4; break; + } + } else { + n = (quad1 - quad0) & 3; + } x0 = path->pts[i-1].x; y0 = path->pts[i-1].y; x1 = y1 = 0; // make gcc happy quad = quad0; - while (1) { + for (j = 0; j < n; ++j) { switch (quad) { case 0: x1 = xc; y1 = yc - r; break; case 1: x1 = xc + r; y1 = yc; break; case 2: x1 = xc; y1 = yc + r; break; case 3: x1 = xc - r; y1 = yc; break; } - last = gFalse; - if (quad == quad1) { - switch (quad) { - case 0: - case 1: last = path->pts[i+1].x > x0; break; - case 2: - case 3: last = path->pts[i+1].x < x0; break; - } - } - if (last) { - addArc(x0, y0, path->pts[i+1].x, path->pts[i+1].y, - xc, yc, r, quad, flatness, - quad == quad0 && (path->flags[i-1] & splashPathFirst), - (path->flags[i+1] & splashPathLast), - quad == quad0 && !closeSubpaths && - (path->flags[i-1] & splashPathFirst) && - !(path->flags[i-1] & splashPathClosed), - !closeSubpaths && - (path->flags[i+1] & splashPathLast) && - !(path->flags[i+1] & splashPathClosed)); - break; - } else { addArc(x0, y0, x1, y1, xc, yc, r, quad, flatness, quad == quad0 && (path->flags[i-1] & splashPathFirst), @@ -138,7 +126,16 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness, y0 = y1; quad = (quad + 1) & 3; } - } + addArc(x0, y0, path->pts[i+1].x, path->pts[i+1].y, + xc, yc, r, quad, flatness, + quad == quad0 && (path->flags[i-1] & splashPathFirst), + (path->flags[i+1] & splashPathLast), + quad == quad0 && !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + !closeSubpaths && + (path->flags[i+1] & splashPathLast) && + !(path->flags[i+1] & splashPathClosed)); i += 2; // line segment @@ -172,7 +169,7 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness, SplashXPath::SplashXPath(SplashXPath *xPath) { length = xPath->length; size = xPath->size; - segs = (SplashXPathSeg *)gmalloc(size * sizeof(SplashXPathSeg)); + segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg)); memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg)); } @@ -189,7 +186,7 @@ void SplashXPath::grow(int nSegs) { while (size < length + nSegs) { size *= 2; } - segs = (SplashXPathSeg *)grealloc(segs, size * sizeof(SplashXPathSeg)); + segs = (SplashXPathSeg *)greallocn(segs, size, sizeof(SplashXPathSeg)); } } @@ -309,8 +306,8 @@ void SplashXPath::addArc(SplashCoord x0, SplashCoord y0, // compute the arc midpoint t = (xx0 - xc) * (xx1 - xc) - (yy0 - yc) * (yy1 - yc); - xm = splashSqrt(0.5 * (r2 + t)); - ym = splashSqrt(0.5 * (r2 - t)); + xm = splashSqrt((SplashCoord)0.5 * (r2 + t)); + ym = splashSqrt((SplashCoord)0.5 * (r2 - t)); switch (quad) { case 0: xm = xc - xm; ym = yc - ym; break; case 1: xm = xc + xm; ym = yc - ym; break; @@ -320,8 +317,8 @@ void SplashXPath::addArc(SplashCoord x0, SplashCoord y0, // compute distance from midpoint of straight segment to midpoint // of arc - dx = 0.5 * (xx0 + xx1) - xm; - dy = 0.5 * (yy0 + yy1) - ym; + dx = (SplashCoord)0.5 * (xx0 + xx1) - xm; + dy = (SplashCoord)0.5 * (yy0 + yy1) - ym; // if the arc is flat enough, or no more subdivisions are allowed, // add the straight line segment @@ -376,7 +373,7 @@ void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0, segs[length].flags |= splashXPathVert; } else { segs[length].dxdy = (x1 - x0) / (y1 - y0); - segs[length].dydx = 1 / segs[length].dxdy; + segs[length].dydx = (SplashCoord)1 / segs[length].dxdy; } if (y0 > y1) { segs[length].flags |= splashXPathFlip; diff --git a/xpdf/splash/SplashXPathScanner.cc b/xpdf/splash/SplashXPathScanner.cc index c93cc49e9..96f51cf44 100644 --- a/xpdf/splash/SplashXPathScanner.cc +++ b/xpdf/splash/SplashXPathScanner.cc @@ -40,6 +40,10 @@ SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA) { eo = eoA; // compute the bbox + if (xPath->length == 0) { + xMin = yMin = 1; + xMax = yMax = 0; + } else { seg = &xPath->segs[0]; if (seg->x0 <= seg->x1) { xMinFP = seg->x0; @@ -81,12 +85,12 @@ SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA) { xMax = splashFloor(xMaxFP); yMin = splashFloor(yMinFP); yMax = splashFloor(yMaxFP); + } - interY = 0; + interY = yMin - 1; xPathIdx = 0; inter = NULL; interLen = interSize = 0; - computeIntersections(yMin); } SplashXPathScanner::~SplashXPathScanner() { @@ -222,8 +226,8 @@ void SplashXPathScanner::computeIntersections(int y) { } else { interSize *= 2; } - inter = (SplashIntersect *)grealloc(inter, - interSize * sizeof(SplashIntersect)); + inter = (SplashIntersect *)greallocn(inter, interSize, + sizeof(SplashIntersect)); } if (seg->flags & splashXPathHoriz) { @@ -234,14 +238,14 @@ void SplashXPathScanner::computeIntersections(int y) { } else { if (ySegMin <= y) { // intersection with top edge - xx0 = seg->x0 + (y - seg->y0) * seg->dxdy; + xx0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy; } else { // x coord of segment endpoint with min y coord xx0 = (seg->flags & splashXPathFlip) ? seg->x1 : seg->x0; } if (ySegMax >= y + 1) { // intersection with bottom edge - xx1 = seg->x0 + (y + 1 - seg->y0) * seg->dxdy; + xx1 = seg->x0 + ((SplashCoord)y + 1 - seg->y0) * seg->dxdy; } else { // x coord of segment endpoint with max y coord xx1 = (seg->flags & splashXPathFlip) ? seg->x0 : seg->x1; @@ -254,7 +258,9 @@ void SplashXPathScanner::computeIntersections(int y) { inter[interLen].x0 = splashFloor(xx1); inter[interLen].x1 = splashFloor(xx0); } - if (ySegMin <= y && y < ySegMax && !(seg->flags & splashXPathHoriz)) { + if (ySegMin <= y && + (SplashCoord)y < ySegMax && + !(seg->flags & splashXPathHoriz)) { inter[interLen].count = eo ? 1 : (seg->flags & splashXPathFlip) ? 1 : -1; } else { diff --git a/xpdf/xpdf/Annot.cc b/xpdf/xpdf/Annot.cc index 245780dab..68bfb6d0b 100644 --- a/xpdf/xpdf/Annot.cc +++ b/xpdf/xpdf/Annot.cc @@ -12,42 +12,26 @@ #pragma implementation #endif +#include #include "gmem.h" #include "Object.h" +#include "Catalog.h" #include "Gfx.h" +#include "Lexer.h" #include "Annot.h" //------------------------------------------------------------------------ // Annot //------------------------------------------------------------------------ -Annot::Annot(XRef *xrefA, Dict *dict) { +Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) { Object apObj, asObj, obj1, obj2; + GBool regen, isTextField; double t; ok = gFalse; xref = xrefA; - - if (dict->lookup("AP", &apObj)->isDict()) { - if (dict->lookup("AS", &asObj)->isName()) { - if (apObj.dictLookup("N", &obj1)->isDict()) { - if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) { - obj2.copy(&appearance); - ok = gTrue; - } - obj2.free(); - } - obj1.free(); - } else { - if (apObj.dictLookupNF("N", &obj1)->isRef()) { - obj1.copy(&appearance); - ok = gTrue; - } - obj1.free(); - } - asObj.free(); - } - apObj.free(); + appearBuf = NULL; if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) { @@ -76,10 +60,204 @@ Annot::Annot(XRef *xrefA, Dict *dict) { xMax = yMax = 1; } obj1.free(); + + // check if field apperances need to be regenerated + regen = gFalse; + if (acroForm) { + acroForm->lookup("NeedAppearances", &obj1); + if (obj1.isBool() && obj1.getBool()) { + regen = gTrue; + } + obj1.free(); + } + + // check for a text-type field + isTextField = dict->lookup("FT", &obj1)->isName("Tx"); + obj1.free(); + +#if 0 //~ appearance stream generation is not finished yet + if (regen && isTextField) { + generateAppearance(acroForm, dict); + } else { +#endif + if (dict->lookup("AP", &apObj)->isDict()) { + if (dict->lookup("AS", &asObj)->isName()) { + if (apObj.dictLookup("N", &obj1)->isDict()) { + if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) { + obj2.copy(&appearance); + ok = gTrue; + } else { + obj2.free(); + if (obj1.dictLookupNF("Off", &obj2)->isRef()) { + obj2.copy(&appearance); + ok = gTrue; + } + } + obj2.free(); + } + obj1.free(); + } else { + if (apObj.dictLookupNF("N", &obj1)->isRef()) { + obj1.copy(&appearance); + ok = gTrue; + } + obj1.free(); + } + asObj.free(); + } + apObj.free(); +#if 0 //~ appearance stream generation is not finished yet + } +#endif } Annot::~Annot() { appearance.free(); + if (appearBuf) { + delete appearBuf; + } +} + +void Annot::generateAppearance(Dict *acroForm, Dict *dict) { + MemStream *appearStream; + Object daObj, vObj, drObj, appearDict, obj1, obj2; + GString *daStr, *daStr1, *vStr, *s; + char buf[256]; + double fontSize; + int c; + int i0, i1; + + //~ DA can be inherited + if (dict->lookup("DA", &daObj)->isString()) { + daStr = daObj.getString(); + + // look for a font size + //~ may want to parse the DS entry in place of this (if it exists) + daStr1 = NULL; + fontSize = 10; + for (i1 = daStr->getLength() - 2; i1 >= 0; --i1) { + if (daStr->getChar(i1) == 'T' && daStr->getChar(i1+1) == 'f') { + for (--i1; i1 >= 0 && Lexer::isSpace(daStr->getChar(i1)); --i1) ; + for (i0 = i1; i0 >= 0 && !Lexer::isSpace(daStr->getChar(i0)); --i0) ; + if (i0 >= 0) { + ++i0; + ++i1; + s = new GString(daStr, i0, i1 - i0); + fontSize = atof(s->getCString()); + delete s; + + // autosize the font + if (fontSize == 0) { + fontSize = 0.67 * (yMax - yMin); + daStr1 = new GString(daStr, 0, i0); + sprintf(buf, "%.2f", fontSize); + daStr1->append(buf); + daStr1->append(daStr->getCString() + i1, + daStr->getLength() - i1); + } + } + break; + } + } + + // build the appearance stream contents + appearBuf = new GString(); + appearBuf->append("/Tx BMC\n"); + appearBuf->append("q BT\n"); + appearBuf->append(daStr1 ? daStr1 : daStr)->append("\n"); + if (dict->lookup("V", &vObj)->isString()) { + //~ handle quadding -- this requires finding the font and using + //~ the encoding and char widths + sprintf(buf, "1 0 0 1 %.2f %.2f Tm\n", 2.0, yMax - yMin - fontSize); + appearBuf->append(buf); + sprintf(buf, "%g TL\n", fontSize); + appearBuf->append(buf); + vStr = vObj.getString(); + i0 = 0; + while (i0 < vStr->getLength()) { + for (i1 = i0; + i1 < vStr->getLength() && + vStr->getChar(i1) != '\n' && vStr->getChar(i1) != '\r'; + ++i1) ; + if (i0 > 0) { + appearBuf->append("T*\n"); + } + appearBuf->append('('); + for (; i0 < i1; ++i0) { + c = vStr->getChar(i0); + if (c == '(' || c == ')' || c == '\\') { + appearBuf->append('\\'); + appearBuf->append(c); + } else if (c < 0x20 || c >= 0x80) { + sprintf(buf, "\\%03o", c); + appearBuf->append(buf); + } else { + appearBuf->append(c); + } + } + appearBuf->append(") Tj\n"); + if (i1 + 1 < vStr->getLength() && + vStr->getChar(i1) == '\r' && vStr->getChar(i1 + 1) == '\n') { + i0 = i1 + 2; + } else { + i0 = i1 + 1; + } + } + } + vObj.free(); + appearBuf->append("ET Q\n"); + appearBuf->append("EMC\n"); + + // build the appearance stream dictionary + appearDict.initDict(xref); + appearDict.dictAdd(copyString("Length"), + obj1.initInt(appearBuf->getLength())); + appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form")); + obj1.initArray(xref); + obj1.arrayAdd(obj2.initReal(0)); + obj1.arrayAdd(obj2.initReal(0)); + obj1.arrayAdd(obj2.initReal(xMax - xMin)); + obj1.arrayAdd(obj2.initReal(yMax - yMin)); + appearDict.dictAdd(copyString("BBox"), &obj1); + + // find the resource dictionary + dict->lookup("DR", &drObj); + if (!drObj.isDict()) { + dict->lookup("Parent", &obj1); + while (obj1.isDict()) { + drObj.free(); + obj1.dictLookup("DR", &drObj); + if (drObj.isDict()) { + break; + } + obj1.dictLookup("Parent", &obj2); + obj1.free(); + obj1 = obj2; + } + obj1.free(); + if (!drObj.isDict()) { + if (acroForm) { + drObj.free(); + acroForm->lookup("DR", &drObj); + } + } + } + if (drObj.isDict()) { + appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1)); + } + drObj.free(); + + // build the appearance stream + appearStream = new MemStream(appearBuf->getCString(), 0, + appearBuf->getLength(), &appearDict); + appearance.initStream(appearStream); + ok = gTrue; + + if (daStr1) { + delete daStr1; + } + } + daObj.free(); } void Annot::draw(Gfx *gfx) { @@ -95,7 +273,8 @@ void Annot::draw(Gfx *gfx) { // Annots //------------------------------------------------------------------------ -Annots::Annots(XRef *xref, Object *annotsObj) { +Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) { + Dict *acroForm; Annot *annot; Object obj1; int size; @@ -105,14 +284,16 @@ Annots::Annots(XRef *xref, Object *annotsObj) { size = 0; nAnnots = 0; + acroForm = catalog->getAcroForm()->isDict() ? + catalog->getAcroForm()->getDict() : NULL; if (annotsObj->isArray()) { for (i = 0; i < annotsObj->arrayGetLength(); ++i) { if (annotsObj->arrayGet(i, &obj1)->isDict()) { - annot = new Annot(xref, obj1.getDict()); + annot = new Annot(xref, acroForm, obj1.getDict()); if (annot->isOk()) { if (nAnnots >= size) { size += 16; - annots = (Annot **)grealloc(annots, size * sizeof(Annot *)); + annots = (Annot **)greallocn(annots, size, sizeof(Annot *)); } annots[nAnnots++] = annot; } else { diff --git a/xpdf/xpdf/Annot.h b/xpdf/xpdf/Annot.h index 89dde0f90..f10cb0344 100644 --- a/xpdf/xpdf/Annot.h +++ b/xpdf/xpdf/Annot.h @@ -16,6 +16,7 @@ #endif class XRef; +class Catalog; class Gfx; //------------------------------------------------------------------------ @@ -25,7 +26,7 @@ class Gfx; class Annot { public: - Annot(XRef *xrefA, Dict *dict); + Annot(XRef *xrefA, Dict *acroForm, Dict *dict); ~Annot(); GBool isOk() { return ok; } @@ -36,9 +37,12 @@ public: private: + void generateAppearance(Dict *acroForm, Dict *dict); + XRef *xref; // the xref table for this PDF file Object appearance; // a reference to the Form XObject stream // for the normal appearance + GString *appearBuf; double xMin, yMin, // annotation rectangle xMax, yMax; GBool ok; @@ -52,7 +56,7 @@ class Annots { public: // Extract non-link annotations from array of annotations. - Annots(XRef *xref, Object *annotsObj); + Annots(XRef *xref, Catalog *catalog, Object *annotsObj); ~Annots(); diff --git a/xpdf/xpdf/Array.cc b/xpdf/xpdf/Array.cc index fd9a548b1..8232037b0 100644 --- a/xpdf/xpdf/Array.cc +++ b/xpdf/xpdf/Array.cc @@ -44,7 +44,7 @@ void Array::add(Object *elem) { } else { size *= 2; } - elems = (Object *)grealloc(elems, size * sizeof(Object)); + elems = (Object *)greallocn(elems, size, sizeof(Object)); } elems[length] = *elem; ++length; diff --git a/xpdf/xpdf/BuiltinFont.cc b/xpdf/xpdf/BuiltinFont.cc index 9ca7dd643..33c9fa5e1 100644 --- a/xpdf/xpdf/BuiltinFont.cc +++ b/xpdf/xpdf/BuiltinFont.cc @@ -24,7 +24,7 @@ BuiltinFontWidths::BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA) { int i, h; size = sizeA; - tab = (BuiltinFontWidth **)gmalloc(size * sizeof(BuiltinFontWidth *)); + tab = (BuiltinFontWidth **)gmallocn(size, sizeof(BuiltinFontWidth *)); for (i = 0; i < size; ++i) { tab[i] = NULL; } diff --git a/xpdf/xpdf/CMap.cc b/xpdf/xpdf/CMap.cc index 0a9813e1e..89905a8c3 100644 --- a/xpdf/xpdf/CMap.cc +++ b/xpdf/xpdf/CMap.cc @@ -49,7 +49,7 @@ CMap *CMap::parse(CMapCache *cache, GString *collectionA, PSTokenizer *pst; char tok1[256], tok2[256], tok3[256]; int n1, n2, n3; - Guint start, end; + Guint start, end, code; if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) { @@ -99,6 +99,30 @@ CMap *CMap::parse(CMapCache *cache, GString *collectionA, } } pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "begincidchar")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endcidchar")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endcidchar")) { + error(-1, "Illegal entry in cidchar block in CMap"); + break; + } + if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' && + n1 >= 4 && (n1 & 1) == 0)) { + error(-1, "Illegal entry in cidchar block in CMap"); + continue; + } + tok1[n1 - 1] = '\0'; + if (sscanf(tok1 + 1, "%x", &code) != 1) { + error(-1, "Illegal entry in cidchar block in CMap"); + continue; + } + n1 = (n1 - 2) / 2; + cmap->addCIDs(code, code, n1, (CID)atoi(tok2)); + } + pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok2, "begincidrange")) { while (pst->getToken(tok1, sizeof(tok1), &n1)) { if (!strcmp(tok1, "endcidrange")) { @@ -138,7 +162,7 @@ CMap::CMap(GString *collectionA, GString *cMapNameA) { collection = collectionA; cMapName = cMapNameA; wMode = 0; - vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry)); + vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); for (i = 0; i < 256; ++i) { vector[i].isVector = gFalse; vector[i].cid = 0; @@ -182,7 +206,7 @@ void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) { if (!dest[i].isVector) { dest[i].isVector = gTrue; dest[i].vector = - (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry)); + (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); for (j = 0; j < 256; ++j) { dest[i].vector[j].isVector = gFalse; dest[i].vector[j].cid = 0; @@ -213,7 +237,7 @@ void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end, if (!vec[i].isVector) { vec[i].isVector = gTrue; vec[i].vector = - (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry)); + (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); for (j = 0; j < 256; ++j) { vec[i].vector[j].isVector = gFalse; vec[i].vector[j].cid = 0; @@ -234,7 +258,7 @@ void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) { for (i = nBytes - 1; i >= 1; --i) { byte = (start >> (8 * i)) & 0xff; if (!vec[byte].isVector) { - error(-1, "Invalid CID (%*x - %*x) in CMap", + error(-1, "Invalid CID (%0*x - %0*x) in CMap", 2*nBytes, start, 2*nBytes, end); return; } @@ -243,7 +267,7 @@ void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) { cid = firstCID; for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) { if (vec[byte].isVector) { - error(-1, "Invalid CID (%*x - %*x) in CMap", + error(-1, "Invalid CID (%0*x - %0*x) in CMap", 2*nBytes, start, 2*nBytes, end); } else { vec[byte].cid = cid; diff --git a/xpdf/xpdf/Catalog.cc b/xpdf/xpdf/Catalog.cc index f1547c85d..6c3da8df9 100644 --- a/xpdf/xpdf/Catalog.cc +++ b/xpdf/xpdf/Catalog.cc @@ -67,16 +67,9 @@ Catalog::Catalog(XRef *xrefA) { } pagesSize = numPages0 = (int)obj.getNum(); obj.free(); - if (((unsigned) pagesSize >= INT_MAX / sizeof(Page *)) || - ((unsigned) pagesSize >= INT_MAX / sizeof(Ref))) - { - error(-1, "Invalid 'pagesSize'"); - ok = gFalse; - return; - } - pages = (Page **)gmalloc(pagesSize * sizeof(Page *)); - pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref)); + pages = (Page **)gmallocn(pagesSize, sizeof(Page *)); + pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref)); for (i = 0; i < pagesSize; ++i) { pages[i] = NULL; pageRefs[i].num = -1; @@ -134,6 +127,9 @@ Catalog::Catalog(XRef *xrefA) { // get the outline dictionary catDict.dictLookup("Outlines", &outline); + // get the AcroForm dictionary + catDict.dictLookup("AcroForm", &acroForm); + catDict.free(); return; @@ -167,6 +163,7 @@ Catalog::~Catalog() { metadata.free(); structTreeRoot.free(); outline.free(); + acroForm.free(); } GString *Catalog::readMetadata() { @@ -219,13 +216,8 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { } if (start >= pagesSize) { pagesSize += 32; - if ((unsigned) pagesSize >= INT_MAX / sizeof(Page*) || - (unsigned) pagesSize >= INT_MAX / sizeof(Ref)) { - error(-1, "Invalid 'pagesSize' parameter."); - goto err3; - } - pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *)); - pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref)); + pages = (Page **)greallocn(pages, pagesSize, sizeof(Page *)); + pageRefs = (Ref *)greallocn(pageRefs, pagesSize, sizeof(Ref)); for (j = pagesSize - 32; j < pagesSize; ++j) { pages[j] = NULL; pageRefs[j].num = -1; @@ -249,7 +241,6 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { } else { error(-1, "Kid object (page %d) is wrong type (%s)", start+1, kid.getTypeName()); - goto err2; } kid.free(); } diff --git a/xpdf/xpdf/Catalog.h b/xpdf/xpdf/Catalog.h index d8db44802..2ca6db9e9 100644 --- a/xpdf/xpdf/Catalog.h +++ b/xpdf/xpdf/Catalog.h @@ -108,6 +108,8 @@ public: Object *getOutline() { return &outline; } + Object *getAcroForm() { return &acroForm; } + private: XRef *xref; // the xref table for this PDF file @@ -122,6 +124,7 @@ private: Object metadata; // metadata stream Object structTreeRoot; // structure tree root dictionary Object outline; // outline dictionary + Object acroForm; // AcroForm dictionary GBool ok; // true if catalog is valid int readPageTree(Dict *pages, PageAttrs *attrs, int start); diff --git a/xpdf/xpdf/CharCodeToUnicode.cc b/xpdf/xpdf/CharCodeToUnicode.cc index 85ce5944f..ae6e1e4c8 100644 --- a/xpdf/xpdf/CharCodeToUnicode.cc +++ b/xpdf/xpdf/CharCodeToUnicode.cc @@ -70,13 +70,13 @@ CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName, } size = 32768; - mapA = (Unicode *)gmalloc(size * sizeof(Unicode)); + mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); mapLenA = 0; while (getLine(buf, sizeof(buf), f)) { if (mapLenA == size) { size *= 2; - mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode)); + mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); } if (sscanf(buf, "%x", &u) == 1) { mapA[mapLenA] = u; @@ -115,7 +115,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( } size = 4096; - mapA = (Unicode *)gmalloc(size * sizeof(Unicode)); + mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); memset(mapA, 0, size * sizeof(Unicode)); len = 0; sMapA = NULL; @@ -152,7 +152,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( while (u0 >= size) { size *= 2; } - mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode)); + mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode)); } if (n == 1) { @@ -162,7 +162,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( if (sMapLenA == sMapSizeA) { sMapSizeA += 16; sMapA = (CharCodeToUnicodeString *) - grealloc(sMapA, sMapSizeA * sizeof(CharCodeToUnicodeString)); + greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString)); } sMapA[sMapLenA].c = u0; for (i = 0; i < n; ++i) { @@ -251,7 +251,7 @@ void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); continue; } - addMapping(code1, tok2 + 1, n2 - 1, 0); + addMapping(code1, tok2 + 1, n2 - 2, 0); } pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok2, "beginbfrange")) { @@ -320,7 +320,7 @@ void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n, if (code >= mapLen) { oldLen = mapLen; mapLen = (code + 256) & ~255; - map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode)); + map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode)); for (i = oldLen; i < mapLen; ++i) { map[i] = 0; } @@ -335,7 +335,7 @@ void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n, if (sMapLen >= sMapSize) { sMapSize = sMapSize + 16; sMap = (CharCodeToUnicodeString *) - grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString)); + greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); } map[code] = 0; sMap[sMapLen].c = code; @@ -357,7 +357,7 @@ CharCodeToUnicode::CharCodeToUnicode(GString *tagA) { tag = tagA; mapLen = 256; - map = (Unicode *)gmalloc(mapLen * sizeof(Unicode)); + map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); for (i = 0; i < mapLen; ++i) { map[i] = 0; } @@ -376,7 +376,7 @@ CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA, tag = tagA; mapLen = mapLenA; if (copyMap) { - map = (Unicode *)gmalloc(mapLen * sizeof(Unicode)); + map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); memcpy(map, mapA, mapLen * sizeof(Unicode)); } else { map = mapA; @@ -433,24 +433,31 @@ GBool CharCodeToUnicode::match(GString *tagA) { } void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) { - int i; + int i, j; if (len == 1) { map[c] = u[0]; } else { - map[c] = 0; + for (i = 0; i < sMapLen; ++i) { + if (sMap[i].c == c) { + break; + } + } + if (i == sMapLen) { if (sMapLen == sMapSize) { sMapSize += 8; sMap = (CharCodeToUnicodeString *) - grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString)); - } - sMap[sMapLen].c = c; - sMap[sMapLen].len = len; - for (i = 0; i < len && i < maxUnicodeString; ++i) { - sMap[sMapLen].u[i] = u[i]; + greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); } ++sMapLen; } + map[c] = 0; + sMap[i].c = c; + sMap[i].len = len; + for (j = 0; j < len && j < maxUnicodeString; ++j) { + sMap[i].u[j] = u[j]; + } + } } int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) { @@ -480,7 +487,7 @@ CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) { int i; size = sizeA; - cache = (CharCodeToUnicode **)gmalloc(size * sizeof(CharCodeToUnicode *)); + cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *)); for (i = 0; i < size; ++i) { cache[i] = NULL; } diff --git a/xpdf/xpdf/CharCodeToUnicode.h b/xpdf/xpdf/CharCodeToUnicode.h index f75f4bd75..04852aea8 100644 --- a/xpdf/xpdf/CharCodeToUnicode.h +++ b/xpdf/xpdf/CharCodeToUnicode.h @@ -71,8 +71,6 @@ public: // code supported by the mapping. CharCode getLength() { return mapLen; } - CharCode getMapLen() { return mapLen; } - private: void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits); diff --git a/xpdf/xpdf/Decrypt.cc b/xpdf/xpdf/Decrypt.cc index f1df89a79..cb53abd1f 100644 --- a/xpdf/xpdf/Decrypt.cc +++ b/xpdf/xpdf/Decrypt.cc @@ -12,6 +12,7 @@ #pragma implementation #endif +#include #include "gmem.h" #include "Decrypt.h" @@ -65,7 +66,8 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, GString *ownerPassword, GString *userPassword, - Guchar *fileKey, GBool *ownerPasswordOk) { + Guchar *fileKey, GBool encryptMetadata, + GBool *ownerPasswordOk) { Guchar test[32], test2[32]; GString *userPassword2; Guchar fState[256]; @@ -110,7 +112,8 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, } userPassword2 = new GString((char *)test2, 32); if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, - permissions, fileID, userPassword2, fileKey)) { + permissions, fileID, userPassword2, fileKey, + encryptMetadata)) { *ownerPasswordOk = gTrue; delete userPassword2; return gTrue; @@ -120,13 +123,15 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, // try using the supplied user password return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, - permissions, fileID, userPassword, fileKey); + permissions, fileID, userPassword, fileKey, + encryptMetadata); } GBool Decrypt::makeFileKey2(int /*encVersion*/, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, - GString *userPassword, Guchar *fileKey) { + GString *userPassword, Guchar *fileKey, + GBool encryptMetadata) { Guchar *buf; Guchar test[32]; Guchar fState[256]; @@ -136,7 +141,7 @@ GBool Decrypt::makeFileKey2(int /*encVersion*/, int encRevision, int keyLength, GBool ok; // generate file key - buf = (Guchar *)gmalloc(68 + fileID->getLength()); + buf = (Guchar *)gmalloc(72 + fileID->getLength()); if (userPassword) { len = userPassword->getLength(); if (len < 32) { @@ -154,7 +159,14 @@ GBool Decrypt::makeFileKey2(int /*encVersion*/, int encRevision, int keyLength, buf[66] = (permissions >> 16) & 0xff; buf[67] = (permissions >> 24) & 0xff; memcpy(buf + 68, fileID->getCString(), fileID->getLength()); - md5(buf, 68 + fileID->getLength(), fileKey); + len = 68 + fileID->getLength(); + if (!encryptMetadata) { + buf[len++] = 0xff; + buf[len++] = 0xff; + buf[len++] = 0xff; + buf[len++] = 0xff; + } + md5(buf, len, fileKey); if (encRevision == 3) { for (i = 0; i < 50; ++i) { md5(fileKey, keyLength, fileKey); diff --git a/xpdf/xpdf/Decrypt.h b/xpdf/xpdf/Decrypt.h index 71f945748..2beba5815 100644 --- a/xpdf/xpdf/Decrypt.h +++ b/xpdf/xpdf/Decrypt.h @@ -43,14 +43,16 @@ public: GString *ownerKey, GString *userKey, int permissions, GString *fileID, GString *ownerPassword, GString *userPassword, - Guchar *fileKey, GBool *ownerPasswordOk); + Guchar *fileKey, GBool encryptMetadata, + GBool *ownerPasswordOk); private: static GBool makeFileKey2(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, - GString *userPassword, Guchar *fileKey); + GString *userPassword, Guchar *fileKey, + GBool encryptMetadata); int objKeyLength; Guchar objKey[21]; diff --git a/xpdf/xpdf/Dict.cc b/xpdf/xpdf/Dict.cc index b46a70d85..f17aca444 100644 --- a/xpdf/xpdf/Dict.cc +++ b/xpdf/xpdf/Dict.cc @@ -47,7 +47,7 @@ void Dict::add(const char *key, Object *val) { } else { size *= 2; } - entries = (DictEntry *)grealloc(entries, size * sizeof(DictEntry)); + entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry)); } entries[length].key = key; entries[length].val = *val; diff --git a/xpdf/xpdf/Function.cc b/xpdf/xpdf/Function.cc index f47174eb9..b1caf39ed 100644 --- a/xpdf/xpdf/Function.cc +++ b/xpdf/xpdf/Function.cc @@ -185,7 +185,7 @@ void IdentityFunction::transform(double *in, double *out) { SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { Stream *str; - int nSamples, sampleBits; + int sampleBits; double sampleMul; Object obj1, obj2; Guint buf, bitMask; @@ -228,6 +228,10 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { obj2.free(); } obj1.free(); + idxMul[0] = n; + for (i = 1; i < m; ++i) { + idxMul[i] = idxMul[i-1] * sampleSize[i-1]; + } //----- BitsPerSample if (!dict->lookup("BitsPerSample", &obj1)->isInt()) { @@ -264,6 +268,10 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { } } obj1.free(); + for (i = 0; i < m; ++i) { + inputMul[i] = (encode[i][1] - encode[i][0]) / + (domain[i][1] - domain[i][0]); + } //----- Decode if (dict->lookup("Decode", &obj1)->isArray() && @@ -296,7 +304,7 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { nSamples = n; for (i = 0; i < m; ++i) nSamples *= sampleSize[i]; - samples = (double *)gmalloc(nSamples * sizeof(double)); + samples = (double *)gmallocn(nSamples, sizeof(double)); buf = 0; bits = 0; bitMask = (1 << sampleBits) - 1; @@ -342,37 +350,34 @@ SampledFunction::~SampledFunction() { } SampledFunction::SampledFunction(SampledFunction *func) { - int nSamples, i; - memcpy(this, func, sizeof(SampledFunction)); - - nSamples = n; - for (i = 0; i < m; ++i) { - nSamples *= sampleSize[i]; - } - samples = (double *)gmalloc(nSamples * sizeof(double)); + samples = (double *)gmallocn(nSamples, sizeof(double)); memcpy(samples, func->samples, nSamples * sizeof(double)); } void SampledFunction::transform(double *in, double *out) { double x; - int e[2][funcMaxInputs]; - double efrac[funcMaxInputs]; - double s0[1 << funcMaxInputs], s1[1 << funcMaxInputs]; - int i, j, k, idx; + int e[funcMaxInputs][2]; + double efrac0[funcMaxInputs]; + double efrac1[funcMaxInputs]; + double s[1 << funcMaxInputs]; + int i, j, k, idx, t; // map input values into sample array for (i = 0; i < m; ++i) { - x = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) * - (encode[i][1] - encode[i][0]) + encode[i][0]; + x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0]; if (x < 0) { x = 0; } else if (x > sampleSize[i] - 1) { x = sampleSize[i] - 1; } - e[0][i] = (int)floor(x); - e[1][i] = (int)ceil(x); - efrac[i] = x - e[0][i]; + e[i][0] = (int)x; + if ((e[i][1] = e[i][0] + 1) >= sampleSize[i]) { + // this happens if in[i] = domain[i][1] + e[i][1] = e[i][0]; + } + efrac1[i] = x - e[i][0]; + efrac0[i] = 1 - efrac1[i]; } // for each output, do m-linear interpolation @@ -380,24 +385,22 @@ void SampledFunction::transform(double *in, double *out) { // pull 2^m values out of the sample array for (j = 0; j < (1<= 0; --k) { - idx = idx * sampleSize[k] + e[(j >> k) & 1][k]; + idx = i; + for (k = 0, t = j; k < m; ++k, t >>= 1) { + idx += idxMul[k] * (e[k][t & 1]); } - idx = idx * n + i; - s0[j] = samples[idx]; + s[j] = samples[idx]; } // do m sets of interpolations - for (j = 0; j < m; ++j) { - for (k = 0; k < (1 << (m - j)); k += 2) { - s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1]; + for (j = 0, t = (1<>= 1) { + for (k = 0; k < t; k += 2) { + s[k >> 1] = efrac0[j] * s[k] + efrac1[j] * s[k+1]; } - memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(double)); } // map output value to range - out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0]; + out[i] = s[0] * (decode[i][1] - decode[i][0]) + decode[i][0]; if (out[i] < range[i][0]) { out[i] = range[i][0]; } else if (out[i] > range[i][1]) { @@ -553,9 +556,9 @@ StitchingFunction::StitchingFunction(Object * /*funcObj*/, Dict *dict) { goto err1; } k = obj1.arrayGetLength(); - funcs = (Function **)gmalloc(k * sizeof(Function *)); - bounds = (double *)gmalloc((k + 1) * sizeof(double)); - encode = (double *)gmalloc(2 * k * sizeof(double)); + funcs = (Function **)gmallocn(k, sizeof(Function *)); + bounds = (double *)gmallocn(k + 1, sizeof(double)); + encode = (double *)gmallocn(2 * k, sizeof(double)); for (i = 0; i < k; ++i) { funcs[i] = NULL; } @@ -619,13 +622,13 @@ StitchingFunction::StitchingFunction(StitchingFunction *func) { int i; k = func->k; - funcs = (Function **)gmalloc(k * sizeof(Function *)); + funcs = (Function **)gmallocn(k, sizeof(Function *)); for (i = 0; i < k; ++i) { funcs[i] = func->funcs[i]->copy(); } - bounds = (double *)gmalloc((k + 1) * sizeof(double)); + bounds = (double *)gmallocn(k + 1, sizeof(double)); memcpy(bounds, func->bounds, (k + 1) * sizeof(double)); - encode = (double *)gmalloc(2 * k * sizeof(double)); + encode = (double *)gmallocn(2 * k, sizeof(double)); memcpy(encode, func->encode, 2 * k * sizeof(double)); ok = gTrue; } @@ -916,10 +919,14 @@ double PSStack::popNum() { void PSStack::copy(int n) { int i; + if (sp + n > psStackSize) { + error(-1, "Stack underflow in PostScript function"); + return; + } if (!checkOverflow(n)) { return; } - for (i = sp + n - 1; i <= sp; ++i) { + for (i = sp + n - 1; i >= sp; --i) { stack[i - n] = stack[i]; } sp -= n; @@ -990,6 +997,7 @@ PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) { str = funcObj->getStream(); //----- parse the function + codeString = new GString(); str->reset(); if (!(tok = getToken(str)) || tok->cmp("{")) { error(-1, "Expected '{' at start of PostScript function"); @@ -1015,12 +1023,14 @@ PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) { PostScriptFunction::PostScriptFunction(PostScriptFunction *func) { memcpy(this, func, sizeof(PostScriptFunction)); - code = (PSObject *)gmalloc(codeSize * sizeof(PSObject)); + code = (PSObject *)gmallocn(codeSize, sizeof(PSObject)); memcpy(code, func->code, codeSize * sizeof(PSObject)); + codeString = func->codeString->copy(); } PostScriptFunction::~PostScriptFunction() { gfree(code); + delete codeString; } void PostScriptFunction::transform(double *in, double *out) { @@ -1174,6 +1184,9 @@ GString *PostScriptFunction::getToken(Stream *str) { s = new GString(); do { c = str->getChar(); + if (c != EOF) { + codeString->append(c); + } } while (c != EOF && isspace(c)); if (c == '{' || c == '}') { s->append((char)c); @@ -1185,6 +1198,7 @@ GString *PostScriptFunction::getToken(Stream *str) { break; } str->getChar(); + codeString->append(c); } } else { while (1) { @@ -1194,6 +1208,7 @@ GString *PostScriptFunction::getToken(Stream *str) { break; } str->getChar(); + codeString->append(c); } } return s; @@ -1202,7 +1217,7 @@ GString *PostScriptFunction::getToken(Stream *str) { void PostScriptFunction::resizeCode(int newSize) { if (newSize >= codeSize) { codeSize += 64; - code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject)); + code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject)); } } diff --git a/xpdf/xpdf/Function.h b/xpdf/xpdf/Function.h index 0ceb03515..bfaf83e30 100644 --- a/xpdf/xpdf/Function.h +++ b/xpdf/xpdf/Function.h @@ -45,10 +45,24 @@ public: virtual Function *copy() = 0; + // Return the function type: + // -1 : identity + // 0 : sampled + // 2 : exponential + // 3 : stitching + // 4 : PostScript + virtual int getType() = 0; + // Return size of input and output tuples. int getInputSize() { return m; } int getOutputSize() { return n; } + double getDomainMin(int i) { return domain[i][0]; } + double getDomainMax(int i) { return domain[i][1]; } + double getRangeMin(int i) { return range[i][0]; } + double getRangeMax(int i) { return range[i][1]; } + GBool getHasRange() { return hasRange; } + // Transform an input tuple into an output tuple. virtual void transform(double *in, double *out) = 0; @@ -74,6 +88,7 @@ public: IdentityFunction(); virtual ~IdentityFunction(); virtual Function *copy() { return new IdentityFunction(); } + virtual int getType() { return -1; } virtual void transform(double *in, double *out); virtual GBool isOk() { return gTrue; } @@ -90,9 +105,17 @@ public: SampledFunction(Object *funcObj, Dict *dict); virtual ~SampledFunction(); virtual Function *copy() { return new SampledFunction(this); } + virtual int getType() { return 0; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } + int getSampleSize(int i) { return sampleSize[i]; } + double getEncodeMin(int i) { return encode[i][0]; } + double getEncodeMax(int i) { return encode[i][1]; } + double getDecodeMin(int i) { return decode[i][0]; } + double getDecodeMax(int i) { return decode[i][1]; } + double *getSamples() { return samples; } + private: SampledFunction(SampledFunction *func); @@ -103,7 +126,11 @@ private: encode[funcMaxInputs][2]; double // min and max values for range decoder decode[funcMaxOutputs][2]; + double // input multipliers + inputMul[funcMaxInputs]; + int idxMul[funcMaxInputs]; // sample array index multipliers double *samples; // the samples + int nSamples; // size of the samples array GBool ok; }; @@ -117,9 +144,14 @@ public: ExponentialFunction(Object *funcObj, Dict *dict); virtual ~ExponentialFunction(); virtual Function *copy() { return new ExponentialFunction(this); } + virtual int getType() { return 2; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } + double *getC0() { return c0; } + double *getC1() { return c1; } + double getE() { return e; } + private: ExponentialFunction(ExponentialFunction *func); @@ -140,9 +172,15 @@ public: StitchingFunction(Object *funcObj, Dict *dict); virtual ~StitchingFunction(); virtual Function *copy() { return new StitchingFunction(this); } + virtual int getType() { return 3; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } + int getNumFuncs() { return k; } + Function *getFunc(int i) { return funcs[i]; } + double *getBounds() { return bounds; } + double *getEncode() { return encode; } + private: StitchingFunction(StitchingFunction *func); @@ -164,9 +202,12 @@ public: PostScriptFunction(Object *funcObj, Dict *dict); virtual ~PostScriptFunction(); virtual Function *copy() { return new PostScriptFunction(this); } + virtual int getType() { return 4; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } + GString *getCodeString() { return codeString; } + private: PostScriptFunction(PostScriptFunction *func); @@ -175,6 +216,7 @@ private: void resizeCode(int newSize); void exec(PSStack *stack, int codePtr); + GString *codeString; PSObject *code; int codeSize; GBool ok; diff --git a/xpdf/xpdf/Gfx.cc b/xpdf/xpdf/Gfx.cc index eafcf4495..c2235331d 100644 --- a/xpdf/xpdf/Gfx.cc +++ b/xpdf/xpdf/Gfx.cc @@ -12,6 +12,7 @@ #pragma implementation #endif +#include #include #include #include @@ -45,19 +46,33 @@ #define functionMaxDepth 6 // Max delta allowed in any color component for a function shading fill. -#define functionColorDelta (1 / 256.0) +#define functionColorDelta (dblToCol(1 / 256.0)) // Max number of splits along the t axis for an axial shading fill. #define axialMaxSplits 256 // Max delta allowed in any color component for an axial shading fill. -#define axialColorDelta (1 / 256.0) +#define axialColorDelta (dblToCol(1 / 256.0)) // Max number of splits along the t axis for a radial shading fill. #define radialMaxSplits 256 // Max delta allowed in any color component for a radial shading fill. -#define radialColorDelta (1 / 256.0) +#define radialColorDelta (dblToCol(1 / 256.0)) + +// Max recursive depth for a Gouraud triangle shading fill. +#define gouraudMaxDepth 4 + +// Max delta allowed in any color component for a Gouraud triangle +// shading fill. +#define gouraudColorDelta (dblToCol(1 / 256.0)) + +// Max recursive depth for a patch mesh shading fill. +#define patchMaxDepth 6 + +// Max delta allowed in any color component for a patch mesh shading +// fill. +#define patchColorDelta (dblToCol(1 / 256.0)) //------------------------------------------------------------------------ // Operator table @@ -405,7 +420,7 @@ GBool GfxResources::lookupGState(const char *name, Object *obj) { //------------------------------------------------------------------------ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, - double hDPI, double vDPI, PDFRectangle *box, GBool crop, + double hDPI, double vDPI, PDFRectangle *box, PDFRectangle *cropBox, int rotate, GBool (*abortCheckCbkA)(void *data), void *abortCheckCbkDataA) { @@ -435,7 +450,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, abortCheckCbkData = abortCheckCbkDataA; // set crop box - if (crop) { + if (cropBox) { state->moveTo(cropBox->x1, cropBox->y1); state->lineTo(cropBox->x2, cropBox->y1); state->lineTo(cropBox->x2, cropBox->y2); @@ -448,7 +463,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, } Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, - PDFRectangle *box, GBool crop, PDFRectangle *cropBox, + PDFRectangle *box, PDFRectangle *cropBox, GBool (*abortCheckCbkA)(void *data), void *abortCheckCbkDataA) { int i; @@ -474,7 +489,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, abortCheckCbkData = abortCheckCbkDataA; // set crop box - if (crop) { + if (cropBox) { state->moveTo(cropBox->x1, cropBox->y1); state->lineTo(cropBox->x2, cropBox->y1); state->lineTo(cropBox->x2, cropBox->y2); @@ -734,7 +749,7 @@ void Gfx::opSetDash(Object args[], int /*numArgs*/) { if (length == 0) { dash = NULL; } else { - dash = (double *)gmalloc(length * sizeof(double)); + dash = (double *)gmallocn(length, sizeof(double)); for (i = 0; i < length; ++i) { dash[i] = a->get(i, &obj)->getNum(); obj.free(); @@ -771,6 +786,8 @@ void Gfx::opSetLineWidth(Object args[], int /*numArgs*/) { void Gfx::opSetExtGState(Object args[], int /*numArgs*/) { Object obj1, obj2; + GfxBlendMode mode; + GBool haveFillOP; if (!res->lookupGState(args[0].getName(), &obj1)) { return; @@ -780,6 +797,17 @@ void Gfx::opSetExtGState(Object args[], int /*numArgs*/) { obj1.free(); return; } + + // transparency support: blend mode, fill/stroke opacity + if (!obj1.dictLookup("BM", &obj2)->isNull()) { + if (state->parseBlendMode(&obj2, &mode)) { + state->setBlendMode(mode); + out->updateBlendMode(state); + } else { + error(getPos(), "Invalid blend mode in ExtGState"); + } + } + obj2.free(); if (obj1.dictLookup("ca", &obj2)->isNum()) { state->setFillOpacity(obj2.getNum()); out->updateFillOpacity(state); @@ -790,10 +818,27 @@ void Gfx::opSetExtGState(Object args[], int /*numArgs*/) { out->updateStrokeOpacity(state); } obj2.free(); + + // fill/stroke overprint + if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) { + state->setFillOverprint(obj2.getBool()); + out->updateFillOverprint(state); + } + obj2.free(); + if (obj1.dictLookup("OP", &obj2)->isBool()) { + state->setStrokeOverprint(obj2.getBool()); + out->updateStrokeOverprint(state); + if (!haveFillOP) { + state->setFillOverprint(obj2.getBool()); + out->updateFillOverprint(state); + } + } + obj2.free(); + obj1.free(); } -void Gfx::opSetRenderingIntent(Object * /*args*/, int /*numArgs*/) { +void Gfx::opSetRenderingIntent(Object */*args*/, int /*numArgs*/) { } //------------------------------------------------------------------------ @@ -805,7 +850,8 @@ void Gfx::opSetFillGray(Object args[], int /*numArgs*/) { state->setFillPattern(NULL); state->setFillColorSpace(new GfxDeviceGrayColorSpace()); - color.c[0] = args[0].getNum(); + out->updateFillColorSpace(state); + color.c[0] = dblToCol(args[0].getNum()); state->setFillColor(&color); out->updateFillColor(state); } @@ -815,7 +861,8 @@ void Gfx::opSetStrokeGray(Object args[], int /*numArgs*/) { state->setStrokePattern(NULL); state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); - color.c[0] = args[0].getNum(); + out->updateStrokeColorSpace(state); + color.c[0] = dblToCol(args[0].getNum()); state->setStrokeColor(&color); out->updateStrokeColor(state); } @@ -826,8 +873,9 @@ void Gfx::opSetFillCMYKColor(Object args[], int /*numArgs*/) { state->setFillPattern(NULL); state->setFillColorSpace(new GfxDeviceCMYKColorSpace()); + out->updateFillColorSpace(state); for (i = 0; i < 4; ++i) { - color.c[i] = args[i].getNum(); + color.c[i] = dblToCol(args[i].getNum()); } state->setFillColor(&color); out->updateFillColor(state); @@ -839,8 +887,9 @@ void Gfx::opSetStrokeCMYKColor(Object args[], int /*numArgs*/) { state->setStrokePattern(NULL); state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace()); + out->updateStrokeColorSpace(state); for (i = 0; i < 4; ++i) { - color.c[i] = args[i].getNum(); + color.c[i] = dblToCol(args[i].getNum()); } state->setStrokeColor(&color); out->updateStrokeColor(state); @@ -852,8 +901,9 @@ void Gfx::opSetFillRGBColor(Object args[], int /*numArgs*/) { state->setFillPattern(NULL); state->setFillColorSpace(new GfxDeviceRGBColorSpace()); + out->updateFillColorSpace(state); for (i = 0; i < 3; ++i) { - color.c[i] = args[i].getNum(); + color.c[i] = dblToCol(args[i].getNum()); } state->setFillColor(&color); out->updateFillColor(state); @@ -865,8 +915,9 @@ void Gfx::opSetStrokeRGBColor(Object args[], int /*numArgs*/) { state->setStrokePattern(NULL); state->setStrokeColorSpace(new GfxDeviceRGBColorSpace()); + out->updateStrokeColorSpace(state); for (i = 0; i < 3; ++i) { - color.c[i] = args[i].getNum(); + color.c[i] = dblToCol(args[i].getNum()); } state->setStrokeColor(&color); out->updateStrokeColor(state); @@ -888,6 +939,7 @@ void Gfx::opSetFillColorSpace(Object args[], int /*numArgs*/) { obj.free(); if (colorSpace) { state->setFillColorSpace(colorSpace); + out->updateFillColorSpace(state); } else { error(getPos(), "Bad color space (fill)"); } @@ -914,6 +966,7 @@ void Gfx::opSetStrokeColorSpace(Object args[], int /*numArgs*/) { obj.free(); if (colorSpace) { state->setStrokeColorSpace(colorSpace); + out->updateStrokeColorSpace(state); } else { error(getPos(), "Bad color space (stroke)"); } @@ -930,7 +983,7 @@ void Gfx::opSetFillColor(Object args[], int numArgs) { state->setFillPattern(NULL); for (i = 0; i < numArgs; ++i) { - color.c[i] = args[i].getNum(); + color.c[i] = dblToCol(args[i].getNum()); } state->setFillColor(&color); out->updateFillColor(state); @@ -942,7 +995,7 @@ void Gfx::opSetStrokeColor(Object args[], int numArgs) { state->setStrokePattern(NULL); for (i = 0; i < numArgs; ++i) { - color.c[i] = args[i].getNum(); + color.c[i] = dblToCol(args[i].getNum()); } state->setStrokeColor(&color); out->updateStrokeColor(state); @@ -957,7 +1010,7 @@ void Gfx::opSetFillColorN(Object args[], int numArgs) { if (numArgs > 1) { for (i = 0; i < numArgs && i < 4; ++i) { if (args[i].isNum()) { - color.c[i] = args[i].getNum(); + color.c[i] = dblToCol(args[i].getNum()); } } state->setFillColor(&color); @@ -972,7 +1025,7 @@ void Gfx::opSetFillColorN(Object args[], int numArgs) { state->setFillPattern(NULL); for (i = 0; i < numArgs && i < 4; ++i) { if (args[i].isNum()) { - color.c[i] = args[i].getNum(); + color.c[i] = dblToCol(args[i].getNum()); } } state->setFillColor(&color); @@ -989,7 +1042,7 @@ void Gfx::opSetStrokeColorN(Object args[], int numArgs) { if (numArgs > 1) { for (i = 0; i < numArgs && i < 4; ++i) { if (args[i].isNum()) { - color.c[i] = args[i].getNum(); + color.c[i] = dblToCol(args[i].getNum()); } } state->setStrokeColor(&color); @@ -1004,7 +1057,7 @@ void Gfx::opSetStrokeColorN(Object args[], int numArgs) { state->setStrokePattern(NULL); for (i = 0; i < numArgs && i < 4; ++i) { if (args[i].isNum()) { - color.c[i] = args[i].getNum(); + color.c[i] = dblToCol(args[i].getNum()); } } state->setStrokeColor(&color); @@ -1090,7 +1143,7 @@ void Gfx::opRectangle(Object args[], int /*numArgs*/) { state->closePath(); } -void Gfx::opClosePath(Object * /*args*/, int /*numArgs*/) { +void Gfx::opClosePath(Object */*args*/, int /*numArgs*/) { if (!state->isCurPt()) { error(getPos(), "No current point in closepath"); return; @@ -1102,11 +1155,11 @@ void Gfx::opClosePath(Object * /*args*/, int /*numArgs*/) { // path painting operators //------------------------------------------------------------------------ -void Gfx::opEndPath(Object * /*args*/, int /*numArgs*/) { +void Gfx::opEndPath(Object */*args*/, int /*numArgs*/) { doEndPath(); } -void Gfx::opStroke(Object * /*args*/, int /*numArgs*/) { +void Gfx::opStroke(Object */*args*/, int /*numArgs*/) { if (!state->isCurPt()) { //error(getPos(), "No path in stroke"); return; @@ -1116,7 +1169,7 @@ void Gfx::opStroke(Object * /*args*/, int /*numArgs*/) { doEndPath(); } -void Gfx::opCloseStroke(Object * /*args*/, int /*numArgs*/) { +void Gfx::opCloseStroke(Object */*args*/, int /*numArgs*/) { if (!state->isCurPt()) { //error(getPos(), "No path in closepath/stroke"); return; @@ -1128,7 +1181,7 @@ void Gfx::opCloseStroke(Object * /*args*/, int /*numArgs*/) { doEndPath(); } -void Gfx::opFill(Object * /*args*/, int /*numArgs*/) { +void Gfx::opFill(Object */*args*/, int /*numArgs*/) { if (!state->isCurPt()) { //error(getPos(), "No path in fill"); return; @@ -1143,7 +1196,7 @@ void Gfx::opFill(Object * /*args*/, int /*numArgs*/) { doEndPath(); } -void Gfx::opEOFill(Object * /*args*/, int /*numArgs*/) { +void Gfx::opEOFill(Object */*args*/, int /*numArgs*/) { if (!state->isCurPt()) { //error(getPos(), "No path in eofill"); return; @@ -1158,7 +1211,7 @@ void Gfx::opEOFill(Object * /*args*/, int /*numArgs*/) { doEndPath(); } -void Gfx::opFillStroke(Object * /*args*/, int /*numArgs*/) { +void Gfx::opFillStroke(Object */*args*/, int /*numArgs*/) { if (!state->isCurPt()) { //error(getPos(), "No path in fill/stroke"); return; @@ -1174,7 +1227,7 @@ void Gfx::opFillStroke(Object * /*args*/, int /*numArgs*/) { doEndPath(); } -void Gfx::opCloseFillStroke(Object * /*args*/, int /*numArgs*/) { +void Gfx::opCloseFillStroke(Object */*args*/, int /*numArgs*/) { if (!state->isCurPt()) { //error(getPos(), "No path in closepath/fill/stroke"); return; @@ -1191,7 +1244,7 @@ void Gfx::opCloseFillStroke(Object * /*args*/, int /*numArgs*/) { doEndPath(); } -void Gfx::opEOFillStroke(Object * /*args*/, int /*numArgs*/) { +void Gfx::opEOFillStroke(Object */*args*/, int /*numArgs*/) { if (!state->isCurPt()) { //error(getPos(), "No path in eofill/stroke"); return; @@ -1207,7 +1260,7 @@ void Gfx::opEOFillStroke(Object * /*args*/, int /*numArgs*/) { doEndPath(); } -void Gfx::opCloseEOFillStroke(Object * /*args*/, int /*numArgs*/) { +void Gfx::opCloseEOFillStroke(Object */*args*/, int /*numArgs*/) { if (!state->isCurPt()) { //error(getPos(), "No path in closepath/eofill/stroke"); return; @@ -1294,7 +1347,7 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; - // construct a (base space) -> (pattern space) transform matrix + // construct a (device space) -> (pattern space) transform matrix det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]); imb[0] = m1[3] * det; imb[1] = -m1[1] * det; @@ -1312,11 +1365,15 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { // Adobe's behavior if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) { state->setFillColorSpace(cs->copy()); + out->updateFillColorSpace(state); state->setStrokeColorSpace(cs->copy()); + out->updateStrokeColorSpace(state); state->setStrokeColor(state->getFillColor()); } else { state->setFillColorSpace(new GfxDeviceGrayColorSpace()); + out->updateFillColorSpace(state); state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); + out->updateStrokeColorSpace(state); } state->setFillPattern(NULL); out->updateFillColor(state); @@ -1334,8 +1391,13 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { } state->clearPath(); - // transform clip region bbox to pattern space + // get the clip region, check for empty state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax); + if (cxMin > cxMax || cyMin > cyMax) { + goto err; + } + + // transform clip region bbox to pattern space xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4]; yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5]; x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4]; @@ -1387,6 +1449,14 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { for (i = 0; i < 4; ++i) { m1[i] = m[i]; } + if (out->useTilingPatternFill()) { + m1[4] = m[4]; + m1[5] = m[5]; + out->tilingPatternFill(state, tPat->getContentStream(), + tPat->getPaintType(), tPat->getResDict(), + m1, tPat->getBBox(), + xi0, yi0, xi1, yi1, xstep, ystep); + } else { for (yi = yi0; yi < yi1; ++yi) { for (xi = xi0; xi < xi1; ++xi) { x = xi * xstep; @@ -1397,8 +1467,10 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { m1, tPat->getBBox()); } } + } // restore graphics state + err: restoreState(); state->setPath(savedPath); } @@ -1427,7 +1499,7 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) { state->closePath(); state->clip(); out->clip(state); - state->clearPath(); + state->setPath(savedPath->copy()); } // clip to current path @@ -1437,6 +1509,17 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) { } else { out->clip(state); } + + // set the color space + state->setFillColorSpace(shading->getColorSpace()->copy()); + out->updateFillColorSpace(state); + + // background color fill + if (shading->getHasBackground()) { + state->setFillColor(shading->getBackground()); + out->updateFillColor(state); + out->fill(state); + } state->clearPath(); // construct a (pattern space) -> (current space) transform matrix @@ -1470,9 +1553,6 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) { state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]); out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]); - // set the color space - state->setFillColorSpace(shading->getColorSpace()->copy()); - // do shading type-specific operations switch (shading->getType()) { case 1: @@ -1484,6 +1564,14 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) { case 3: doRadialShFill((GfxRadialShading *)shading); break; + case 4: + case 5: + doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading); + break; + case 6: + case 7: + doPatchMeshShFill((GfxPatchMeshShading *)shading); + break; } // restore graphics state @@ -1519,6 +1607,7 @@ void Gfx::opShFill(Object args[], int /*numArgs*/) { // set the color space state->setFillColorSpace(shading->getColorSpace()->copy()); + out->updateFillColorSpace(state); // do shading type-specific operations switch (shading->getType()) { @@ -1531,6 +1620,14 @@ void Gfx::opShFill(Object args[], int /*numArgs*/) { case 3: doRadialShFill((GfxRadialShading *)shading); break; + case 4: + case 5: + doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading); + break; + case 6: + case 7: + doPatchMeshShFill((GfxPatchMeshShading *)shading); + break; } // restore graphics state @@ -1544,12 +1641,16 @@ void Gfx::doFunctionShFill(GfxFunctionShading *shading) { double x0, y0, x1, y1; GfxColor colors[4]; + if (out->useShadedFills()) { + out->functionShadedFill(state, shading); + } else { shading->getDomain(&x0, &y0, &x1, &y1); shading->getColor(x0, y0, &colors[0]); shading->getColor(x0, y1, &colors[1]); shading->getColor(x1, y0, &colors[2]); shading->getColor(x1, y1, &colors[3]); doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0); + } } void Gfx::doFunctionShFill1(GfxFunctionShading *shading, @@ -1569,7 +1670,7 @@ void Gfx::doFunctionShFill1(GfxFunctionShading *shading, // compare the four corner colors for (i = 0; i < 4; ++i) { for (j = 0; j < nComps; ++j) { - if (fabs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) { + if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) { break; } } @@ -1664,6 +1765,7 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { double xMin, yMin, xMax, yMax; double x0, y0, x1, y1; double dx, dy, mul; + GBool dxZero, dyZero; double tMin, tMax, t, tx, ty; double s[4], sMin, sMax, tmp; double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1; @@ -1674,6 +1776,12 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { int nComps; int i, j, k, kk; + if (out->useShadedFills()) { + + out->axialShadedFill(state, shading); + + } else { + // get the clip region bbox state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); @@ -1682,6 +1790,8 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { shading->getCoords(&x0, &y0, &x1, &y1); dx = x1 - x0; dy = y1 - y0; + dxZero = fabs(dx) < 0.001; + dyZero = fabs(dy) < 0.001; mul = 1 / (dx * dx + dy * dy); tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; @@ -1766,13 +1876,13 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { // bounding box tx = x0 + tMin * dx; ty = y0 + tMin * dy; - if (dx == 0 && dy == 0) { + if (dxZero && dyZero) { sMin = sMax = 0; - } if (dx == 0) { + } if (dxZero) { sMin = (xMin - tx) / -dy; sMax = (xMax - tx) / -dy; if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } - } else if (dy == 0) { + } else if (dyZero) { sMin = (yMin - ty) / dx; sMax = (yMax - ty) / dx; if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } @@ -1814,7 +1924,7 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { } shading->getColor(tt, &color1); for (k = 0; k < nComps; ++k) { - if (fabs(color1.c[k] - color0.c[k]) > axialColorDelta) { + if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) { break; } } @@ -1830,7 +1940,7 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { // use the average of the colors of the two sides of the region for (k = 0; k < nComps; ++k) { - color0.c[k] = 0.5 * (color0.c[k] + color1.c[k]); + color0.c[k] = (color0.c[k] + color1.c[k]) / 2; } // compute the coordinates of the point on the t axis; then @@ -1838,13 +1948,13 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { // bounding box tx = x0 + ta[j] * dx; ty = y0 + ta[j] * dy; - if (dx == 0 && dy == 0) { + if (dxZero && dyZero) { sMin = sMax = 0; - } if (dx == 0) { + } if (dxZero) { sMin = (xMin - tx) / -dy; sMax = (xMax - tx) / -dy; if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } - } else if (dy == 0) { + } else if (dyZero) { sMin = (yMin - ty) / dx; sMax = (yMax - ty) / dx; if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } @@ -1891,6 +2001,7 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { color0 = color1; i = next[i]; } + } } void Gfx::doRadialShFill(GfxRadialShading *shading) { @@ -1902,7 +2013,13 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { double ta, tb, sa, sb; int ia, ib, k, n; double *ctm; - double angle, t; + double angle, t, d0, d1; + + if (out->useShadedFills()) { + + out->radialShadedFill(state, shading); + + } else { // get the shading info shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); @@ -1919,13 +2036,14 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { sMin = -r0 / (r1 - r0); } else { // extend the larger end - //~ this computes the diagonal of the bounding box -- we should - //~ really compute the intersection of the moving/expanding - //~ circles with each of the four corners and look for the max - //~ radius state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - sMin = (sqrt((xMax - xMin) * (xMax - xMin) + - (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0); + d0 = (x0 - xMin) * (x0 - xMin); + d1 = (x0 - xMax) * (x0 - xMax); + sMin = d0 > d1 ? d0 : d1; + d0 = (y0 - yMin) * (y0 - yMin); + d1 = (y0 - yMax) * (y0 - yMax); + sMin += d0 > d1 ? d0 : d1; + sMin = (sqrt(sMin) - r0) / (r1 - r0); if (sMin > 0) { sMin = 0; } else if (sMin < -20) { @@ -1941,10 +2059,15 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { } else if (r1 > r0) { // extend the larger end state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - sMax = (sqrt((xMax - xMin) * (xMax - xMin) + - (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0); + d0 = (x1 - xMin) * (x1 - xMin); + d1 = (x1 - xMax) * (x1 - xMax); + sMax = d0 > d1 ? d0 : d1; + d0 = (y1 - yMin) * (y1 - yMin); + d1 = (y1 - yMax) * (y1 - yMax); + sMax += d0 > d1 ? d0 : d1; + sMax = (sqrt(sMax) - r0) / (r1 - r0); if (sMax < 1) { - sMin = 1; + sMax = 1; } else if (sMax > 20) { // sanity check sMax = 20; @@ -2029,7 +2152,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { } while (ib - ia > 1) { for (k = 0; k < nComps; ++k) { - if (fabs(colorB.c[k] - colorA.c[k]) > radialColorDelta) { + if (abs(colorB.c[k] - colorA.c[k]) > radialColorDelta) { break; } } @@ -2055,7 +2178,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { // use the average of the colors at the two circles for (k = 0; k < nComps; ++k) { - colorA.c[k] = 0.5 * (colorA.c[k] + colorB.c[k]); + colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2; } state->setFillColor(&colorA); out->updateFillColor(state); @@ -2089,6 +2212,215 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { ra = rb; colorA = colorB; } + } +} + +void Gfx::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 Gfx::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; + 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 == gouraudMaxDepth) { + state->setFillColor(color0); + out->updateFillColor(state); + state->moveTo(x0, y0); + state->lineTo(x1, y1); + state->lineTo(x2, y2); + state->closePath(); + out->fill(state); + 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 Gfx::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 Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) { + GfxPatch patch00, patch01, patch10, patch11; + double xx[4][8], yy[4][8]; + double xxm, yym; + 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; + } + } + if (i == nComps || depth == patchMaxDepth) { + state->setFillColor(&patch->color[0][0]); + out->updateFillColor(state); + 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(); + out->fill(state); + 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 Gfx::doEndPath() { @@ -2108,11 +2440,11 @@ void Gfx::doEndPath() { // path clipping operators //------------------------------------------------------------------------ -void Gfx::opClip(Object * /*args*/, int /*numArgs*/) { +void Gfx::opClip(Object */*args*/, int /*numArgs*/) { clip = clipNormal; } -void Gfx::opEOClip(Object * /*args*/, int /*numArgs*/) { +void Gfx::opEOClip(Object */*args*/, int /*numArgs*/) { clip = clipEO; } @@ -2120,7 +2452,7 @@ void Gfx::opEOClip(Object * /*args*/, int /*numArgs*/) { // text object operators //------------------------------------------------------------------------ -void Gfx::opBeginText(Object * /*args*/, int /*numArgs*/) { +void Gfx::opBeginText(Object */*args*/, int /*numArgs*/) { state->setTextMat(1, 0, 0, 1, 0, 0); state->textMoveTo(0, 0); out->updateTextMat(state); @@ -2128,7 +2460,7 @@ void Gfx::opBeginText(Object * /*args*/, int /*numArgs*/) { fontChanged = gTrue; } -void Gfx::opEndText(Object * /*args*/, int /*numArgs*/) { +void Gfx::opEndText(Object */*args*/, int /*numArgs*/) { out->endTextObject(state); } @@ -2150,7 +2482,7 @@ void Gfx::opSetFont(Object args[], int /*numArgs*/) { if (printCommands) { printf(" font: tag=%s name='%s' %g\n", font->getTag()->getCString(), - font->getName() ? font->getName()->getCString() : "\?\?\?", + font->getName() ? font->getName()->getCString() : "???", args[1].getNum()); fflush(stdout); } @@ -2217,7 +2549,7 @@ void Gfx::opSetTextMatrix(Object args[], int /*numArgs*/) { fontChanged = gTrue; } -void Gfx::opTextNextLine(Object * /*args*/, int /*numArgs*/) { +void Gfx::opTextNextLine(Object */*args*/, int /*numArgs*/) { double tx, ty; tx = state->getLineX(); @@ -2235,7 +2567,13 @@ void Gfx::opShowText(Object args[], int /*numArgs*/) { error(getPos(), "No font in show"); return; } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } + out->beginStringOp(state); doShowText(args[0].getString()); + out->endStringOp(state); } void Gfx::opMoveShowText(Object args[], int /*numArgs*/) { @@ -2245,11 +2583,17 @@ void Gfx::opMoveShowText(Object args[], int /*numArgs*/) { error(getPos(), "No font in move/show"); return; } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } tx = state->getLineX(); ty = state->getLineY() - state->getLeading(); state->textMoveTo(tx, ty); out->updateTextPos(state); + out->beginStringOp(state); doShowText(args[0].getString()); + out->endStringOp(state); } void Gfx::opMoveSetShowText(Object args[], int /*numArgs*/) { @@ -2259,6 +2603,10 @@ void Gfx::opMoveSetShowText(Object args[], int /*numArgs*/) { error(getPos(), "No font in move/set/show"); return; } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } state->setWordSpace(args[0].getNum()); state->setCharSpace(args[1].getNum()); tx = state->getLineX(); @@ -2267,7 +2615,9 @@ void Gfx::opMoveSetShowText(Object args[], int /*numArgs*/) { out->updateWordSpace(state); out->updateCharSpace(state); out->updateTextPos(state); + out->beginStringOp(state); doShowText(args[2].getString()); + out->endStringOp(state); } void Gfx::opShowSpaceText(Object args[], int /*numArgs*/) { @@ -2280,15 +2630,24 @@ void Gfx::opShowSpaceText(Object args[], int /*numArgs*/) { error(getPos(), "No font in show/space"); return; } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } + out->beginStringOp(state); wMode = state->getFont()->getWMode(); a = args[0].getArray(); for (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 * state->getFontSize()); + state->textShift(0, -obj.getNum() * 0.001 * + fabs(state->getFontSize())); } else { - state->textShift(-obj.getNum() * 0.001 * state->getFontSize(), 0); + state->textShift(-obj.getNum() * 0.001 * + fabs(state->getFontSize()), 0); } out->updateTextShift(state, obj.getNum()); } else if (obj.isString()) { @@ -2298,6 +2657,7 @@ void Gfx::opShowSpaceText(Object args[], int /*numArgs*/) { } obj.free(); } + out->endStringOp(state); } void Gfx::doShowText(GString *s) { @@ -2316,10 +2676,6 @@ void Gfx::doShowText(GString *s) { char *p; int len, n, uLen, nChars, nSpaces, i; - if (fontChanged) { - out->updateFont(state); - fontChanged = gFalse; - } font = state->getFont(); wMode = font->getWMode(); @@ -2371,7 +2727,7 @@ void Gfx::doShowText(GString *s) { state->transform(curX + riseX, curY + riseY, &x, &y); saveState(); state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); - //~ out->updateCTM(\?\?\?) + //~ out->updateCTM(???) if (!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy, code, u, uLen)) { ((Gfx8BitFont *)font)->getCharProc(code, &charProc); @@ -2428,7 +2784,7 @@ void Gfx::doShowText(GString *s) { originY *= state->getFontSize(); state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY, - tdx, tdy, tOriginX, tOriginY, code, u, uLen); + tdx, tdy, tOriginX, tOriginY, code, n, u, uLen); state->shift(tdx, tdy); p += n; len -= n; @@ -2502,9 +2858,11 @@ void Gfx::opXObject(Object args[], int /*numArgs*/) { #endif obj1.streamGetDict()->lookup("Subtype", &obj2); if (obj2.isName("Image")) { + if (out->needNonText()) { res->lookupXObjectNF(args[0].getName(), &refObj); doImage(&refObj, obj1.getStream(), gFalse); refObj.free(); + } } else if (obj2.isName("Form")) { doForm(&obj1); } else if (obj2.isName("PS")) { @@ -2527,19 +2885,28 @@ void Gfx::opXObject(Object args[], int /*numArgs*/) { } void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { - Dict *dict; + Dict *dict, *maskDict; int width, height; - int bits; + int bits, maskBits; + StreamColorSpaceMode csMode; GBool mask; GBool invert; - GfxColorSpace *colorSpace; - GfxImageColorMap *colorMap; - Object maskObj; - GBool haveMask; + GfxColorSpace *colorSpace, *maskColorSpace; + GfxImageColorMap *colorMap, *maskColorMap; + Object maskObj, smaskObj; + GBool haveColorKeyMask, haveExplicitMask, haveSoftMask; int maskColors[2*gfxColorMaxComps]; + int maskWidth, maskHeight; + GBool maskInvert; + Stream *maskStr; Object obj1, obj2; int i; + // get info from the stream + bits = 0; + csMode = streamCSNone; + str->getImageParams(&bits, &csMode); + // get stream dict dict = str->getDict(); @@ -2577,6 +2944,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { obj1.free(); // bit depth + if (bits == 0) { dict->lookup("BitsPerComponent", &obj1); if (obj1.isNull()) { obj1.free(); @@ -2590,6 +2958,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { goto err2; } obj1.free(); + } // display a mask if (mask) { @@ -2633,7 +3002,17 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { obj2.free(); } } + if (!obj1.isNull()) { colorSpace = GfxColorSpace::parse(&obj1); + } 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; @@ -2651,9 +3030,84 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { } // get the mask - haveMask = gFalse; + haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse; + maskStr = NULL; // make gcc happy + maskWidth = maskHeight = 0; // make gcc happy + maskInvert = gFalse; // make gcc happy + maskColorMap = NULL; // make gcc happy dict->lookup("Mask", &maskObj); - if (maskObj.isArray()) { + dict->lookup("SMask", &smaskObj); + if (smaskObj.isStream()) { + // soft mask + if (inlineImg) { + goto err1; + } + maskStr = smaskObj.getStream(); + maskDict = smaskObj.streamGetDict(); + maskDict->lookup("Width", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("W", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskWidth = obj1.getInt(); + obj1.free(); + maskDict->lookup("Height", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("H", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskHeight = obj1.getInt(); + obj1.free(); + maskDict->lookup("BitsPerComponent", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("BPC", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskBits = obj1.getInt(); + obj1.free(); + maskDict->lookup("ColorSpace", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("CS", &obj1); + } + if (obj1.isName()) { + res->lookupColorSpace(obj1.getName(), &obj2); + if (!obj2.isNull()) { + obj1.free(); + obj1 = obj2; + } else { + obj2.free(); + } + } + maskColorSpace = GfxColorSpace::parse(&obj1); + obj1.free(); + if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) { + goto err1; + } + maskDict->lookup("Decode", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("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 for (i = 0; i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps; ++i) { @@ -2661,15 +3115,78 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { maskColors[i] = obj1.getInt(); obj1.free(); } - haveMask = gTrue; + haveColorKeyMask = gTrue; + } else if (maskObj.isStream()) { + // explicit mask + if (inlineImg) { + goto err1; + } + maskStr = maskObj.getStream(); + maskDict = maskObj.streamGetDict(); + maskDict->lookup("Width", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("W", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskWidth = obj1.getInt(); + obj1.free(); + maskDict->lookup("Height", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("H", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskHeight = obj1.getInt(); + obj1.free(); + maskDict->lookup("ImageMask", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("IM", &obj1); + } + if (!obj1.isBool() || !obj1.getBool()) { + goto err2; + } + obj1.free(); + maskInvert = gFalse; + maskDict->lookup("Decode", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("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) { + out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, + maskStr, maskWidth, maskHeight, maskColorMap); + delete maskColorMap; + } else if (haveExplicitMask) { + out->drawMaskedImage(state, ref, str, width, height, colorMap, + maskStr, maskWidth, maskHeight, maskInvert); + } else { out->drawImage(state, ref, str, width, height, colorMap, - haveMask ? maskColors : (int *)NULL, inlineImg); + haveColorKeyMask ? maskColors : (int *)NULL, inlineImg); + } delete colorMap; maskObj.free(); + smaskObj.free(); } if ((i = width * height) > 1000) { @@ -2704,7 +3221,7 @@ void Gfx::doForm(Object *str) { // check form type dict->lookup("FormType", &obj1); - if (!(obj1.isInt() && obj1.getInt() == 1)) { + if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) { error(getPos(), "Unknown form type"); } obj1.free(); @@ -2928,7 +3445,7 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) { // in-line image operators //------------------------------------------------------------------------ -void Gfx::opBeginImage(Object * /*args*/, int /*numArgs*/) { +void Gfx::opBeginImage(Object */*args*/, int /*numArgs*/) { Stream *str; int c1, c2; @@ -2990,11 +3507,11 @@ Stream *Gfx::buildImageStream() { return str; } -void Gfx::opImageData(Object * /*args*/, int /*numArgs*/) { +void Gfx::opImageData(Object */*args*/, int /*numArgs*/) { error(getPos(), "Internal: got 'ID' operator"); } -void Gfx::opEndImage(Object * /*args*/, int /*numArgs*/) { +void Gfx::opEndImage(Object */*args*/, int /*numArgs*/) { error(getPos(), "Internal: got 'EI' operator"); } @@ -3016,11 +3533,11 @@ void Gfx::opSetCacheDevice(Object args[], int /*numArgs*/) { // compatibility operators //------------------------------------------------------------------------ -void Gfx::opBeginIgnoreUndef(Object * /*args*/, int /*numArgs*/) { +void Gfx::opBeginIgnoreUndef(Object */*args*/, int /*numArgs*/) { ++ignoreUndef; } -void Gfx::opEndIgnoreUndef(Object * /*args*/, int /*numArgs*/) { +void Gfx::opEndIgnoreUndef(Object */*args*/, int /*numArgs*/) { if (ignoreUndef > 0) --ignoreUndef; } diff --git a/xpdf/xpdf/Gfx.h b/xpdf/xpdf/Gfx.h index ab63bc40d..4ab1dee80 100644 --- a/xpdf/xpdf/Gfx.h +++ b/xpdf/xpdf/Gfx.h @@ -33,6 +33,9 @@ class GfxShading; class GfxFunctionShading; class GfxAxialShading; class GfxRadialShading; +class GfxGouraudTriangleShading; +class GfxPatchMeshShading; +struct GfxPatch; class GfxState; struct GfxColor; class Gfx; @@ -101,14 +104,14 @@ public: // Constructor for regular output. Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, - double hDPI, double vDPI, PDFRectangle *box, GBool crop, + double hDPI, double vDPI, PDFRectangle *box, PDFRectangle *cropBox, int rotate, GBool (*abortCheckCbkA)(void *data) = NULL, void *abortCheckCbkDataA = NULL); // Constructor for a sub-page object. Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, - PDFRectangle *box, GBool crop, PDFRectangle *cropBox, + PDFRectangle *box, PDFRectangle *cropBox, GBool (*abortCheckCbkA)(void *data) = NULL, void *abortCheckCbkDataA = NULL); @@ -128,6 +131,9 @@ public: // Restore graphics state. void restoreState(); + // Get the current graphics state object. + GfxState *getState() { return state; } + private: XRef *xref; // the xref table for this PDF file @@ -216,6 +222,13 @@ private: GfxColor *colors, int depth); void doAxialShFill(GfxAxialShading *shading); void doRadialShFill(GfxRadialShading *shading); + void doGouraudTriangleShFill(GfxGouraudTriangleShading *shading); + void gouraudFillTriangle(double x0, double y0, GfxColor *color0, + double x1, double y1, GfxColor *color1, + double x2, double y2, GfxColor *color2, + int nComps, int depth); + void doPatchMeshShFill(GfxPatchMeshShading *shading); + void fillPatch(GfxPatch *patch, int nComps, int depth); void doEndPath(); // path clipping operators diff --git a/xpdf/xpdf/GfxFont.cc b/xpdf/xpdf/GfxFont.cc index 9e3ccbe52..9c031c932 100644 --- a/xpdf/xpdf/GfxFont.cc +++ b/xpdf/xpdf/GfxFont.cc @@ -55,8 +55,8 @@ static StdFontMapEntry stdFontMap[] = { { "Arial-ItalicMT", "Helvetica-Oblique" }, { "ArialMT", "Helvetica" }, { "Courier,Bold", "Courier-Bold" }, - { "Courier,Italic", "Courier-Oblique" }, { "Courier,BoldItalic", "Courier-BoldOblique" }, + { "Courier,Italic", "Courier-Oblique" }, { "CourierNew", "Courier" }, { "CourierNew,Bold", "Courier-Bold" }, { "CourierNew,BoldItalic", "Courier-BoldOblique" }, @@ -191,19 +191,19 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { // look for embedded font file if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) { - if (type == fontType1) { embFontID = obj2.getRef(); - } else { + if (type != fontType1) { error(-1, "Mismatch between font type and embedded font file"); + type = fontType1; } } obj2.free(); if (embFontID.num == -1 && obj1.dictLookupNF("FontFile2", &obj2)->isRef()) { - if (type == fontTrueType || type == fontCIDType2) { embFontID = obj2.getRef(); - } else { + if (type != fontTrueType && type != fontCIDType2) { error(-1, "Mismatch between font type and embedded font file"); + type = type == fontCIDType0 ? fontCIDType2 : fontTrueType; } } obj2.free(); @@ -212,33 +212,29 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { if (obj2.fetch(xref, &obj3)->isStream()) { obj3.streamGetDict()->lookup("Subtype", &obj4); if (obj4.isName("Type1")) { - if (type == fontType1) { embFontID = obj2.getRef(); - } else { + if (type != fontType1) { error(-1, "Mismatch between font type and embedded font file"); + type = fontType1; } } else if (obj4.isName("Type1C")) { - if (type == fontType1) { - type = fontType1C; embFontID = obj2.getRef(); - } else if (type == fontType1C) { - embFontID = obj2.getRef(); - } else { + if (type != fontType1 && type != fontType1C) { error(-1, "Mismatch between font type and embedded font file"); } + type = fontType1C; } else if (obj4.isName("TrueType")) { - if (type == fontTrueType) { embFontID = obj2.getRef(); - } else { + if (type != fontTrueType) { error(-1, "Mismatch between font type and embedded font file"); + type = fontTrueType; } } else if (obj4.isName("CIDFontType0C")) { - if (type == fontCIDType0) { - type = fontCIDType0C; embFontID = obj2.getRef(); - } else { + if (type != fontCIDType0) { error(-1, "Mismatch between font type and embedded font file"); } + type = fontCIDType0C; } else { error(-1, "Unknown embedded font type '%s'", obj4.isName() ? obj4.getName() : "???"); @@ -399,6 +395,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Dict *fontDict): GfxFont(tagA, idA, nameA) { + GString *name2; BuiltinFont *builtinFont; const char **baseEnc; GBool baseEncFromFontFile; @@ -424,20 +421,30 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, // do font name substitution for various aliases of the Base 14 font // names if (name) { + name2 = name->copy(); + i = 0; + while (i < name2->getLength()) { + if (name2->getChar(i) == ' ') { + name2->del(i); + } else { + ++i; + } + } a = 0; b = sizeof(stdFontMap) / sizeof(StdFontMapEntry); - // invariant: stdFontMap[a].altName <= name < stdFontMap[b].altName + // invariant: stdFontMap[a].altName <= name2 < stdFontMap[b].altName while (b - a > 1) { m = (a + b) / 2; - if (name->cmp(stdFontMap[m].altName) >= 0) { + if (name2->cmp(stdFontMap[m].altName) >= 0) { a = m; } else { b = m; } } - if (!name->cmp(stdFontMap[a].altName)) { + if (!name2->cmp(stdFontMap[a].altName)) { name = new GString(stdFontMap[a].properName); } + delete name2; } // is it a built-in font? @@ -468,6 +475,17 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, // get info from font descriptor readFontDescriptor(xref, fontDict); + // for non-embedded fonts, don't trust the ascent/descent/bbox + // values from the font descriptor + if (builtinFont && embFontID.num < 0) { + ascent = 0.001 * builtinFont->ascent; + descent = 0.001 * builtinFont->descent; + fontBBox[0] = 0.001 * builtinFont->bbox[0]; + fontBBox[1] = 0.001 * builtinFont->bbox[1]; + fontBBox[2] = 0.001 * builtinFont->bbox[2]; + fontBBox[3] = 0.001 * builtinFont->bbox[3]; + } + // look for an external font file findExtFontFile(); @@ -513,7 +531,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, // 2. embedded or external font file // 3. default: // - builtin --> builtin encoding - // - TrueType --> MacRomanEncoding + // - TrueType --> WinAnsiEncoding // - others --> StandardEncoding // and then add a list of differences (if any) from // FontDict.Encoding.Differences. @@ -536,9 +554,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, } else if (obj2.isName("WinAnsiEncoding")) { hasEncoding = gTrue; baseEnc = winAnsiEncoding; - } else if (obj2.isName("StandardEncoding")) { - hasEncoding = gTrue; - baseEnc = standardEncoding; } obj2.free(); } else if (obj1.isName("MacRomanEncoding")) { @@ -551,9 +566,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, } else if (obj1.isName("WinAnsiEncoding")) { hasEncoding = gTrue; baseEnc = winAnsiEncoding; - } else if (obj1.isName("StandardEncoding")) { - hasEncoding = gTrue; - baseEnc = standardEncoding; } // check embedded or external font file for base encoding @@ -607,7 +619,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, // get default base encoding if (!baseEnc) { - if (builtinFont) { + if (builtinFont && embFontID.num < 0) { baseEnc = builtinFont->defaultBaseEnc; hasEncoding = gTrue; } else if (type == fontTrueType) { @@ -899,7 +911,7 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { Unicode u; int code, i, n; - map = (Gushort *)gmalloc(256 * sizeof(Gushort)); + map = (Gushort *)gmallocn(256, sizeof(Gushort)); for (i = 0; i < 256; ++i) { map[i] = 0; } @@ -919,7 +931,8 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { // directly (possibly with an offset of 0xf000). // 1d. If the TrueType font has a Macintosh Roman cmap, use it, // as in case 1a. - // 2. If the PDF font does not have an encoding: + // 2. If the PDF font does not have an encoding or the PDF font is + // symbolic: // 2a. If the TrueType font has a Macintosh Roman cmap, use it, // and use char codes directly (possibly with an offset of // 0xf000). @@ -953,6 +966,8 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { useUnicode = gTrue; } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) { cmap = msSymbolCmap; + } else if ((flags & fontSymbolic) && macRomanCmap >= 0) { + cmap = macRomanCmap; } else if (macRomanCmap >= 0) { cmap = macRomanCmap; useMacRoman = gTrue; @@ -979,7 +994,9 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { // map Unicode through the cmap } else if (useUnicode) { for (i = 0; i < 256; ++i) { - if ((n = ctu->mapToUnicode((CharCode)i, &u, 1))) { + if (((charName = enc[i]) && + (u = globalParams->mapNameToUnicode(charName))) || + (n = ctu->mapToUnicode((CharCode)i, &u, 1))) { map[i] = ff->mapCodeToGID(cmap, u); } } @@ -1043,8 +1060,11 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, GString *collection, *cMapName; Object desFontDictObj; Object obj1, obj2, obj3, obj4, obj5, obj6; + CharCodeToUnicode *utu; + CharCode c; + Unicode uBuf[8]; int c1, c2; - int excepsSize, i, j, k; + int excepsSize, i, j, k, n; ascent = 0.95; descent = -0.35; @@ -1126,12 +1146,30 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, if (!(ctu = globalParams->getCIDToUnicode(collection))) { error(-1, "Unknown character collection '%s'", collection->getCString()); - delete collection; - goto err2; + // fall-through, assuming the Identity mapping -- this appears + // to match Adobe's behavior } } } + // look for a Unicode-to-Unicode mapping + if (name && (utu = globalParams->getUnicodeToUnicode(name))) { + if (ctu) { + for (c = 0; c < ctu->getLength(); ++c) { + n = ctu->mapToUnicode(c, uBuf, 8); + if (n >= 1) { + n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); + if (n >= 1) { + ctu->setMapping(c, uBuf, n); + } + } + } + utu->decRefCnt(); + } else { + ctu = utu; + } + } + // encoding (i.e., CMap) //~ need to handle a CMap stream here //~ also need to deal with the UseCMap entry in the stream dict @@ -1158,13 +1196,13 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, if (obj1.isStream()) { cidToGIDLen = 0; i = 64; - cidToGID = (Gushort *)gmalloc(i * sizeof(Gushort)); + cidToGID = (Gushort *)gmallocn(i, sizeof(Gushort)); obj1.streamReset(); while ((c1 = obj1.streamGetChar()) != EOF && (c2 = obj1.streamGetChar()) != EOF) { if (cidToGIDLen == i) { i *= 2; - cidToGID = (Gushort *)grealloc(cidToGID, i * sizeof(Gushort)); + cidToGID = (Gushort *)greallocn(cidToGID, i, sizeof(Gushort)); } cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2); } @@ -1194,8 +1232,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, if (widths.nExceps == excepsSize) { excepsSize += 16; widths.exceps = (GfxFontCIDWidthExcep *) - grealloc(widths.exceps, - excepsSize * sizeof(GfxFontCIDWidthExcep)); + greallocn(widths.exceps, + excepsSize, sizeof(GfxFontCIDWidthExcep)); } widths.exceps[widths.nExceps].first = obj2.getInt(); widths.exceps[widths.nExceps].last = obj3.getInt(); @@ -1210,8 +1248,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, if (widths.nExceps + obj3.arrayGetLength() > excepsSize) { excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15; widths.exceps = (GfxFontCIDWidthExcep *) - grealloc(widths.exceps, - excepsSize * sizeof(GfxFontCIDWidthExcep)); + greallocn(widths.exceps, + excepsSize, sizeof(GfxFontCIDWidthExcep)); } j = obj2.getInt(); for (k = 0; k < obj3.arrayGetLength(); ++k) { @@ -1267,8 +1305,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, if (widths.nExcepsV == excepsSize) { excepsSize += 16; widths.excepsV = (GfxFontCIDWidthExcepV *) - grealloc(widths.excepsV, - excepsSize * sizeof(GfxFontCIDWidthExcepV)); + greallocn(widths.excepsV, + excepsSize, sizeof(GfxFontCIDWidthExcepV)); } widths.excepsV[widths.nExcepsV].first = obj2.getInt(); widths.excepsV[widths.nExcepsV].last = obj3.getInt(); @@ -1288,8 +1326,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, excepsSize = (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15; widths.excepsV = (GfxFontCIDWidthExcepV *) - grealloc(widths.excepsV, - excepsSize * sizeof(GfxFontCIDWidthExcepV)); + greallocn(widths.excepsV, + excepsSize, sizeof(GfxFontCIDWidthExcepV)); } j = obj2.getInt(); for (k = 0; k < obj3.arrayGetLength(); k += 3) { @@ -1450,8 +1488,8 @@ Gushort *GfxCIDFont::getCodeToGIDMap(FoFiTrueType *ff, int *mapsizep) { // char *charName; Unicode u; int /*code, */i; - int mapsize; - int cidlen; + unsigned int mapsize; + unsigned int cidlen; *mapsizep = 0; @@ -1470,7 +1508,7 @@ Gushort *GfxCIDFont::getCodeToGIDMap(FoFiTrueType *ff, int *mapsizep) { mapsize = 64; map = (Gushort *)gmalloc(mapsize * sizeof(Gushort)); - while (cidlen < ctu->getMapLen()) { + while (cidlen < ctu->getLength()) { int n; if ((n = ctu->mapToUnicode((CharCode)cidlen, &u, 1)) == 0) { cidlen++; @@ -1499,7 +1537,7 @@ GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { Ref r; numFonts = fontDict->getLength(); - fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *)); + fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *)); for (i = 0; i < numFonts; ++i) { fontDict->getValNF(i, &obj1); obj1.fetch(xref, &obj2); diff --git a/xpdf/xpdf/GfxState.cc b/xpdf/xpdf/GfxState.cc index 8ed73b47f..a5d5bf931 100644 --- a/xpdf/xpdf/GfxState.cc +++ b/xpdf/xpdf/GfxState.cc @@ -14,7 +14,7 @@ #include #include -#include // for memcpy() +#include #include "gmem.h" #include "Error.h" #include "Object.h" @@ -24,12 +24,46 @@ //------------------------------------------------------------------------ +static inline GfxColorComp clip01(GfxColorComp x) { + return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x; +} + static inline double clip01(double x) { - return (x < 0) ? 0 : ((x > 1) ? 1 : x); + return (x < 0) ? 0 : (x > 1) ? 1 : x; } //------------------------------------------------------------------------ +static struct { + char *name; + GfxBlendMode mode; +} gfxBlendModeNames[] = { + { "Normal", gfxBlendNormal }, + { "Compatible", gfxBlendNormal }, + { "Multiply", gfxBlendMultiply }, + { "Screen", gfxBlendScreen }, + { "Overlay", gfxBlendOverlay }, + { "Darken", gfxBlendDarken }, + { "Lighten", gfxBlendLighten }, + { "ColorDodge", gfxBlendColorDodge }, + { "ColorBurn", gfxBlendColorBurn }, + { "HardLight", gfxBlendHardLight }, + { "SoftLight", gfxBlendSoftLight }, + { "Difference", gfxBlendDifference }, + { "Exclusion", gfxBlendExclusion }, + { "Hue", gfxBlendHue }, + { "Saturation", gfxBlendSaturation }, + { "Color", gfxBlendColor }, + { "Luminosity", gfxBlendLuminosity } +}; + +#define nGfxBlendModeNames \ + ((int)((sizeof(gfxBlendModeNames) / sizeof(char *)))) + +//------------------------------------------------------------------------ + +// NB: This must match the GfxColorSpaceMode enum defined in +// GfxState.h static const char *gfxColorSpaceModeNames[] = { "DeviceGray", "CalGray", @@ -139,7 +173,7 @@ GfxColorSpace *GfxDeviceGrayColorSpace::copy() { return new GfxDeviceGrayColorSpace(); } -void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) { +void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { *gray = clip01(color->c[0]); } @@ -149,7 +183,7 @@ void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->c = cmyk->m = cmyk->y = 0; - cmyk->k = clip01(1 - color->c[0]); + cmyk->k = clip01(gfxColorComp1 - color->c[0]); } //------------------------------------------------------------------------ @@ -224,7 +258,7 @@ GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) { return cs; } -void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) { +void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { *gray = clip01(color->c[0]); } @@ -234,7 +268,7 @@ void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->c = cmyk->m = cmyk->y = 0; - cmyk->k = clip01(1 - color->c[0]); + cmyk->k = clip01(gfxColorComp1 - color->c[0]); } //------------------------------------------------------------------------ @@ -251,10 +285,10 @@ GfxColorSpace *GfxDeviceRGBColorSpace::copy() { return new GfxDeviceRGBColorSpace(); } -void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) { - *gray = clip01(0.299 * color->c[0] + - 0.587 * color->c[1] + - 0.114 * color->c[2]); +void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { + *gray = clip01((GfxColorComp)(0.3 * color->c[0] + + 0.59 * color->c[1] + + 0.11 * color->c[2] + 0.5)); } void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { @@ -264,11 +298,11 @@ void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { } void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - double c, m, y, k; + GfxColorComp c, m, y, k; - c = clip01(1 - color->c[0]); - m = clip01(1 - color->c[1]); - y = clip01(1 - color->c[2]); + c = clip01(gfxColorComp1 - color->c[0]); + m = clip01(gfxColorComp1 - color->c[1]); + y = clip01(gfxColorComp1 - color->c[2]); k = c; if (m < k) { k = m; @@ -382,10 +416,10 @@ GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) { return cs; } -void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) { - *gray = clip01(0.299 * color->c[0] + +void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { + *gray = clip01((GfxColorComp)(0.299 * color->c[0] + 0.587 * color->c[1] + - 0.114 * color->c[2]); + 0.114 * color->c[2] + 0.5)); } void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { @@ -395,11 +429,11 @@ void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { } void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - double c, m, y, k; + GfxColorComp c, m, y, k; - c = clip01(1 - color->c[0]); - m = clip01(1 - color->c[1]); - y = clip01(1 - color->c[2]); + c = clip01(gfxColorComp1 - color->c[0]); + m = clip01(gfxColorComp1 - color->c[1]); + y = clip01(gfxColorComp1 - color->c[2]); k = c; if (m < k) { k = m; @@ -427,30 +461,73 @@ GfxColorSpace *GfxDeviceCMYKColorSpace::copy() { return new GfxDeviceCMYKColorSpace(); } -void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) { - *gray = clip01(1 - color->c[3] - - 0.299 * color->c[0] - - 0.587 * color->c[1] - - 0.114 * color->c[2]); +void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) { + *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3] + - 0.3 * color->c[0] + - 0.59 * color->c[1] + - 0.11 * color->c[2] + 0.5)); } void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double c, m, y, aw, ac, am, ay, ar, ag, ab; - - c = clip01(color->c[0] + color->c[3]); - m = clip01(color->c[1] + color->c[3]); - y = clip01(color->c[2] + color->c[3]); - aw = (1-c) * (1-m) * (1-y); - ac = c * (1-m) * (1-y); - am = (1-c) * m * (1-y); - ay = (1-c) * (1-m) * y; - ar = (1-c) * m * y; - ag = c * (1-m) * y; - ab = c * m * (1-y); - rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar); - rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag); - rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag + - 0.4863*ab); + double c, m, y, k, c1, m1, y1, k1, r, g, b, x; + + c = colToDbl(color->c[0]); + m = colToDbl(color->c[1]); + y = colToDbl(color->c[2]); + k = colToDbl(color->c[3]); + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + // this is a matrix multiplication, unrolled for performance + // C M Y K + x = c1 * m1 * y1 * k1; // 0 0 0 0 + r = g = b = x; + x = c1 * m1 * y1 * k; // 0 0 0 1 + r += 0.1373 * x; + g += 0.1216 * x; + b += 0.1255 * x; + x = c1 * m1 * y * k1; // 0 0 1 0 + r += x; + g += 0.9490 * x; + x = c1 * m1 * y * k; // 0 0 1 1 + r += 0.1098 * x; + g += 0.1020 * x; + x = c1 * m * y1 * k1; // 0 1 0 0 + r += 0.9255 * x; + b += 0.5490 * x; + x = c1 * m * y1 * k; // 0 1 0 1 + r += 0.1412 * x; + x = c1 * m * y * k1; // 0 1 1 0 + r += 0.9294 * x; + g += 0.1098 * x; + b += 0.1412 * x; + x = c1 * m * y * k; // 0 1 1 1 + r += 0.1333 * x; + x = c * m1 * y1 * k1; // 1 0 0 0 + g += 0.6784 * x; + b += 0.9373 * x; + x = c * m1 * y1 * k; // 1 0 0 1 + g += 0.0588 * x; + b += 0.1412 * x; + x = c * m1 * y * k1; // 1 0 1 0 + g += 0.6510 * x; + b += 0.3137 * x; + x = c * m1 * y * k; // 1 0 1 1 + g += 0.0745 * x; + x = c * m * y1 * k1; // 1 1 0 0 + r += 0.1804 * x; + g += 0.1922 * x; + b += 0.5725 * x; + x = c * m * y1 * k; // 1 1 0 1 + b += 0.0078 * x; + x = c * m * y * k1; // 1 1 1 0 + r += 0.2118 * x; + g += 0.2119 * x; + b += 0.2235 * x; + rgb->r = clip01(dblToCol(r)); + rgb->g = clip01(dblToCol(g)); + rgb->b = clip01(dblToCol(b)); } void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { @@ -570,13 +647,13 @@ GfxColorSpace *GfxLabColorSpace::parse(Array *arr) { return cs; } -void GfxLabColorSpace::getGray(GfxColor *color, double *gray) { +void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) { GfxRGB rgb; getRGB(color, &rgb); - *gray = clip01(0.299 * rgb.r + + *gray = clip01((GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + - 0.114 * rgb.b); + 0.114 * rgb.b + 0.5)); } void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { @@ -585,8 +662,8 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { double r, g, b; // convert L*a*b* to CIE 1931 XYZ color space - t1 = (color->c[0] + 16) / 116; - t2 = t1 + color->c[1] / 500; + t1 = (colToDbl(color->c[0]) + 16) / 116; + t2 = t1 + colToDbl(color->c[1]) / 500; if (t2 >= (6.0 / 29.0)) { X = t2 * t2 * t2; } else { @@ -599,7 +676,7 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0)); } Y *= whiteY; - t2 = t1 - color->c[2] / 200; + t2 = t1 - colToDbl(color->c[2]) / 200; if (t2 >= (6.0 / 29.0)) { Z = t2 * t2 * t2; } else { @@ -611,19 +688,19 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z; g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z; b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z; - rgb->r = pow(clip01(r * kr), 0.5); - rgb->g = pow(clip01(g * kg), 0.5); - rgb->b = pow(clip01(b * kb), 0.5); + rgb->r = dblToCol(pow(clip01(r * kr), 0.5)); + rgb->g = dblToCol(pow(clip01(g * kg), 0.5)); + rgb->b = dblToCol(pow(clip01(b * kb), 0.5)); } void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { GfxRGB rgb; - double c, m, y, k; + GfxColorComp c, m, y, k; getRGB(color, &rgb); - c = clip01(1 - rgb.r); - m = clip01(1 - rgb.g); - y = clip01(1 - rgb.b); + c = clip01(gfxColorComp1 - rgb.r); + m = clip01(gfxColorComp1 - rgb.g); + y = clip01(gfxColorComp1 - rgb.b); k = c; if (m < k) { k = m; @@ -750,7 +827,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) { return cs; } -void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) { +void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) { alt->getGray(color, gray); } @@ -787,7 +864,7 @@ GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA, int indexHighA) { base = baseA; indexHigh = indexHighA; - lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() * + lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(), sizeof(Guchar)); } @@ -889,14 +966,14 @@ GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color, n = base->getNComps(); base->getDefaultRanges(low, range, indexHigh); - p = &lookup[(int)(color->c[0] + 0.5) * n]; + p = &lookup[(int)(colToDbl(color->c[0]) + 0.5) * n]; for (i = 0; i < n; ++i) { - baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i]; + baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]); } return baseColor; } -void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) { +void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) { GfxColor color2; base->getGray(mapColorToBase(color, &color2), gray); @@ -985,24 +1062,45 @@ GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) { return NULL; } -void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) { +void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) { + double x; + double c[gfxColorMaxComps]; GfxColor color2; + int i; - func->transform(color->c, color2.c); + x = colToDbl(color->c[0]); + func->transform(&x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } alt->getGray(&color2, gray); } void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + double x; + double c[gfxColorMaxComps]; GfxColor color2; + int i; - func->transform(color->c, color2.c); + x = colToDbl(color->c[0]); + func->transform(&x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } alt->getRGB(&color2, rgb); } void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + double x; + double c[gfxColorMaxComps]; GfxColor color2; + int i; - func->transform(color->c, color2.c); + x = colToDbl(color->c[0]); + func->transform(&x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } alt->getCMYK(&color2, cmyk); } @@ -1102,24 +1200,48 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) { return NULL; } -void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) { +void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) { + double x[gfxColorMaxComps], c[gfxColorMaxComps]; GfxColor color2; + int i; - func->transform(color->c, color2.c); + for (i = 0; i < nComps; ++i) { + x[i] = colToDbl(color->c[i]); + } + func->transform(x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } alt->getGray(&color2, gray); } void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + double x[gfxColorMaxComps], c[gfxColorMaxComps]; GfxColor color2; + int i; - func->transform(color->c, color2.c); + for (i = 0; i < nComps; ++i) { + x[i] = colToDbl(color->c[i]); + } + func->transform(x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } alt->getRGB(&color2, rgb); } void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + double x[gfxColorMaxComps], c[gfxColorMaxComps]; GfxColor color2; + int i; - func->transform(color->c, color2.c); + for (i = 0; i < nComps; ++i) { + x[i] = colToDbl(color->c[i]); + } + func->transform(x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } alt->getCMYK(&color2, cmyk); } @@ -1165,7 +1287,7 @@ GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) { return cs; } -void GfxPatternColorSpace::getGray(GfxColor */*color*/, double *gray) { +void GfxPatternColorSpace::getGray(GfxColor */*color*/, GfxGray *gray) { *gray = 0; } @@ -1450,6 +1572,38 @@ GfxShading *GfxShading::parse(Object *obj) { case 3: shading = GfxRadialShading::parse(dict); break; + case 4: + if (obj->isStream()) { + shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 4 shading object"); + goto err1; + } + break; + case 5: + if (obj->isStream()) { + shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 5 shading object"); + goto err1; + } + break; + case 6: + if (obj->isStream()) { + shading = GfxPatchMeshShading::parse(6, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 6 shading object"); + goto err1; + } + break; + case 7: + if (obj->isStream()) { + shading = GfxPatchMeshShading::parse(7, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 7 shading object"); + goto err1; + } + break; default: error(-1, "Unimplemented shading type %d", typeA); goto err1; @@ -1481,7 +1635,7 @@ GBool GfxShading::init(Dict *dict) { if (obj1.arrayGetLength() == colorSpace->getNComps()) { hasBackground = gTrue; for (i = 0; i < colorSpace->getNComps(); ++i) { - background.c[i] = obj1.arrayGet(i, &obj2)->getNum(); + background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum()); obj2.free(); } } else { @@ -1649,13 +1803,21 @@ GfxShading *GfxFunctionShading::copy() { } void GfxFunctionShading::getColor(double x, double y, GfxColor *color) { - double in[2]; + double in[2], out[gfxColorMaxComps]; int i; + // NB: there can be one function with n outputs or n functions with + // one output each (where n = number of color components) + for (i = 0; i < gfxColorMaxComps; ++i) { + out[i] = 0; + } in[0] = x; in[1] = y; for (i = 0; i < nFuncs; ++i) { - funcs[i]->transform(in, &color->c[i]); + funcs[i]->transform(in, &out[i]); + } + for (i = 0; i < gfxColorMaxComps; ++i) { + color->c[i] = dblToCol(out[i]); } } @@ -1803,12 +1965,19 @@ GfxShading *GfxAxialShading::copy() { } void GfxAxialShading::getColor(double t, GfxColor *color) { + double out[gfxColorMaxComps]; int i; // NB: there can be one function with n outputs or n functions with // one output each (where n = number of color components) + for (i = 0; i < gfxColorMaxComps; ++i) { + out[i] = 0; + } for (i = 0; i < nFuncs; ++i) { - funcs[i]->transform(&t, &color->c[i]); + funcs[i]->transform(&t, &out[i]); + } + for (i = 0; i < gfxColorMaxComps; ++i) { + color->c[i] = dblToCol(out[i]); } } @@ -1964,13 +2133,961 @@ GfxShading *GfxRadialShading::copy() { } void GfxRadialShading::getColor(double t, GfxColor *color) { + double out[gfxColorMaxComps]; int i; // NB: there can be one function with n outputs or n functions with // one output each (where n = number of color components) + for (i = 0; i < gfxColorMaxComps; ++i) { + out[i] = 0; + } for (i = 0; i < nFuncs; ++i) { - funcs[i]->transform(&t, &color->c[i]); + funcs[i]->transform(&t, &out[i]); + } + for (i = 0; i < gfxColorMaxComps; ++i) { + color->c[i] = dblToCol(out[i]); + } +} + +//------------------------------------------------------------------------ +// GfxShadingBitBuf +//------------------------------------------------------------------------ + +class GfxShadingBitBuf { +public: + + GfxShadingBitBuf(Stream *strA); + ~GfxShadingBitBuf(); + GBool getBits(int n, Guint *val); + void flushBits(); + +private: + + Stream *str; + int bitBuf; + int nBits; +}; + +GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) { + str = strA; + str->reset(); + bitBuf = 0; + nBits = 0; +} + +GfxShadingBitBuf::~GfxShadingBitBuf() { + str->close(); +} + +GBool GfxShadingBitBuf::getBits(int n, Guint *val) { + int x; + + if (nBits >= n) { + x = (bitBuf >> (nBits - n)) & ((1 << n) - 1); + nBits -= n; + } else { + x = 0; + if (nBits > 0) { + x = bitBuf & ((1 << nBits) - 1); + n -= nBits; + nBits = 0; + } + while (n > 0) { + if ((bitBuf = str->getChar()) == EOF) { + nBits = 0; + return gFalse; + } + if (n >= 8) { + x = (x << 8) | bitBuf; + n -= 8; + } else { + x = (x << n) | (bitBuf >> (8 - n)); + nBits = 8 - n; + n = 0; + } + } } + *val = x; + return gTrue; +} + +void GfxShadingBitBuf::flushBits() { + bitBuf = 0; + nBits = 0; +} + +//------------------------------------------------------------------------ +// GfxGouraudTriangleShading +//------------------------------------------------------------------------ + +GfxGouraudTriangleShading::GfxGouraudTriangleShading( + int typeA, + GfxGouraudVertex *verticesA, int nVerticesA, + int (*trianglesA)[3], int nTrianglesA, + Function **funcsA, int nFuncsA): + GfxShading(typeA) +{ + int i; + + vertices = verticesA; + nVertices = nVerticesA; + triangles = trianglesA; + nTriangles = nTrianglesA; + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } +} + +GfxGouraudTriangleShading::GfxGouraudTriangleShading( + GfxGouraudTriangleShading *shading): + GfxShading(shading) +{ + int i; + + nVertices = shading->nVertices; + vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex)); + memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex)); + nTriangles = shading->nTriangles; + triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int)); + memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int)); + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } +} + +GfxGouraudTriangleShading::~GfxGouraudTriangleShading() { + int i; + + gfree(vertices); + gfree(triangles); + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA, + Dict *dict, + Stream *str) { + GfxGouraudTriangleShading *shading; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + int coordBits, compBits, flagBits, vertsPerRow, nRows; + double xMin, xMax, yMin, yMax; + double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; + double xMul, yMul; + double cMul[gfxColorMaxComps]; + GfxGouraudVertex *verticesA; + int (*trianglesA)[3]; + int nComps, nVerticesA, nTrianglesA, vertSize, triSize; + Guint x, y, flag; + Guint c[gfxColorMaxComps]; + GfxShadingBitBuf *bitBuf; + Object obj1, obj2; + int i, j, k, state; + + if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) { + coordBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("BitsPerComponent", &obj1)->isInt()) { + compBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerComponent in shading dictionary"); + goto err2; + } + obj1.free(); + flagBits = vertsPerRow = 0; // make gcc happy + if (typeA == 4) { + if (dict->lookup("BitsPerFlag", &obj1)->isInt()) { + flagBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerFlag in shading dictionary"); + goto err2; + } + obj1.free(); + } else { + if (dict->lookup("VerticesPerRow", &obj1)->isInt()) { + vertsPerRow = obj1.getInt(); + } else { + error(-1, "Missing or invalid VerticesPerRow in shading dictionary"); + goto err2; + } + obj1.free(); + } + if (dict->lookup("Decode", &obj1)->isArray() && + obj1.arrayGetLength() >= 6) { + xMin = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + xMax = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); + yMin = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + yMax = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); + for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { + cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(); + obj2.free(); + cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(); + obj2.free(); + cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1); + } + nComps = i; + } else { + error(-1, "Missing or invalid Decode array in shading dictionary"); + goto err2; + } + obj1.free(); + + if (!dict->lookup("Function", &obj1)->isNull()) { + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + for (i = 0; i < nFuncsA; ++i) { + obj1.arrayGet(i, &obj2); + if (!(funcsA[i] = Function::parse(&obj2))) { + obj1.free(); + obj2.free(); + goto err1; + } + obj2.free(); + } + } else { + nFuncsA = 1; + if (!(funcsA[0] = Function::parse(&obj1))) { + obj1.free(); + goto err1; + } + } + } else { + nFuncsA = 0; + } + obj1.free(); + + nVerticesA = nTrianglesA = 0; + verticesA = NULL; + trianglesA = NULL; + vertSize = triSize = 0; + state = 0; + flag = 0; // make gcc happy + bitBuf = new GfxShadingBitBuf(str); + while (1) { + if (typeA == 4) { + if (!bitBuf->getBits(flagBits, &flag)) { + break; + } + } + if (!bitBuf->getBits(coordBits, &x) || + !bitBuf->getBits(coordBits, &y)) { + break; + } + for (i = 0; i < nComps; ++i) { + if (!bitBuf->getBits(compBits, &c[i])) { + break; + } + } + if (i < nComps) { + break; + } + if (nVerticesA == vertSize) { + vertSize = (vertSize == 0) ? 16 : 2 * vertSize; + verticesA = (GfxGouraudVertex *) + greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex)); + } + verticesA[nVerticesA].x = xMin + xMul * (double)x; + verticesA[nVerticesA].y = yMin + yMul * (double)y; + for (i = 0; i < nComps; ++i) { + verticesA[nVerticesA].color.c[i] = + dblToCol(cMin[i] + cMul[i] * (double)c[i]); + } + ++nVerticesA; + bitBuf->flushBits(); + if (typeA == 4) { + if (state == 0 || state == 1) { + ++state; + } else if (state == 2 || flag > 0) { + if (nTrianglesA == triSize) { + triSize = (triSize == 0) ? 16 : 2 * triSize; + trianglesA = (int (*)[3]) + greallocn(trianglesA, triSize * 3, sizeof(int)); + } + if (state == 2) { + trianglesA[nTrianglesA][0] = nVerticesA - 3; + trianglesA[nTrianglesA][1] = nVerticesA - 2; + trianglesA[nTrianglesA][2] = nVerticesA - 1; + ++state; + } else if (flag == 1) { + trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1]; + trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; + trianglesA[nTrianglesA][2] = nVerticesA - 1; + } else { // flag == 2 + trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0]; + trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; + trianglesA[nTrianglesA][2] = nVerticesA - 1; + } + ++nTrianglesA; + } else { // state == 3 && flag == 0 + state = 1; + } + } + } + delete bitBuf; + if (typeA == 5) { + nRows = nVerticesA / vertsPerRow; + nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1); + trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int)); + k = 0; + for (i = 0; i < nRows - 1; ++i) { + for (j = 0; j < vertsPerRow - 1; ++j) { + trianglesA[k][0] = i * vertsPerRow + j; + trianglesA[k][1] = i * vertsPerRow + j+1; + trianglesA[k][2] = (i+1) * vertsPerRow + j; + ++k; + trianglesA[k][0] = i * vertsPerRow + j+1; + trianglesA[k][1] = (i+1) * vertsPerRow + j; + trianglesA[k][2] = (i+1) * vertsPerRow + j+1; + ++k; + } + } + } + + shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA, + trianglesA, nTrianglesA, + funcsA, nFuncsA); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err2: + obj1.free(); + err1: + return NULL; +} + +GfxShading *GfxGouraudTriangleShading::copy() { + return new GfxGouraudTriangleShading(this); +} + +void GfxGouraudTriangleShading::getTriangle( + int i, + double *x0, double *y0, GfxColor *color0, + double *x1, double *y1, GfxColor *color1, + double *x2, double *y2, GfxColor *color2) { + double in; + double out[gfxColorMaxComps]; + int v, j; + + v = triangles[i][0]; + *x0 = vertices[v].x; + *y0 = vertices[v].y; + if (nFuncs > 0) { + in = colToDbl(vertices[v].color.c[0]); + for (j = 0; j < nFuncs; ++j) { + funcs[j]->transform(&in, &out[j]); + } + for (j = 0; j < gfxColorMaxComps; ++j) { + color0->c[j] = dblToCol(out[j]); + } + } else { + *color0 = vertices[v].color; + } + v = triangles[i][1]; + *x1 = vertices[v].x; + *y1 = vertices[v].y; + if (nFuncs > 0) { + in = colToDbl(vertices[v].color.c[0]); + for (j = 0; j < nFuncs; ++j) { + funcs[j]->transform(&in, &out[j]); + } + for (j = 0; j < gfxColorMaxComps; ++j) { + color1->c[j] = dblToCol(out[j]); + } + } else { + *color1 = vertices[v].color; + } + v = triangles[i][2]; + *x2 = vertices[v].x; + *y2 = vertices[v].y; + if (nFuncs > 0) { + in = colToDbl(vertices[v].color.c[0]); + for (j = 0; j < nFuncs; ++j) { + funcs[j]->transform(&in, &out[j]); + } + for (j = 0; j < gfxColorMaxComps; ++j) { + color2->c[j] = dblToCol(out[j]); + } + } else { + *color2 = vertices[v].color; + } +} + +//------------------------------------------------------------------------ +// GfxPatchMeshShading +//------------------------------------------------------------------------ + +GfxPatchMeshShading::GfxPatchMeshShading(int typeA, + GfxPatch *patchesA, int nPatchesA, + Function **funcsA, int nFuncsA): + GfxShading(typeA) +{ + int i; + + patches = patchesA; + nPatches = nPatchesA; + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } +} + +GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading): + GfxShading(shading) +{ + int i; + + nPatches = shading->nPatches; + patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch)); + memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch)); + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } +} + +GfxPatchMeshShading::~GfxPatchMeshShading() { + int i; + + gfree(patches); + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, + Stream *str) { + GfxPatchMeshShading *shading; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + int coordBits, compBits, flagBits; + double xMin, xMax, yMin, yMax; + double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; + double xMul, yMul; + double cMul[gfxColorMaxComps]; + GfxPatch *patchesA, *p; + int nComps, nPatchesA, patchesSize, nPts, nColors; + Guint flag; + double x[16], y[16]; + Guint xi, yi; + GfxColorComp c[4][gfxColorMaxComps]; + Guint ci[4]; + GfxShadingBitBuf *bitBuf; + Object obj1, obj2; + int i, j; + + if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) { + coordBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("BitsPerComponent", &obj1)->isInt()) { + compBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerComponent in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("BitsPerFlag", &obj1)->isInt()) { + flagBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerFlag in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("Decode", &obj1)->isArray() && + obj1.arrayGetLength() >= 6) { + xMin = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + xMax = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); + yMin = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + yMax = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); + for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { + cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(); + obj2.free(); + cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(); + obj2.free(); + cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1); + } + nComps = i; + } else { + error(-1, "Missing or invalid Decode array in shading dictionary"); + goto err2; + } + obj1.free(); + + if (!dict->lookup("Function", &obj1)->isNull()) { + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + for (i = 0; i < nFuncsA; ++i) { + obj1.arrayGet(i, &obj2); + if (!(funcsA[i] = Function::parse(&obj2))) { + obj1.free(); + obj2.free(); + goto err1; + } + obj2.free(); + } + } else { + nFuncsA = 1; + if (!(funcsA[0] = Function::parse(&obj1))) { + obj1.free(); + goto err1; + } + } + } else { + nFuncsA = 0; + } + obj1.free(); + + nPatchesA = 0; + patchesA = NULL; + patchesSize = 0; + bitBuf = new GfxShadingBitBuf(str); + while (1) { + if (!bitBuf->getBits(flagBits, &flag)) { + break; + } + if (typeA == 6) { + switch (flag) { + case 0: nPts = 12; nColors = 4; break; + case 1: + case 2: + case 3: + default: nPts = 8; nColors = 2; break; + } + } else { + switch (flag) { + case 0: nPts = 16; nColors = 4; break; + case 1: + case 2: + case 3: + default: nPts = 12; nColors = 2; break; + } + } + for (i = 0; i < nPts; ++i) { + if (!bitBuf->getBits(coordBits, &xi) || + !bitBuf->getBits(coordBits, &yi)) { + break; + } + x[i] = xMin + xMul * (double)xi; + y[i] = yMin + yMul * (double)yi; + } + if (i < nPts) { + break; + } + for (i = 0; i < nColors; ++i) { + for (j = 0; j < nComps; ++j) { + if (!bitBuf->getBits(compBits, &ci[j])) { + break; + } + c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]); + } + if (j < nComps) { + break; + } + } + if (i < nColors) { + break; + } + if (nPatchesA == patchesSize) { + patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize; + patchesA = (GfxPatch *)greallocn(patchesA, + patchesSize, sizeof(GfxPatch)); + } + p = &patchesA[nPatchesA]; + if (typeA == 6) { + switch (flag) { + case 0: + p->x[0][0] = x[0]; + p->y[0][0] = y[0]; + p->x[0][1] = x[1]; + p->y[0][1] = y[1]; + p->x[0][2] = x[2]; + p->y[0][2] = y[2]; + p->x[0][3] = x[3]; + p->y[0][3] = y[3]; + p->x[1][3] = x[4]; + p->y[1][3] = y[4]; + p->x[2][3] = x[5]; + p->y[2][3] = y[5]; + p->x[3][3] = x[6]; + p->y[3][3] = y[6]; + p->x[3][2] = x[7]; + p->y[3][2] = y[7]; + p->x[3][1] = x[8]; + p->y[3][1] = y[8]; + p->x[3][0] = x[9]; + p->y[3][0] = y[9]; + p->x[2][0] = x[10]; + p->y[2][0] = y[10]; + p->x[1][0] = x[11]; + p->y[1][0] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = c[0][j]; + p->color[0][1].c[j] = c[1][j]; + p->color[1][1].c[j] = c[2][j]; + p->color[1][0].c[j] = c[3][j]; + } + break; + case 1: + p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; + p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; + p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; + p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 2: + p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; + p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; + p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; + p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 3: + p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; + p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; + p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; + p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; + p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; + p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + for (j = 0; j < nComps; ++j) { + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + } + } else { + switch (flag) { + case 0: + p->x[0][0] = x[0]; + p->y[0][0] = y[0]; + p->x[0][1] = x[1]; + p->y[0][1] = y[1]; + p->x[0][2] = x[2]; + p->y[0][2] = y[2]; + p->x[0][3] = x[3]; + p->y[0][3] = y[3]; + p->x[1][3] = x[4]; + p->y[1][3] = y[4]; + p->x[2][3] = x[5]; + p->y[2][3] = y[5]; + p->x[3][3] = x[6]; + p->y[3][3] = y[6]; + p->x[3][2] = x[7]; + p->y[3][2] = y[7]; + p->x[3][1] = x[8]; + p->y[3][1] = y[8]; + p->x[3][0] = x[9]; + p->y[3][0] = y[9]; + p->x[2][0] = x[10]; + p->y[2][0] = y[10]; + p->x[1][0] = x[11]; + p->y[1][0] = y[11]; + p->x[1][1] = x[12]; + p->y[1][1] = y[12]; + p->x[1][2] = x[13]; + p->y[1][2] = y[13]; + p->x[2][2] = x[14]; + p->y[2][2] = y[14]; + p->x[2][1] = x[15]; + p->y[2][1] = y[15]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = c[0][j]; + p->color[0][1].c[j] = c[1][j]; + p->color[1][1].c[j] = c[2][j]; + p->color[1][0].c[j] = c[3][j]; + } + break; + case 1: + p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; + p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; + p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; + p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + p->x[1][1] = x[8]; + p->y[1][1] = y[8]; + p->x[1][2] = x[9]; + p->y[1][2] = y[9]; + p->x[2][2] = x[10]; + p->y[2][2] = y[10]; + p->x[2][1] = x[11]; + p->y[2][1] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 2: + p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; + p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; + p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; + p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + p->x[1][1] = x[8]; + p->y[1][1] = y[8]; + p->x[1][2] = x[9]; + p->y[1][2] = y[9]; + p->x[2][2] = x[10]; + p->y[2][2] = y[10]; + p->x[2][1] = x[11]; + p->y[2][1] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 3: + p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; + p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; + p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; + p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; + p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; + p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + p->x[1][1] = x[8]; + p->y[1][1] = y[8]; + p->x[1][2] = x[9]; + p->y[1][2] = y[9]; + p->x[2][2] = x[10]; + p->y[2][2] = y[10]; + p->x[2][1] = x[11]; + p->y[2][1] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + } + } + ++nPatchesA; + bitBuf->flushBits(); + } + delete bitBuf; + + if (typeA == 6) { + for (i = 0; i < nPatchesA; ++i) { + p = &patchesA[i]; + p->x[1][1] = (-4 * p->x[0][0] + +6 * (p->x[0][1] + p->x[1][0]) + -2 * (p->x[0][3] + p->x[3][0]) + +3 * (p->x[3][1] + p->x[1][3]) + - p->x[3][3]) / 9; + p->y[1][1] = (-4 * p->y[0][0] + +6 * (p->y[0][1] + p->y[1][0]) + -2 * (p->y[0][3] + p->y[3][0]) + +3 * (p->y[3][1] + p->y[1][3]) + - p->y[3][3]) / 9; + p->x[1][2] = (-4 * p->x[0][3] + +6 * (p->x[0][2] + p->x[1][3]) + -2 * (p->x[0][0] + p->x[3][3]) + +3 * (p->x[3][2] + p->x[1][0]) + - p->x[3][0]) / 9; + p->y[1][2] = (-4 * p->y[0][3] + +6 * (p->y[0][2] + p->y[1][3]) + -2 * (p->y[0][0] + p->y[3][3]) + +3 * (p->y[3][2] + p->y[1][0]) + - p->y[3][0]) / 9; + p->x[2][1] = (-4 * p->x[3][0] + +6 * (p->x[3][1] + p->x[2][0]) + -2 * (p->x[3][3] + p->x[0][0]) + +3 * (p->x[0][1] + p->x[2][3]) + - p->x[0][3]) / 9; + p->y[2][1] = (-4 * p->y[3][0] + +6 * (p->y[3][1] + p->y[2][0]) + -2 * (p->y[3][3] + p->y[0][0]) + +3 * (p->y[0][1] + p->y[2][3]) + - p->y[0][3]) / 9; + p->x[2][2] = (-4 * p->x[3][3] + +6 * (p->x[3][2] + p->x[2][3]) + -2 * (p->x[3][0] + p->x[0][3]) + +3 * (p->x[0][2] + p->x[2][0]) + - p->x[0][0]) / 9; + p->y[2][2] = (-4 * p->y[3][3] + +6 * (p->y[3][2] + p->y[2][3]) + -2 * (p->y[3][0] + p->y[0][3]) + +3 * (p->y[0][2] + p->y[2][0]) + - p->y[0][0]) / 9; + } + } + + shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA, + funcsA, nFuncsA); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err2: + obj1.free(); + err1: + return NULL; +} + +GfxShading *GfxPatchMeshShading::copy() { + return new GfxPatchMeshShading(this); } //------------------------------------------------------------------------ @@ -2030,6 +3147,9 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, // Optimization: for Indexed and Separation color spaces (which have // only one component), we store color values in the lookup table // rather than component values. + for (k = 0; k < gfxColorMaxComps; ++k) { + lookup[k] = NULL; + } colorSpace2 = NULL; nComps2 = 0; if (colorSpace->getMode() == csIndexed) { @@ -2040,9 +3160,11 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, colorSpace2 = indexedCS->getBase(); indexHigh = indexedCS->getIndexHigh(); nComps2 = colorSpace2->getNComps(); - lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double)); lookup2 = indexedCS->getLookup(); colorSpace2->getDefaultRanges(x, y, indexHigh); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, + sizeof(GfxColorComp)); for (i = 0; i <= maxPixel; ++i) { j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5); if (j < 0) { @@ -2050,29 +3172,31 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, } else if (j > indexHigh) { j = indexHigh; } - for (k = 0; k < nComps2; ++k) { - lookup[i*nComps2 + k] = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]; + lookup[k][i] = + dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]); } } } else if (colorSpace->getMode() == csSeparation) { sepCS = (GfxSeparationColorSpace *)colorSpace; colorSpace2 = sepCS->getAlt(); nComps2 = colorSpace2->getNComps(); - lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double)); sepFunc = sepCS->getFunc(); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, + sizeof(GfxColorComp)); for (i = 0; i <= maxPixel; ++i) { x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel; sepFunc->transform(x, y); - for (k = 0; k < nComps2; ++k) { - lookup[i*nComps2 + k] = y[k]; + lookup[k][i] = dblToCol(y[k]); } } } else { - lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double)); - for (i = 0; i <= maxPixel; ++i) { for (k = 0; k < nComps; ++k) { - lookup[i*nComps + k] = decodeLow[k] + - (i * decodeRange[k]) / maxPixel; + lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, + sizeof(GfxColorComp)); + for (i = 0; i <= maxPixel; ++i) { + lookup[k][i] = dblToCol(decodeLow[k] + + (i * decodeRange[k]) / maxPixel); } } } @@ -2086,26 +3210,35 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, } GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) { - int n, i; + int n, i, k; colorSpace = colorMap->colorSpace->copy(); bits = colorMap->bits; nComps = colorMap->nComps; nComps2 = colorMap->nComps2; colorSpace2 = NULL; - lookup = NULL; + for (k = 0; k < gfxColorMaxComps; ++k) { + lookup[k] = NULL; + } n = 1 << bits; if (colorSpace->getMode() == csIndexed) { colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase(); - n = n * nComps2 * sizeof(double); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); + memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); + } } else if (colorSpace->getMode() == csSeparation) { colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt(); - n = n * nComps2 * sizeof(double); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); + memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); + } } else { - n = n * nComps * sizeof(double); + for (k = 0; k < nComps; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); + memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); + } } - lookup = (double *)gmalloc(n); - memcpy(lookup, colorMap->lookup, n); for (i = 0; i < nComps; ++i) { decodeLow[i] = colorMap->decodeLow[i]; decodeRange[i] = colorMap->decodeRange[i]; @@ -2114,24 +3247,26 @@ GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) { } GfxImageColorMap::~GfxImageColorMap() { + int i; + delete colorSpace; - gfree(lookup); + for (i = 0; i < gfxColorMaxComps; ++i) { + gfree(lookup[i]); + } } -void GfxImageColorMap::getGray(Guchar *x, double *gray) { +void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) { GfxColor color; - double *p; int i; if (colorSpace2) { - p = &lookup[x[0] * nComps2]; for (i = 0; i < nComps2; ++i) { - color.c[i] = *p++; + color.c[i] = lookup[i][x[0]]; } colorSpace2->getGray(&color, gray); } else { for (i = 0; i < nComps; ++i) { - color.c[i] = lookup[x[i] * nComps + i]; + color.c[i] = lookup[i][x[i]]; } colorSpace->getGray(&color, gray); } @@ -2139,18 +3274,16 @@ void GfxImageColorMap::getGray(Guchar *x, double *gray) { void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) { GfxColor color; - double *p; int i; if (colorSpace2) { - p = &lookup[x[0] * nComps2]; for (i = 0; i < nComps2; ++i) { - color.c[i] = *p++; + color.c[i] = lookup[i][x[0]]; } colorSpace2->getRGB(&color, rgb); } else { for (i = 0; i < nComps; ++i) { - color.c[i] = lookup[x[i] * nComps + i]; + color.c[i] = lookup[i][x[i]]; } colorSpace->getRGB(&color, rgb); } @@ -2158,18 +3291,16 @@ void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) { void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) { GfxColor color; - double *p; int i; if (colorSpace2) { - p = &lookup[x[0] * nComps2]; for (i = 0; i < nComps2; ++i) { - color.c[i] = *p++; + color.c[i] = lookup[i][x[0]]; } colorSpace2->getCMYK(&color, cmyk); } else { for (i = 0; i < nComps; ++i) { - color.c[i] = lookup[x[i] * nComps + i]; + color.c[i] = lookup[i][x[i]]; } colorSpace->getCMYK(&color, cmyk); } @@ -2180,7 +3311,7 @@ void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) { maxPixel = (1 << bits) - 1; for (i = 0; i < nComps; ++i) { - color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel; + color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel); } } @@ -2190,9 +3321,9 @@ void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) { GfxSubpath::GfxSubpath(double x1, double y1) { size = 16; - x = (double *)gmalloc(size * sizeof(double)); - y = (double *)gmalloc(size * sizeof(double)); - curve = (GBool *)gmalloc(size * sizeof(GBool)); + x = (double *)gmallocn(size, sizeof(double)); + y = (double *)gmallocn(size, sizeof(double)); + curve = (GBool *)gmallocn(size, sizeof(GBool)); n = 1; x[0] = x1; y[0] = y1; @@ -2210,9 +3341,9 @@ GfxSubpath::~GfxSubpath() { GfxSubpath::GfxSubpath(GfxSubpath *subpath) { size = subpath->size; n = subpath->n; - x = (double *)gmalloc(size * sizeof(double)); - y = (double *)gmalloc(size * sizeof(double)); - curve = (GBool *)gmalloc(size * sizeof(GBool)); + x = (double *)gmallocn(size, sizeof(double)); + y = (double *)gmallocn(size, sizeof(double)); + curve = (GBool *)gmallocn(size, sizeof(GBool)); memcpy(x, subpath->x, n * sizeof(double)); memcpy(y, subpath->y, n * sizeof(double)); memcpy(curve, subpath->curve, n * sizeof(GBool)); @@ -2222,9 +3353,9 @@ GfxSubpath::GfxSubpath(GfxSubpath *subpath) { void GfxSubpath::lineTo(double x1, double y1) { if (n >= size) { size += 16; - x = (double *)grealloc(x, size * sizeof(double)); - y = (double *)grealloc(y, size * sizeof(double)); - curve = (GBool *)grealloc(curve, size * sizeof(GBool)); + x = (double *)greallocn(x, size, sizeof(double)); + y = (double *)greallocn(y, size, sizeof(double)); + curve = (GBool *)greallocn(curve, size, sizeof(GBool)); } x[n] = x1; y[n] = y1; @@ -2236,9 +3367,9 @@ void GfxSubpath::curveTo(double x1, double y1, double x2, double y2, double x3, double y3) { if (n+3 > size) { size += 16; - x = (double *)grealloc(x, size * sizeof(double)); - y = (double *)grealloc(y, size * sizeof(double)); - curve = (GBool *)grealloc(curve, size * sizeof(GBool)); + x = (double *)greallocn(x, size, sizeof(double)); + y = (double *)greallocn(y, size, sizeof(double)); + curve = (GBool *)greallocn(curve, size, sizeof(GBool)); } x[n] = x1; y[n] = y1; @@ -2272,7 +3403,7 @@ GfxPath::GfxPath() { size = 16; n = 0; firstX = firstY = 0; - subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *)); + subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *)); } GfxPath::~GfxPath() { @@ -2293,7 +3424,7 @@ GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1, firstY = firstY1; size = size1; n = n1; - subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *)); + subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *)); for (i = 0; i < n; ++i) subpaths[i] = subpaths1[i]->copy(); } @@ -2309,7 +3440,7 @@ void GfxPath::lineTo(double x, double y) { if (n >= size) { size += 16; subpaths = (GfxSubpath **) - grealloc(subpaths, size * sizeof(GfxSubpath *)); + greallocn(subpaths, size, sizeof(GfxSubpath *)); } subpaths[n] = new GfxSubpath(firstX, firstY); ++n; @@ -2324,7 +3455,7 @@ void GfxPath::curveTo(double x1, double y1, double x2, double y2, if (n >= size) { size += 16; subpaths = (GfxSubpath **) - grealloc(subpaths, size * sizeof(GfxSubpath *)); + greallocn(subpaths, size, sizeof(GfxSubpath *)); } subpaths[n] = new GfxSubpath(firstX, firstY); ++n; @@ -2340,7 +3471,7 @@ void GfxPath::close() { if (n >= size) { size += 16; subpaths = (GfxSubpath **) - grealloc(subpaths, size * sizeof(GfxSubpath *)); + greallocn(subpaths, size, sizeof(GfxSubpath *)); } subpaths[n] = new GfxSubpath(firstX, firstY); ++n; @@ -2355,7 +3486,7 @@ void GfxPath::append(GfxPath *path) { if (n + path->n > size) { size = n + path->n; subpaths = (GfxSubpath **) - grealloc(subpaths, size * sizeof(GfxSubpath *)); + greallocn(subpaths, size, sizeof(GfxSubpath *)); } for (i = 0; i < path->n; ++i) { subpaths[n++] = path->subpaths[i]->copy(); @@ -2376,9 +3507,10 @@ void GfxPath::offset(double dx, double dy) { //------------------------------------------------------------------------ GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, - int rotate, GBool upsideDown) { + int rotateA, GBool upsideDown) { double kx, ky; + rotate = rotateA; px1 = pageBox->x1; py1 = pageBox->y1; px2 = pageBox->x2; @@ -2429,8 +3561,11 @@ GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, strokeColor.c[0] = 0; fillPattern = NULL; strokePattern = NULL; + blendMode = gfxBlendNormal; fillOpacity = 1; strokeOpacity = 1; + fillOverprint = gFalse; + strokeOverprint = gFalse; lineWidth = 1; lineDash = NULL; @@ -2504,7 +3639,7 @@ GfxState::GfxState(GfxState *state) { strokePattern = state->strokePattern->copy(); } if (lineDashLength > 0) { - lineDash = (double *)gmalloc(lineDashLength * sizeof(double)); + lineDash = (double *)gmallocn(lineDashLength, sizeof(double)); memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double)); } saved = NULL; @@ -2774,3 +3909,38 @@ GfxState *GfxState::restore() { return oldState; } + +GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) { + Object obj2; + int i, j; + + if (obj->isName()) { + for (i = 0; i < nGfxBlendModeNames; ++i) { + if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) { + *mode = gfxBlendModeNames[i].mode; + return gTrue; + } + } + return gFalse; + } else if (obj->isArray()) { + for (i = 0; i < obj->arrayGetLength(); ++i) { + obj->arrayGet(i, &obj2); + if (!obj2.isName()) { + obj2.free(); + return gFalse; + } + for (j = 0; j < nGfxBlendModeNames; ++j) { + if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) { + obj2.free(); + *mode = gfxBlendModeNames[j].mode; + return gTrue; + } + } + obj2.free(); + } + *mode = gfxBlendNormal; + return gTrue; + } else { + return gFalse; + } +} diff --git a/xpdf/xpdf/GfxState.h b/xpdf/xpdf/GfxState.h index 5cc4976b6..202318d0d 100644 --- a/xpdf/xpdf/GfxState.h +++ b/xpdf/xpdf/GfxState.h @@ -24,6 +24,59 @@ class GfxFont; class PDFRectangle; class GfxShading; +//------------------------------------------------------------------------ +// GfxBlendMode +//------------------------------------------------------------------------ + +enum GfxBlendMode { + gfxBlendNormal, + gfxBlendMultiply, + gfxBlendScreen, + gfxBlendOverlay, + gfxBlendDarken, + gfxBlendLighten, + gfxBlendColorDodge, + gfxBlendColorBurn, + gfxBlendHardLight, + gfxBlendSoftLight, + gfxBlendDifference, + gfxBlendExclusion, + gfxBlendHue, + gfxBlendSaturation, + gfxBlendColor, + gfxBlendLuminosity +}; + +//------------------------------------------------------------------------ +// GfxColorComp +//------------------------------------------------------------------------ + +// 16.16 fixed point color component +typedef int GfxColorComp; + +#define gfxColorComp1 0x10000 + +static inline GfxColorComp dblToCol(double x) { + return (GfxColorComp)(x * gfxColorComp1); +} + +static inline double colToDbl(GfxColorComp x) { + return (double)x / (double)gfxColorComp1; +} + +static inline GfxColorComp byteToCol(Guchar x) { + // (x / 255) << 16 = (0.0000000100000001... * x) << 16 + // = ((x << 8) + (x) + (x >> 8) + ...) << 16 + // = (x << 8) + (x) + (x >> 7) + // [for rounding] + return (GfxColorComp)((x << 8) + x + (x >> 7)); +} + +static inline Guchar colToByte(GfxColorComp x) { + // 255 * x + 0.5 = 256 * x - x + 0x8000 + return (Guchar)(((x << 8) - x + 0x8000) >> 16); +} + //------------------------------------------------------------------------ // GfxColor //------------------------------------------------------------------------ @@ -31,15 +84,21 @@ class GfxShading; #define gfxColorMaxComps funcMaxOutputs struct GfxColor { - double c[gfxColorMaxComps]; + GfxColorComp c[gfxColorMaxComps]; }; +//------------------------------------------------------------------------ +// GfxGray +//------------------------------------------------------------------------ + +typedef GfxColorComp GfxGray; + //------------------------------------------------------------------------ // GfxRGB //------------------------------------------------------------------------ struct GfxRGB { - double r, g, b; + GfxColorComp r, g, b; }; //------------------------------------------------------------------------ @@ -47,7 +106,7 @@ struct GfxRGB { //------------------------------------------------------------------------ struct GfxCMYK { - double c, m, y, k; + GfxColorComp c, m, y, k; }; //------------------------------------------------------------------------ @@ -82,7 +141,7 @@ public: static GfxColorSpace *parse(Object *csObj); // Convert to gray, RGB, or CMYK. - virtual void getGray(GfxColor *color, double *gray) = 0; + virtual void getGray(GfxColor *color, GfxGray *gray) = 0; virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0; virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0; @@ -115,7 +174,7 @@ public: virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceGray; } - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -139,7 +198,7 @@ public: // Construct a CalGray color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -173,7 +232,7 @@ public: virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceRGB; } - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -197,7 +256,7 @@ public: // Construct a CalRGB color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -235,7 +294,7 @@ public: virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceCMYK; } - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -259,7 +318,7 @@ public: // Construct a Lab color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -304,7 +363,7 @@ public: // Construct an ICCBased color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -340,7 +399,7 @@ public: // Construct a Lab color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -378,7 +437,7 @@ public: // Construct a Separation color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -411,7 +470,7 @@ public: // Construct a DeviceN color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -446,7 +505,7 @@ public: // Construct a Pattern color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -599,6 +658,8 @@ public: void getDomain(double *x0A, double *y0A, double *x1A, double *y1A) { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } double *getMatrix() { return matrix; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } void getColor(double x, double y, GfxColor *color); private: @@ -632,9 +693,11 @@ public: { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } double getDomain0() { return t0; } double getDomain1() { return t1; } - void getColor(double t, GfxColor *color); GBool getExtend0() { return extend0; } GBool getExtend1() { return extend1; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } + void getColor(double t, GfxColor *color); private: @@ -669,9 +732,11 @@ public: { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; } double getDomain0() { return t0; } double getDomain1() { return t1; } - void getColor(double t, GfxColor *color); GBool getExtend0() { return extend0; } GBool getExtend1() { return extend1; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } + void getColor(double t, GfxColor *color); private: @@ -682,6 +747,77 @@ private: GBool extend0, extend1; }; +//------------------------------------------------------------------------ +// GfxGouraudTriangleShading +//------------------------------------------------------------------------ + +struct GfxGouraudVertex { + double x, y; + GfxColor color; +}; + +class GfxGouraudTriangleShading: public GfxShading { +public: + + GfxGouraudTriangleShading(int typeA, + GfxGouraudVertex *verticesA, int nVerticesA, + int (*trianglesA)[3], int nTrianglesA, + Function **funcsA, int nFuncsA); + GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading); + virtual ~GfxGouraudTriangleShading(); + + static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str); + + virtual GfxShading *copy(); + + int getNTriangles() { return nTriangles; } + void getTriangle(int i, double *x0, double *y0, GfxColor *color0, + double *x1, double *y1, GfxColor *color1, + double *x2, double *y2, GfxColor *color2); + +private: + + GfxGouraudVertex *vertices; + int nVertices; + int (*triangles)[3]; + int nTriangles; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + +//------------------------------------------------------------------------ +// GfxPatchMeshShading +//------------------------------------------------------------------------ + +struct GfxPatch { + double x[4][4]; + double y[4][4]; + GfxColor color[2][2]; +}; + +class GfxPatchMeshShading: public GfxShading { +public: + + GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA, + Function **funcsA, int nFuncsA); + GfxPatchMeshShading(GfxPatchMeshShading *shading); + virtual ~GfxPatchMeshShading(); + + static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str); + + virtual GfxShading *copy(); + + int getNPatches() { return nPatches; } + GfxPatch *getPatch(int i) { return &patches[i]; } + +private: + + GfxPatch *patches; + int nPatches; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + //------------------------------------------------------------------------ // GfxImageColorMap //------------------------------------------------------------------------ @@ -713,7 +849,7 @@ public: double getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; } // Convert an image pixel to a color. - void getGray(Guchar *x, double *gray); + void getGray(Guchar *x, GfxGray *gray); void getRGB(Guchar *x, GfxRGB *rgb); void getCMYK(Guchar *x, GfxCMYK *cmyk); void getColor(Guchar *x, GfxColor *color); @@ -727,7 +863,8 @@ private: int nComps; // number of components in a pixel GfxColorSpace *colorSpace2; // secondary color space int nComps2; // number of components in colorSpace2 - double *lookup; // lookup table + GfxColorComp * // lookup table + lookup[gfxColorMaxComps]; double // minimum values for each component decodeLow[gfxColorMaxComps]; double // max - min value for each component @@ -853,10 +990,10 @@ class GfxState { public: // Construct a default GfxState, for a device with resolution - // x , page box , page rotation , and + // x , page box , page rotation , and // coordinate system specified by . GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, - int rotate, GBool upsideDown); + int rotateA, GBool upsideDown); // Destructor. ~GfxState(); @@ -872,11 +1009,12 @@ public: double getY2() { return py2; } double getPageWidth() { return pageWidth; } double getPageHeight() { return pageHeight; } + int getRotate() { return rotate; } GfxColor *getFillColor() { return &fillColor; } GfxColor *getStrokeColor() { return &strokeColor; } - void getFillGray(double *gray) + void getFillGray(GfxGray *gray) { fillColorSpace->getGray(&fillColor, gray); } - void getStrokeGray(double *gray) + void getStrokeGray(GfxGray *gray) { strokeColorSpace->getGray(&strokeColor, gray); } void getFillRGB(GfxRGB *rgb) { fillColorSpace->getRGB(&fillColor, rgb); } @@ -890,8 +1028,11 @@ public: GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; } GfxPattern *getFillPattern() { return fillPattern; } GfxPattern *getStrokePattern() { return strokePattern; } + GfxBlendMode getBlendMode() { return blendMode; } double getFillOpacity() { return fillOpacity; } double getStrokeOpacity() { return strokeOpacity; } + GBool getFillOverprint() { return fillOverprint; } + GBool getStrokeOverprint() { return strokeOverprint; } double getLineWidth() { return lineWidth; } void getLineDash(double **dash, int *length, double *start) { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; } @@ -952,8 +1093,11 @@ public: void setStrokeColor(GfxColor *color) { strokeColor = *color; } void setFillPattern(GfxPattern *pattern); void setStrokePattern(GfxPattern *pattern); + void setBlendMode(GfxBlendMode mode) { blendMode = mode; } void setFillOpacity(double opac) { fillOpacity = opac; } void setStrokeOpacity(double opac) { strokeOpacity = opac; } + void setFillOverprint(GBool op) { fillOverprint = op; } + void setStrokeOverprint(GBool op) { strokeOverprint = op; } void setLineWidth(double width) { lineWidth = width; } void setLineDash(double *dash, int length, double start); void setFlatness(int flatness1) { flatness = flatness1; } @@ -1006,11 +1150,15 @@ public: GfxState *restore(); GBool hasSaves() { return saved != NULL; } + // Misc + GBool parseBlendMode(Object *obj, GfxBlendMode *mode); + private: double ctm[6]; // coord transform matrix double px1, py1, px2, py2; // page corners (user coords) double pageWidth, pageHeight; // page size (pixels) + int rotate; // page rotation angle GfxColorSpace *fillColorSpace; // fill color space GfxColorSpace *strokeColorSpace; // stroke color space @@ -1018,8 +1166,11 @@ private: GfxColor strokeColor; // stroke color GfxPattern *fillPattern; // fill pattern GfxPattern *strokePattern; // stroke pattern + GfxBlendMode blendMode; // transparency blend mode double fillOpacity; // fill opacity double strokeOpacity; // stroke opacity + GBool fillOverprint; // fill overprint + GBool strokeOverprint; // stroke overprint double lineWidth; // line width double *lineDash; // line dash diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index 224032dba..4b1af8955 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -44,6 +44,9 @@ #include "CMap.h" #include "BuiltinFontTables.h" #include "FontEncodingTables.h" +#ifdef ENABLE_PLUGINS +# include "XpdfPluginAPI.h" +#endif #include "GlobalParams.h" #if MULTITHREADED @@ -66,6 +69,12 @@ #include "UnicodeMapTables.h" #include "UTF8.h" +#ifdef ENABLE_PLUGINS +# ifdef WIN32 +extern XpdfPluginVecTable xpdfPluginVecTable; +# endif +#endif + //------------------------------------------------------------------------ #define cidToUnicodeCacheSize 4 @@ -75,35 +84,42 @@ static struct { const char *name; - const char *fileName; + const char *t1FileName; + const char *ttFileName; } displayFontTab[] = { - {"Courier", "n022003l.pfb"}, - {"Courier-Bold", "n022004l.pfb"}, - {"Courier-BoldOblique", "n022024l.pfb"}, - {"Courier-Oblique", "n022023l.pfb"}, - {"Helvetica", "n019003l.pfb"}, - {"Helvetica-Bold", "n019004l.pfb"}, - {"Helvetica-BoldOblique", "n019024l.pfb"}, - {"Helvetica-Oblique", "n019023l.pfb"}, - {"Symbol", "s050000l.pfb"}, - {"Times-Bold", "n021004l.pfb"}, - {"Times-BoldItalic", "n021024l.pfb"}, - {"Times-Italic", "n021023l.pfb"}, - {"Times-Roman", "n021003l.pfb"}, - {"ZapfDingbats", "d050000l.pfb"}, - {NULL, NULL} + {"Courier", "n022003l.pfb", "cour.ttf"}, + {"Courier-Bold", "n022004l.pfb", "courbd.ttf"}, + {"Courier-BoldOblique", "n022024l.pfb", "courbi.ttf"}, + {"Courier-Oblique", "n022023l.pfb", "couri.ttf"}, + {"Helvetica", "n019003l.pfb", "arial.ttf"}, + {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf"}, + {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf"}, + {"Helvetica-Oblique", "n019023l.pfb", "ariali.ttf"}, + {"Symbol", "s050000l.pfb", NULL}, + {"Times-Bold", "n021004l.pfb", "timesbd.ttf"}, + {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf"}, + {"Times-Italic", "n021023l.pfb", "timesi.ttf"}, + {"Times-Roman", "n021003l.pfb", "times.ttf"}, + {"ZapfDingbats", "d050000l.pfb", NULL}, + {NULL, NULL, NULL} }; +#ifdef WIN32 +static const char *displayFontDirs[] = { + "c:/windows/fonts", + "c:/winnt/fonts", + NULL +}; +#else static const char *displayFontDirs[] = { "/usr/share/ghostscript/fonts", "/usr/local/share/ghostscript/fonts", "/usr/share/fonts/default/Type1", + "/usr/share/fonts/default/ghostscript", "/usr/share/fonts/type1/gsfonts", - "/usr/share/fonts/default/ghostscript/", - "/usr/share/fonts/Type1", NULL }; - +#endif //------------------------------------------------------------------------ @@ -163,6 +179,148 @@ PSFontParam::~PSFontParam() { } } +#ifdef ENABLE_PLUGINS +//------------------------------------------------------------------------ +// Plugin +//------------------------------------------------------------------------ + +class Plugin { +public: + + static Plugin *load(char *type, char *name); + ~Plugin(); + +private: + +#ifdef WIN32 + Plugin(HMODULE libA); + HMODULE lib; +#else + Plugin(void *dlA); + void *dl; +#endif +}; + +Plugin *Plugin::load(char *type, char *name) { + GString *path; + Plugin *plugin; + XpdfPluginVecTable *vt; + XpdfBool (*xpdfInitPlugin)(void); +#ifdef WIN32 + HMODULE libA; +#else + void *dlA; +#endif + + path = globalParams->getBaseDir(); + appendToPath(path, "plugins"); + appendToPath(path, type); + appendToPath(path, name); + +#ifdef WIN32 + path->append(".dll"); + if (!(libA = LoadLibrary(path->getCString()))) { + error(-1, "Failed to load plugin '%s'", + path->getCString()); + goto err1; + } + if (!(vt = (XpdfPluginVecTable *) + GetProcAddress(libA, "xpdfPluginVecTable"))) { + error(-1, "Failed to find xpdfPluginVecTable in plugin '%s'", + path->getCString()); + goto err2; + } +#else + //~ need to deal with other extensions here + path->append(".so"); + if (!(dlA = dlopen(path->getCString(), RTLD_NOW))) { + error(-1, "Failed to load plugin '%s': %s", + path->getCString(), dlerror()); + goto err1; + } + if (!(vt = (XpdfPluginVecTable *)dlsym(dlA, "xpdfPluginVecTable"))) { + error(-1, "Failed to find xpdfPluginVecTable in plugin '%s'", + path->getCString()); + goto err2; + } +#endif + + if (vt->version != xpdfPluginVecTable.version) { + error(-1, "Plugin '%s' is wrong version", path->getCString()); + goto err2; + } + memcpy(vt, &xpdfPluginVecTable, sizeof(xpdfPluginVecTable)); + +#ifdef WIN32 + if (!(xpdfInitPlugin = (XpdfBool (*)(void)) + GetProcAddress(libA, "xpdfInitPlugin"))) { + error(-1, "Failed to find xpdfInitPlugin in plugin '%s'", + path->getCString()); + goto err2; + } +#else + if (!(xpdfInitPlugin = (XpdfBool (*)(void))dlsym(dlA, "xpdfInitPlugin"))) { + error(-1, "Failed to find xpdfInitPlugin in plugin '%s'", + path->getCString()); + goto err2; + } +#endif + + if (!(*xpdfInitPlugin)()) { + error(-1, "Initialization of plugin '%s' failed", + path->getCString()); + goto err2; + } + +#ifdef WIN32 + plugin = new Plugin(libA); +#else + plugin = new Plugin(dlA); +#endif + + delete path; + return plugin; + + err2: +#ifdef WIN32 + FreeLibrary(libA); +#else + dlclose(dlA); +#endif + err1: + delete path; + return NULL; +} + +#ifdef WIN32 +Plugin::Plugin(HMODULE libA) { + lib = libA; +} +#else +Plugin::Plugin(void *dlA) { + dl = dlA; +} +#endif + +Plugin::~Plugin() { + void (*xpdfFreePlugin)(void); + +#ifdef WIN32 + if ((xpdfFreePlugin = (void (*)(void)) + GetProcAddress(lib, "xpdfFreePlugin"))) { + (*xpdfFreePlugin)(); + } + FreeLibrary(lib); +#else + if ((xpdfFreePlugin = (void (*)(void))dlsym(dl, "xpdfFreePlugin"))) { + (*xpdfFreePlugin)(); + } + dlclose(dl); +#endif +} + +#endif // ENABLE_PLUGINS + //------------------------------------------------------------------------ // parsing //------------------------------------------------------------------------ @@ -190,6 +348,12 @@ GlobalParams::GlobalParams(const char *cfgFileName) { } } +#ifdef WIN32 + // baseDir will be set by a call to setBaseDir + baseDir = new GString(); +#else + baseDir = appendToPath(getHomeDir(), ".xpdf"); +#endif nameToUnicode = new NameToCharCode(); cidToUnicodes = new GHash(gTrue); unicodeToUnicodes = new GHash(gTrue); @@ -250,6 +414,7 @@ GlobalParams::GlobalParams(const char *cfgFileName) { textKeepTinyChars = gFalse; fontDirs = new GList(); initialZoom = new GString("125"); + continuousView = gFalse; enableT1lib = gTrue; enableFreeType = gTrue; antialias = gTrue; @@ -265,6 +430,11 @@ GlobalParams::GlobalParams(const char *cfgFileName) { unicodeMapCache = new UnicodeMapCache(); cMapCache = new CMapCache(); +#ifdef ENABLE_PLUGINS + plugins = new GList(); + securityHandlers = new GList(); +#endif + // set up the initial nameToUnicode table for (i = 0; nameToUnicodeTab[i].name; ++i) { nameToUnicode->add(nameToUnicodeTab[i].name, nameToUnicodeTab[i].u); @@ -457,6 +627,8 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { parseFontDir(tokens, fileName, line); } else if (!cmd->cmp("initialZoom")) { parseInitialZoom(tokens, fileName, line); + } else if (!cmd->cmp("continuousView")) { + parseYesNo("continuousView", &continuousView, tokens, fileName, line); } else if (!cmd->cmp("enableT1lib")) { parseYesNo("enableT1lib", &enableT1lib, tokens, fileName, line); } else if (!cmd->cmp("enableFreeType")) { @@ -878,6 +1050,7 @@ GlobalParams::~GlobalParams() { delete macRomanReverseMap; + delete baseDir; delete nameToUnicode; deleteGHash(cidToUnicodes, GString); deleteGHash(unicodeToUnicodes, GString); @@ -914,6 +1087,11 @@ GlobalParams::~GlobalParams() { delete unicodeMapCache; delete cMapCache; +#ifdef ENABLE_PLUGINS + delete securityHandlers; + deleteGList(plugins, Plugin); +#endif + #if MULTITHREADED gDestroyMutex(&mutex); gDestroyMutex(&unicodeMapCacheMutex); @@ -923,13 +1101,43 @@ GlobalParams::~GlobalParams() { //------------------------------------------------------------------------ +void GlobalParams::setBaseDir(char *dir) { + delete baseDir; + baseDir = new GString(dir); +} + void GlobalParams::setupBaseFonts(char *dir) { GString *fontName; GString *fileName; +#ifdef WIN32 + HMODULE shell32Lib; + BOOL (__stdcall *SHGetSpecialFolderPathFunc)(HWND hwndOwner, + LPTSTR lpszPath, + int nFolder, + BOOL fCreate); + char winFontDir[MAX_PATH]; +#endif FILE *f; + DisplayFontParamKind kind; DisplayFontParam *dfp; int i, j; +#ifdef WIN32 + // SHGetSpecialFolderPath isn't available in older versions of + // shell32.dll (Win95 and WinNT4), so do a dynamic load + winFontDir[0] = '\0'; + if ((shell32Lib = LoadLibrary("shell32.dll"))) { + if ((SHGetSpecialFolderPathFunc = + (BOOL (__stdcall *)(HWND hwndOwner, LPTSTR lpszPath, + int nFolder, BOOL fCreate)) + GetProcAddress(shell32Lib, "SHGetSpecialFolderPath"))) { + if (!(*SHGetSpecialFolderPathFunc)(NULL, winFontDir, + CSIDL_FONTS, FALSE)) { + winFontDir[0] = '\0'; + } + } + } +#endif for (i = 0; displayFontTab[i].name; ++i) { fontName = new GString(displayFontTab[i].name); if (getDisplayFont(fontName)) { @@ -937,8 +1145,10 @@ void GlobalParams::setupBaseFonts(char *dir) { continue; } fileName = NULL; + kind = displayFontT1; // make gcc happy if (dir) { - fileName = appendToPath(new GString(dir), displayFontTab[i].fileName); + fileName = appendToPath(new GString(dir), displayFontTab[i].t1FileName); + kind = displayFontT1; if ((f = fopen(fileName->getCString(), "rb"))) { fclose(f); } else { @@ -946,11 +1156,39 @@ void GlobalParams::setupBaseFonts(char *dir) { fileName = NULL; } } - -#ifndef WIN32 +#ifdef WIN32 + if (!fileName && winFontDir[0] && displayFontTab[i].ttFileName) { + fileName = appendToPath(new GString(winFontDir), + displayFontTab[i].ttFileName); + kind = displayFontTT; + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } + // SHGetSpecialFolderPath(CSIDL_FONTS) doesn't work on Win 2k Server + // or Win2003 Server, or with older versions of shell32.dll, so check + // the "standard" directories + if (displayFontTab[i].ttFileName) { + for (j = 0; !fileName && displayFontDirs[j]; ++j) { + fileName = appendToPath(new GString(displayFontDirs[j]), + displayFontTab[i].ttFileName); + kind = displayFontTT; + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } + } +#else for (j = 0; !fileName && displayFontDirs[j]; ++j) { fileName = appendToPath(new GString(displayFontDirs[j]), - displayFontTab[i].fileName); + displayFontTab[i].t1FileName); + kind = displayFontT1; if ((f = fopen(fileName->getCString(), "rb"))) { fclose(f); } else { @@ -959,13 +1197,12 @@ void GlobalParams::setupBaseFonts(char *dir) { } } #endif - if (!fileName) { error(-1, "No display font for '%s'", displayFontTab[i].name); delete fontName; continue; } - dfp = new DisplayFontParam(fontName, displayFontT1); + dfp = new DisplayFontParam(fontName, kind); dfp->t1.fileName = fileName; globalParams->addDisplayFont(dfp); } @@ -980,6 +1217,15 @@ CharCode GlobalParams::getMacRomanCharCode(const char *charName) { return macRomanReverseMap->lookup(charName); } +GString *GlobalParams::getBaseDir() { + GString *s; + + lockGlobalParams; + s = baseDir->copy(); + unlockGlobalParams; + return s; +} + Unicode GlobalParams::mapNameToUnicode(const char *charName) { // no need to lock - nameToUnicode is constant return nameToUnicode->lookup(charName); @@ -1382,6 +1628,15 @@ GString *GlobalParams::getInitialZoom() { return s; } +GBool GlobalParams::getContinuousView() { + GBool f; + + lockGlobalParams; + f = continuousView; + unlockGlobalParams; + return f; +} + GBool GlobalParams::getEnableT1lib() { GBool f; @@ -1698,6 +1953,12 @@ void GlobalParams::setInitialZoom(char *s) { unlockGlobalParams; } +void GlobalParams::setContinuousView(GBool cont) { + lockGlobalParams; + continuousView = cont; + unlockGlobalParams; +} + GBool GlobalParams::setEnableT1lib(char *s) { GBool ok; @@ -1743,3 +2004,63 @@ void GlobalParams::setErrQuiet(GBool errQuietA) { errQuiet = errQuietA; unlockGlobalParams; } + +void GlobalParams::addSecurityHandler(XpdfSecurityHandler */*handler**/) { +#ifdef ENABLE_PLUGINS + lockGlobalParams; + securityHandlers->append(handler); + unlockGlobalParams; +#endif +} + +XpdfSecurityHandler *GlobalParams::getSecurityHandler(char */*name*/) { +#ifdef ENABLE_PLUGINS + XpdfSecurityHandler *hdlr; + int i; + + lockGlobalParams; + for (i = 0; i < securityHandlers->getLength(); ++i) { + hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); + if (!stricmp(hdlr->name, name)) { + unlockGlobalParams; + return hdlr; + } + } + unlockGlobalParams; + + if (!loadPlugin("security", name)) { + return NULL; + } + + lockGlobalParams; + for (i = 0; i < securityHandlers->getLength(); ++i) { + hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); + if (!strcmp(hdlr->name, name)) { + unlockGlobalParams; + return hdlr; + } + } + unlockGlobalParams; +#endif + + return NULL; +} + +#ifdef ENABLE_PLUGINS +//------------------------------------------------------------------------ +// plugins +//------------------------------------------------------------------------ + +GBool GlobalParams::loadPlugin(char *type, char *name) { + Plugin *plugin; + + if (!(plugin = Plugin::load(type, name))) { + return gFalse; + } + lockGlobalParams; + plugins->append(plugin); + unlockGlobalParams; + return gTrue; +} + +#endif // ENABLE_PLUGINS diff --git a/xpdf/xpdf/GlobalParams.h b/xpdf/xpdf/GlobalParams.h index e6be63121..31be7b71d 100644 --- a/xpdf/xpdf/GlobalParams.h +++ b/xpdf/xpdf/GlobalParams.h @@ -33,6 +33,7 @@ class UnicodeMap; class UnicodeMapCache; class CMap; class CMapCache; +struct XpdfSecurityHandler; class GlobalParams; //------------------------------------------------------------------------ @@ -47,6 +48,15 @@ enum DisplayFontParamKind { displayFontTT }; +struct DisplayFontParamT1 { + GString *fileName; +}; + +struct DisplayFontParamTT { + GString *fileName; + int faceIndex; +}; + class DisplayFontParam { public: @@ -55,13 +65,8 @@ public: // generic CID fonts DisplayFontParamKind kind; union { - struct { - GString *fileName; - } t1; - struct { - GString *fileName; - int faceIndex; - } tt; + DisplayFontParamT1 t1; + DisplayFontParamTT tt; }; DisplayFontParam(GString *nameA, DisplayFontParamKind kindA); @@ -116,12 +121,14 @@ public: ~GlobalParams(); + void setBaseDir(char *dir); void setupBaseFonts(char *dir); //----- accessors CharCode getMacRomanCharCode(const char *charName); + GString *getBaseDir(); Unicode mapNameToUnicode(const char *charName); UnicodeMap *getResidentUnicodeMap(GString *encodingName); FILE *getUnicodeMapFile(GString *encodingName); @@ -153,6 +160,7 @@ public: GBool getTextKeepTinyChars(); GString *findFontFile(GString *fontName, const char **exts); GString *getInitialZoom(); + GBool getContinuousView(); GBool getEnableT1lib(); GBool getEnableFreeType(); GBool getAntialias(); @@ -193,6 +201,7 @@ public: void setTextPageBreaks(GBool pageBreaks); void setTextKeepTinyChars(GBool keep); void setInitialZoom(char *s); + void setContinuousView(GBool cont); GBool setEnableT1lib(char *s); GBool setEnableFreeType(char *s); GBool setAntialias(char *s); @@ -200,6 +209,11 @@ public: void setPrintCommands(GBool printCommandsA); void setErrQuiet(GBool errQuietA); + //----- security handlers + + void addSecurityHandler(XpdfSecurityHandler *handler); + XpdfSecurityHandler *getSecurityHandler(char *name); + private: void parseFile(GString *fileName, FILE *f); @@ -229,6 +243,9 @@ private: GList *tokens, GString *fileName, int line); GBool parseYesNo2(char *token, GBool *flag); UnicodeMap *getUnicodeMap2(GString *encodingName); +#ifdef ENABLE_PLUGINS + GBool loadPlugin(char *type, char *name); +#endif //----- static tables @@ -237,6 +254,7 @@ private: //----- user-modifiable settings + GString *baseDir; // base directory - for plugins, etc. NameToCharCode * // mapping from char name to Unicode nameToUnicode; GHash *cidToUnicodes; // files for mappings from char collections @@ -288,6 +306,7 @@ private: GBool textKeepTinyChars; // keep all characters in text output GList *fontDirs; // list of font dirs [GString] GString *initialZoom; // initial zoom level + GBool continuousView; // continuous view mode GBool enableT1lib; // t1lib enable flag GBool enableFreeType; // FreeType enable flag GBool antialias; // anti-aliasing enable flag @@ -302,6 +321,12 @@ private: UnicodeMapCache *unicodeMapCache; CMapCache *cMapCache; +#ifdef ENABLE_PLUGINS + GList *plugins; // list of plugins [Plugin] + GList *securityHandlers; // list of loaded security handlers + // [XpdfSecurityHandler] +#endif + #if MULTITHREADED GMutex mutex; GMutex unicodeMapCacheMutex; diff --git a/xpdf/xpdf/JArithmeticDecoder.cc b/xpdf/xpdf/JArithmeticDecoder.cc index fd297445b..93d6b9cf1 100644 --- a/xpdf/xpdf/JArithmeticDecoder.cc +++ b/xpdf/xpdf/JArithmeticDecoder.cc @@ -22,7 +22,7 @@ JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) { contextSize = contextSizeA; - cxTab = (Guchar *)gmalloc(contextSize * sizeof(Guchar)); + cxTab = (Guchar *)gmallocn(contextSize, sizeof(Guchar)); reset(); } @@ -89,24 +89,24 @@ int JArithmeticDecoder::switchTab[47] = { JArithmeticDecoder::JArithmeticDecoder() { str = NULL; -} - -JArithmeticDecoder::~JArithmeticDecoder() { - while (dataLen > 0) { - readByte(); - } + dataLen = 0; + limitStream = gFalse; } inline Guint JArithmeticDecoder::readByte() { - if (dataLen == 0) { + if (limitStream) { + --dataLen; + if (dataLen < 0) { return 0xff; } - if (dataLen > 0) { - --dataLen; } return (Guint)str->getChar() & 0xff; } +JArithmeticDecoder::~JArithmeticDecoder() { + cleanup(); +} + void JArithmeticDecoder::start() { buf0 = readByte(); buf1 = readByte(); @@ -119,6 +119,28 @@ void JArithmeticDecoder::start() { a = 0x80000000; } +void JArithmeticDecoder::restart(int dataLenA) { + int oldDataLen; + + oldDataLen = dataLen; + dataLen = dataLenA; + if (oldDataLen == -1) { + buf1 = readByte(); + } else if (oldDataLen <= -2) { + buf0 = readByte(); + buf1 = readByte(); + } +} + +void JArithmeticDecoder::cleanup() { + if (limitStream) { + while (dataLen > 0) { + buf0 = buf1; + buf1 = readByte(); + } + } +} + int JArithmeticDecoder::decodeBit(Guint context, JArithmeticDecoderStats *stats) { int bit; diff --git a/xpdf/xpdf/JArithmeticDecoder.h b/xpdf/xpdf/JArithmeticDecoder.h index a348017d0..a40823ddb 100644 --- a/xpdf/xpdf/JArithmeticDecoder.h +++ b/xpdf/xpdf/JArithmeticDecoder.h @@ -53,12 +53,29 @@ public: JArithmeticDecoder(); ~JArithmeticDecoder(); + void setStream(Stream *strA) - { str = strA; dataLen = -1; } + { str = strA; dataLen = 0; limitStream = gFalse; } void setStream(Stream *strA, int dataLenA) - { str = strA; dataLen = dataLenA; } + { str = strA; dataLen = dataLenA; limitStream = gTrue; } + + // Start decoding on a new stream. This fills the byte buffers and + // runs INITDEC. void start(); + + // Restart decoding on an interrupted stream. This refills the + // buffers if needed, but does not run INITDEC. (This is used in + // JPEG 2000 streams when codeblock data is split across multiple + // packets/layers.) + void restart(int dataLenA); + + // Read any leftover data in the stream. + void cleanup(); + + // Decode one bit. int decodeBit(Guint context, JArithmeticDecoderStats *stats); + + // Decode eight bits. int decodeByte(Guint context, JArithmeticDecoderStats *stats); // Returns false for OOB, otherwise sets * and returns true. @@ -86,6 +103,7 @@ private: Stream *str; int dataLen; + GBool limitStream; }; #endif diff --git a/xpdf/xpdf/JBIG2Stream.cc b/xpdf/xpdf/JBIG2Stream.cc index 60899ad72..c190aba47 100644 --- a/xpdf/xpdf/JBIG2Stream.cc +++ b/xpdf/xpdf/JBIG2Stream.cc @@ -681,7 +681,9 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): w = wA; h = hA; line = (wA + 7) >> 3; - data = (Guchar *)gmalloc(h * line); + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)gmalloc(h * line + 1); + data[h * line] = 0; } JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): @@ -690,8 +692,10 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): w = bitmap->w; h = bitmap->h; line = bitmap->line; - data = (Guchar *)gmalloc(h * line); + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)gmalloc(h * line + 1); memcpy(data, bitmap->data, h * line); + data[h * line] = 0; } JBIG2Bitmap::~JBIG2Bitmap() { @@ -719,13 +723,15 @@ void JBIG2Bitmap::expand(int newH, Guint pixel) { if (newH <= h) { return; } - data = (Guchar *)grealloc(data, newH * line); + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)grealloc(data, newH * line + 1); if (pixel) { memset(data + h * line, 0xff, (newH - h) * line); } else { memset(data + h * line, 0x00, (newH - h) * line); } h = newH; + data[h * line] = 0; } void JBIG2Bitmap::clearToZero() { @@ -933,6 +939,10 @@ void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y, } // right-most byte + // note: this last byte (src1) may not actually be used, depending + // on the values of s1, m1, and m2 - and in fact, it may be off + // the edge of the source bitmap, which means we need to allocate + // one extra guard byte at the end of each bitmap dest = *destPtr; src0 = src1; src1 = *srcPtr++; @@ -993,7 +1003,7 @@ JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA): JBIG2Segment(segNumA) { size = sizeA; - bitmaps = (JBIG2Bitmap **)gmalloc(size * sizeof(JBIG2Bitmap *)); + bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); genericRegionStats = NULL; refinementRegionStats = NULL; } @@ -1037,7 +1047,7 @@ JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA): JBIG2Segment(segNumA) { size = sizeA; - bitmaps = (JBIG2Bitmap **)gmalloc(size * sizeof(JBIG2Bitmap *)); + bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); } JBIG2PatternDict::~JBIG2PatternDict() { @@ -1233,7 +1243,7 @@ void JBIG2Stream::readSegments() { } // referred-to segment numbers - refSegs = (Guint *)gmalloc(nRefSegs * sizeof(Guint)); + refSegs = (Guint *)gmallocn(nRefSegs, sizeof(Guint)); if (segNum <= 256) { for (i = 0; i < nRefSegs; ++i) { if (!readUByte(&refSegs[i])) { @@ -1273,7 +1283,9 @@ void JBIG2Stream::readSegments() { // read the segment data switch (segType) { case 0: - readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs); + if (!readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs)) { + goto syntaxError; + } break; case 4: readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs); @@ -1350,13 +1362,17 @@ void JBIG2Stream::readSegments() { return; + syntaxError: + gfree(refSegs); + return; + eofError2: gfree(refSegs); eofError1: error(getPos(), "Unexpected EOF in JBIG2 stream"); } -void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint /*length*/, +GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint /*length*/, Guint *refSegs, Guint nRefSegs) { JBIG2SymbolDict *symbolDict; JBIG2HuffmanTable *huffDHTable, *huffDWTable; @@ -1451,8 +1467,11 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint /*length*/, } // get the input symbol bitmaps - bitmaps = (JBIG2Bitmap **)gmalloc((numInputSyms + numNewSyms) * + bitmaps = (JBIG2Bitmap **)gmallocn(numInputSyms + numNewSyms, sizeof(JBIG2Bitmap *)); + for (i = 0; i < numInputSyms + numNewSyms; ++i) { + bitmaps[i] = NULL; + } k = 0; inputSymbolDict = NULL; for (i = 0; i < nRefSegs; ++i) { @@ -1527,7 +1546,7 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint /*length*/, // allocate symbol widths storage symWidths = NULL; if (huff && !refAgg) { - symWidths = (Guint *)gmalloc(numNewSyms * sizeof(Guint)); + symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint)); } symHeight = 0; @@ -1540,6 +1559,10 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint /*length*/, } else { arithDecoder->decodeInt(&dh, iadhStats); } + if (dh < 0 && (Guint)-dh >= symHeight) { + error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); + goto syntaxError; + } symHeight += dh; symWidth = 0; totalWidth = 0; @@ -1558,6 +1581,10 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint /*length*/, break; } } + if (dw < 0 && (Guint)-dw >= symWidth) { + error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); + goto syntaxError; + } symWidth += dw; // using a collective bitmap, so don't read a bitmap here @@ -1690,10 +1717,23 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint /*length*/, // store the new symbol dict segments->append(symbolDict); - return; + return gTrue; + + syntaxError: + for (i = 0; i < numNewSyms; ++i) { + if (bitmaps[numInputSyms + i]) { + delete bitmaps[numInputSyms + i]; + } + } + gfree(bitmaps); + if (symWidths) { + gfree(symWidths); + } + return gFalse; eofError: error(getPos(), "Unexpected EOF in JBIG2 stream"); + return gFalse; } void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, @@ -1773,12 +1813,15 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, codeTables = new GList(); numSyms = 0; for (i = 0; i < nRefSegs; ++i) { - seg = findSegment(refSegs[i]); + if ((seg = findSegment(refSegs[i]))) { if (seg->getType() == jbig2SegSymbolDict) { numSyms += ((JBIG2SymbolDict *)seg)->getSize(); } else if (seg->getType() == jbig2SegCodeTable) { codeTables->append(seg); } + } else { + error(getPos(), "Invalid segment reference in JBIG2 text region"); + } } symCodeLen = 0; i = 1; @@ -1788,10 +1831,10 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, } // get the symbol bitmaps - syms = (JBIG2Bitmap **)gmalloc(numSyms * sizeof(JBIG2Bitmap *)); + syms = (JBIG2Bitmap **)gmallocn(numSyms, sizeof(JBIG2Bitmap *)); kk = 0; for (i = 0; i < nRefSegs; ++i) { - seg = findSegment(refSegs[i]); + if ((seg = findSegment(refSegs[i]))) { if (seg->getType() == jbig2SegSymbolDict) { symbolDict = (JBIG2SymbolDict *)seg; for (k = 0; k < symbolDict->getSize(); ++k) { @@ -1799,6 +1842,7 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, } } } + } // get the Huffman tables huffFSTable = huffDSTable = huffDTTable = NULL; // make gcc happy @@ -1888,7 +1932,7 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, runLengthTab[35].prefixLen = 0; runLengthTab[35].rangeLen = jbig2HuffmanEOT; huffDecoder->buildTable(runLengthTab, 35); - symCodeTab = (JBIG2HuffmanTable *)gmalloc((numSyms + 1) * + symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1, sizeof(JBIG2HuffmanTable)); for (i = 0; i < numSyms; ++i) { symCodeTab[i].val = i; @@ -1964,7 +2008,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, int w, int h, Guint numInstances, Guint logStrips, - int /*numSyms*/, + int numSyms, JBIG2HuffmanTable *symCodeTab, Guint symCodeLen, JBIG2Bitmap **syms, @@ -2052,6 +2096,10 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); } + if (symID >= (Guint)numSyms) { + error(getPos(), "Invalid symbol number in JBIG2 text region"); + } else { + // get the symbol bitmap symbolBitmap = NULL; if (refine) { @@ -2132,6 +2180,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, if (ri) { delete symbolBitmap; } + } // next instance ++inst; @@ -2298,7 +2347,7 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, } // read the gray-scale image - grayImg = (Guint *)gmalloc(gridW * gridH * sizeof(Guint)); + grayImg = (Guint *)gmallocn(gridW * gridH, sizeof(Guint)); memset(grayImg, 0, gridW * gridH * sizeof(Guint)); atx[0] = templ <= 1 ? 3 : 2; aty[0] = -1; atx[1] = -3; aty[1] = -1; @@ -2451,8 +2500,8 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, if (mmr) { mmrDecoder->reset(); - refLine = (int *)gmalloc((w + 2) * sizeof(int)); - codingLine = (int *)gmalloc((w + 2) * sizeof(int)); + refLine = (int *)gmallocn(w + 2, sizeof(int)); + codingLine = (int *)gmallocn(w + 2, sizeof(int)); codingLine[0] = codingLine[1] = w; for (y = 0; y < h; ++y) { @@ -3111,14 +3160,14 @@ void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint /*length*/) { huffDecoder->reset(); huffTabSize = 8; huffTab = (JBIG2HuffmanTable *) - gmalloc(huffTabSize * sizeof(JBIG2HuffmanTable)); + gmallocn(huffTabSize, sizeof(JBIG2HuffmanTable)); i = 0; val = lowVal; while (val < highVal) { if (i == huffTabSize) { huffTabSize *= 2; huffTab = (JBIG2HuffmanTable *) - grealloc(huffTab, huffTabSize * sizeof(JBIG2HuffmanTable)); + greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); } huffTab[i].val = val; huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); @@ -3129,7 +3178,7 @@ void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint /*length*/) { if (i + oob + 3 > huffTabSize) { huffTabSize = i + oob + 3; huffTab = (JBIG2HuffmanTable *) - grealloc(huffTab, huffTabSize * sizeof(JBIG2HuffmanTable)); + greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); } huffTab[i].val = lowVal - 1; huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); diff --git a/xpdf/xpdf/JBIG2Stream.h b/xpdf/xpdf/JBIG2Stream.h index 04d8e943d..d7a538b8f 100644 --- a/xpdf/xpdf/JBIG2Stream.h +++ b/xpdf/xpdf/JBIG2Stream.h @@ -45,7 +45,7 @@ public: private: void readSegments(); - void readSymbolDictSeg(Guint segNum, Guint length, + GBool readSymbolDictSeg(Guint segNum, Guint length, Guint *refSegs, Guint nRefSegs); void readTextRegionSeg(Guint segNum, GBool imm, GBool lossless, Guint length, diff --git a/xpdf/xpdf/JPXStream.cc b/xpdf/xpdf/JPXStream.cc index 4f65b7a3d..faa61312e 100644 --- a/xpdf/xpdf/JPXStream.cc +++ b/xpdf/xpdf/JPXStream.cc @@ -243,6 +243,9 @@ JPXStream::~JPXStream() { for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) { cb = &subband->cbs[k]; gfree(cb->coeffs); + if (cb->arithDecoder) { + delete cb->arithDecoder; + } if (cb->stats) { delete cb->stats; } @@ -374,6 +377,122 @@ GBool JPXStream::isBinary(GBool /*last*/) { return str->isBinary(gTrue); } +void JPXStream::getImageParams(int *bitsPerComponent, + StreamColorSpaceMode *csMode) { + Guint boxType, boxLen, dataLen, csEnum; + Guint bpc1, dummy, i; + int csMeth, csPrec, csPrec1, dummy2; + StreamColorSpaceMode csMode1; + GBool haveBPC, haveCSMode; + + csPrec = 0; // make gcc happy + haveBPC = haveCSMode = gFalse; + str->reset(); + if (str->lookChar() == 0xff) { + getImageParams2(bitsPerComponent, csMode); + } else { + while (readBoxHdr(&boxType, &boxLen, &dataLen)) { + if (boxType == 0x6a703268) { // JP2 header + // skip the superbox + } else if (boxType == 0x69686472) { // image header + if (readULong(&dummy) && + readULong(&dummy) && + readUWord(&dummy) && + readUByte(&bpc1) && + readUByte(&dummy) && + readUByte(&dummy) && + readUByte(&dummy)) { + *bitsPerComponent = bpc1 + 1; + haveBPC = gTrue; + } + } else if (boxType == 0x636F6C72) { // color specification + if (readByte(&csMeth) && + readByte(&csPrec1) && + readByte(&dummy2)) { + if (csMeth == 1) { + if (readULong(&csEnum)) { + csMode1 = streamCSNone; + if (csEnum == jpxCSBiLevel || + csEnum == jpxCSGrayscale) { + csMode1 = streamCSDeviceGray; + } else if (csEnum == jpxCSCMYK) { + csMode1 = streamCSDeviceCMYK; + } else if (csEnum == jpxCSsRGB || + csEnum == jpxCSCISesRGB || + csEnum == jpxCSROMMRGB) { + csMode1 = streamCSDeviceRGB; + } + if (csMode1 != streamCSNone && + (!haveCSMode || csPrec1 > csPrec)) { + *csMode = csMode1; + csPrec = csPrec1; + haveCSMode = gTrue; + } + for (i = 0; i < dataLen - 7; ++i) { + str->getChar(); + } + } + } else { + for (i = 0; i < dataLen - 3; ++i) { + str->getChar(); + } + } + } + } else if (boxType == 0x6A703263) { // codestream + if (!(haveBPC && haveCSMode)) { + getImageParams2(bitsPerComponent, csMode); + } + break; + } else { + for (i = 0; i < dataLen; ++i) { + str->getChar(); + } + } + } + } + str->close(); +} + +// Get image parameters from the codestream. +void JPXStream::getImageParams2(int *bitsPerComponent, + StreamColorSpaceMode *csMode) { + int segType; + Guint segLen, nComps1, bpc1, dummy, i; + + while (readMarkerHdr(&segType, &segLen)) { + if (segType == 0x51) { // SIZ - image and tile size + if (readUWord(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readUWord(&nComps1) && + readUByte(&bpc1)) { + *bitsPerComponent = (bpc1 & 0x7f) + 1; + // if there's no color space info, take a guess + if (nComps1 == 1) { + *csMode = streamCSDeviceGray; + } else if (nComps1 == 3) { + *csMode = streamCSDeviceRGB; + } else if (nComps1 == 4) { + *csMode = streamCSDeviceCMYK; + } + } + break; + } else { + if (segLen > 2) { + for (i = 0; i < segLen - 2; ++i) { + str->getChar(); + } + } + } + } +} + GBool JPXStream::readBoxes() { Guint boxType, boxLen, dataLen; Guint bpc1, compression, unknownColorspace, ipr; @@ -388,7 +507,7 @@ GBool JPXStream::readBoxes() { error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper"); readCodestream(0); nComps = img.nComps; - bpc = (Guint *)gmalloc(nComps * sizeof(Guint)); + bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); for (i = 0; i < nComps; ++i) { bpc[i] = img.tiles[0].tileComps[i].prec; } @@ -421,7 +540,7 @@ GBool JPXStream::readBoxes() { error(getPos(), "Unknown compression type in JPX stream"); return gFalse; } - bpc = (Guint *)gmalloc(nComps * sizeof(Guint)); + bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); for (i = 0; i < nComps; ++i) { bpc[i] = bpc1; } @@ -454,9 +573,9 @@ GBool JPXStream::readBoxes() { error(getPos(), "Unexpected EOF in JPX stream"); return gFalse; } - palette.bpc = (Guint *)gmalloc(palette.nComps * sizeof(Guint)); + palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint)); palette.c = - (int *)gmalloc(palette.nEntries * palette.nComps * sizeof(int)); + (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int)); for (i = 0; i < palette.nComps; ++i) { if (!readUByte(&palette.bpc[i])) { error(getPos(), "Unexpected EOF in JPX stream"); @@ -478,9 +597,9 @@ GBool JPXStream::readBoxes() { break; case 0x636d6170: // component mapping compMap.nChannels = dataLen / 4; - compMap.comp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint)); - compMap.type = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint)); - compMap.pComp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint)); + compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); + compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); + compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); for (i = 0; i < compMap.nChannels; ++i) { if (!readUWord(&compMap.comp[i]) || !readUByte(&compMap.type[i]) || @@ -497,11 +616,11 @@ GBool JPXStream::readBoxes() { return gFalse; } channelDefn.idx = - (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint)); + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); channelDefn.type = - (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint)); + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); channelDefn.assoc = - (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint)); + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); for (i = 0; i < channelDefn.nChannels; ++i) { if (!readUWord(&channelDefn.idx[i]) || !readUWord(&channelDefn.type[i]) || @@ -515,11 +634,9 @@ GBool JPXStream::readBoxes() { case 0x6A703263: // contiguous codestream if (!bpc) { error(getPos(), "JPX stream is missing the image header box"); - return gFalse; } if (!haveCS) { error(getPos(), "JPX stream has no supported color spec"); - return gFalse; } if (!readCodestream(dataLen)) { return gFalse; @@ -582,7 +699,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) { ok = gTrue; break; case jpxCSCIELab: - if (dataLen == 3 + 7*4) { + if (dataLen == 7 + 7*4) { if (!readULong(&newCS.enumerated.cieLab.rl) || !readULong(&newCS.enumerated.cieLab.ol) || !readULong(&newCS.enumerated.cieLab.ra) || @@ -592,7 +709,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) { !readULong(&newCS.enumerated.cieLab.il)) { goto err; } - } else if (dataLen == 3) { + } else if (dataLen == 7) { //~ this assumes the 8-bit case newCS.enumerated.cieLab.rl = 100; newCS.enumerated.cieLab.ol = 0; @@ -701,10 +818,10 @@ GBool JPXStream::readCodestream(Guint /*len*/) { / img.xTileSize; img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1) / img.yTileSize; - img.tiles = (JPXTile *)gmalloc(img.nXTiles * img.nYTiles * + img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles, sizeof(JPXTile)); for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { - img.tiles[i].tileComps = (JPXTileComp *)gmalloc(img.nComps * + img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps, sizeof(JPXTileComp)); for (comp = 0; comp < img.nComps; ++comp) { img.tiles[i].tileComps[comp].quantSteps = NULL; @@ -767,8 +884,8 @@ GBool JPXStream::readCodestream(Guint /*len*/) { img.tiles[0].tileComps[0].transform; } img.tiles[i].tileComps[comp].resLevels = - (JPXResLevel *)gmalloc( - (img.tiles[i].tileComps[comp].nDecompLevels + 1) * + (JPXResLevel *)gmallocn( + (img.tiles[i].tileComps[comp].nDecompLevels + 1), sizeof(JPXResLevel)); for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; @@ -841,9 +958,9 @@ GBool JPXStream::readCodestream(Guint /*len*/) { img.tiles[0].tileComps[comp].transform; } img.tiles[i].tileComps[comp].resLevels = - (JPXResLevel *)grealloc( + (JPXResLevel *)greallocn( img.tiles[i].tileComps[comp].resLevels, - (img.tiles[i].tileComps[comp].nDecompLevels + 1) * + (img.tiles[i].tileComps[comp].nDecompLevels + 1), sizeof(JPXResLevel)); for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; @@ -881,8 +998,8 @@ GBool JPXStream::readCodestream(Guint /*len*/) { if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) { img.tiles[0].tileComps[0].nQuantSteps = segLen - 3; img.tiles[0].tileComps[0].quantSteps = - (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps, - img.tiles[0].tileComps[0].nQuantSteps * + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) { @@ -893,8 +1010,8 @@ GBool JPXStream::readCodestream(Guint /*len*/) { } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) { img.tiles[0].tileComps[0].nQuantSteps = 1; img.tiles[0].tileComps[0].quantSteps = - (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps, - img.tiles[0].tileComps[0].nQuantSteps * + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, sizeof(Guint)); if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) { error(getPos(), "Error in JPX QCD marker segment"); @@ -903,8 +1020,8 @@ GBool JPXStream::readCodestream(Guint /*len*/) { } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) { img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2; img.tiles[0].tileComps[0].quantSteps = - (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps, - img.tiles[0].tileComps[0].nQuantSteps * + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) { @@ -924,8 +1041,8 @@ GBool JPXStream::readCodestream(Guint /*len*/) { img.tiles[i].tileComps[comp].nQuantSteps = img.tiles[0].tileComps[0].nQuantSteps; img.tiles[i].tileComps[comp].quantSteps = - (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps, - img.tiles[0].tileComps[0].nQuantSteps * + (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, sizeof(Guint)); for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) { img.tiles[i].tileComps[comp].quantSteps[j] = @@ -952,8 +1069,8 @@ GBool JPXStream::readCodestream(Guint /*len*/) { img.tiles[0].tileComps[comp].nQuantSteps = segLen - (img.nComps > 256 ? 5 : 4); img.tiles[0].tileComps[comp].quantSteps = - (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps, - img.tiles[0].tileComps[comp].nQuantSteps * + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) { @@ -964,8 +1081,8 @@ GBool JPXStream::readCodestream(Guint /*len*/) { } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) { img.tiles[0].tileComps[comp].nQuantSteps = 1; img.tiles[0].tileComps[comp].quantSteps = - (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps, - img.tiles[0].tileComps[comp].nQuantSteps * + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, sizeof(Guint)); if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) { error(getPos(), "Error in JPX QCC marker segment"); @@ -975,8 +1092,8 @@ GBool JPXStream::readCodestream(Guint /*len*/) { img.tiles[0].tileComps[comp].nQuantSteps = (segLen - (img.nComps > 256 ? 5 : 4)) / 2; img.tiles[0].tileComps[comp].quantSteps = - (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps, - img.tiles[0].tileComps[comp].nQuantSteps * + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) { @@ -994,8 +1111,8 @@ GBool JPXStream::readCodestream(Guint /*len*/) { img.tiles[i].tileComps[comp].nQuantSteps = img.tiles[0].tileComps[comp].nQuantSteps; img.tiles[i].tileComps[comp].quantSteps = - (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps, - img.tiles[0].tileComps[comp].nQuantSteps * + (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, sizeof(Guint)); for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) { img.tiles[i].tileComps[comp].quantSteps[j] = @@ -1034,7 +1151,7 @@ GBool JPXStream::readCodestream(Guint /*len*/) { } #else nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); - progs = (JPXProgOrder *)gmalloc(nProgs * sizeof(JPXProgOrder)); + progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder)); for (i = 0; i < nProgs; ++i) { if (!readUByte(&progs[i].startRes) || !(img.nComps > 256 && readUWord(&progs[i].startComp)) || @@ -1231,9 +1348,9 @@ GBool JPXStream::readTilePart() { img.tiles[tileIdx].tileComps[0].transform; } img.tiles[tileIdx].tileComps[comp].resLevels = - (JPXResLevel *)grealloc( + (JPXResLevel *)greallocn( img.tiles[tileIdx].tileComps[comp].resLevels, - (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) * + (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), sizeof(JPXResLevel)); for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; @@ -1285,9 +1402,9 @@ GBool JPXStream::readTilePart() { img.tiles[tileIdx].tileComps[comp].codeBlockW += 2; img.tiles[tileIdx].tileComps[comp].codeBlockH += 2; img.tiles[tileIdx].tileComps[comp].resLevels = - (JPXResLevel *)grealloc( + (JPXResLevel *)greallocn( img.tiles[tileIdx].tileComps[comp].resLevels, - (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) * + (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), sizeof(JPXResLevel)); for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; @@ -1317,8 +1434,8 @@ GBool JPXStream::readTilePart() { img.tiles[tileIdx].tileComps[0].nQuantSteps = segLen - 3; img.tiles[tileIdx].tileComps[0].quantSteps = - (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps, - img.tiles[tileIdx].tileComps[0].nQuantSteps * + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { @@ -1329,8 +1446,8 @@ GBool JPXStream::readTilePart() { } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) { img.tiles[tileIdx].tileComps[0].nQuantSteps = 1; img.tiles[tileIdx].tileComps[0].quantSteps = - (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps, - img.tiles[tileIdx].tileComps[0].nQuantSteps * + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, sizeof(Guint)); if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) { error(getPos(), "Error in JPX QCD marker segment"); @@ -1339,8 +1456,8 @@ GBool JPXStream::readTilePart() { } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) { img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2; img.tiles[tileIdx].tileComps[0].quantSteps = - (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps, - img.tiles[tileIdx].tileComps[0].nQuantSteps * + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { @@ -1358,8 +1475,8 @@ GBool JPXStream::readTilePart() { img.tiles[tileIdx].tileComps[comp].nQuantSteps = img.tiles[tileIdx].tileComps[0].nQuantSteps; img.tiles[tileIdx].tileComps[comp].quantSteps = - (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps, - img.tiles[tileIdx].tileComps[0].nQuantSteps * + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, sizeof(Guint)); for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) { img.tiles[tileIdx].tileComps[comp].quantSteps[j] = @@ -1379,8 +1496,8 @@ GBool JPXStream::readTilePart() { img.tiles[tileIdx].tileComps[comp].nQuantSteps = segLen - (img.nComps > 256 ? 5 : 4); img.tiles[tileIdx].tileComps[comp].quantSteps = - (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps, - img.tiles[tileIdx].tileComps[comp].nQuantSteps * + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { @@ -1392,8 +1509,8 @@ GBool JPXStream::readTilePart() { == 0x01) { img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1; img.tiles[tileIdx].tileComps[comp].quantSteps = - (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps, - img.tiles[tileIdx].tileComps[comp].nQuantSteps * + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, sizeof(Guint)); if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) { error(getPos(), "Error in JPX QCC marker segment"); @@ -1404,8 +1521,8 @@ GBool JPXStream::readTilePart() { img.tiles[tileIdx].tileComps[comp].nQuantSteps = (segLen - (img.nComps > 256 ? 5 : 4)) / 2; img.tiles[tileIdx].tileComps[comp].quantSteps = - (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps, - img.tiles[tileIdx].tileComps[comp].nQuantSteps * + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { @@ -1449,7 +1566,7 @@ GBool JPXStream::readTilePart() { } #else nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); - tileProgs = (JPXProgOrder *)gmalloc(nTileProgs * sizeof(JPXProgOrder)); + tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder)); for (i = 0; i < nTileProgs; ++i) { if (!readUByte(&tileProgs[i].startRes) || !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) || @@ -1541,15 +1658,15 @@ GBool JPXStream::readTilePart() { tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep); tileComp->cbW = 1 << tileComp->codeBlockW; tileComp->cbH = 1 << tileComp->codeBlockH; - tileComp->data = (int *)gmalloc((tileComp->x1 - tileComp->x0) * - (tileComp->y1 - tileComp->y0) * + tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) * + (tileComp->y1 - tileComp->y0), sizeof(int)); if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { n = tileComp->x1 - tileComp->x0; } else { n = tileComp->y1 - tileComp->y0; } - tileComp->buf = (int *)gmalloc((n + 8) * sizeof(int)); + tileComp->buf = (int *)gmallocn(n + 8, sizeof(int)); for (r = 0; r <= tileComp->nDecompLevels; ++r) { resLevel = &tileComp->resLevels[r]; k = r == 0 ? tileComp->nDecompLevels @@ -1577,7 +1694,7 @@ GBool JPXStream::readTilePart() { resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); } - resLevel->precincts = (JPXPrecinct *)gmalloc(1 * sizeof(JPXPrecinct)); + resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct)); for (pre = 0; pre < 1; ++pre) { precinct = &resLevel->precincts[pre]; precinct->x0 = resLevel->x0; @@ -1586,7 +1703,7 @@ GBool JPXStream::readTilePart() { precinct->y1 = resLevel->y1; nSBs = r == 0 ? 1 : 3; precinct->subbands = - (JPXSubband *)gmalloc(nSBs * sizeof(JPXSubband)); + (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband)); for (sb = 0; sb < nSBs; ++sb) { subband = &precinct->subbands[sb]; subband->x0 = resLevel->bx0[sb]; @@ -1613,17 +1730,17 @@ GBool JPXStream::readTilePart() { n += nx * ny; } subband->inclusion = - (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode)); + (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); subband->zeroBitPlane = - (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode)); + (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); for (k = 0; k < n; ++k) { subband->inclusion[k].finished = gFalse; subband->inclusion[k].val = 0; subband->zeroBitPlane[k].finished = gFalse; subband->zeroBitPlane[k].val = 0; } - subband->cbs = (JPXCodeBlock *)gmalloc(subband->nXCBs * - subband->nYCBs * + subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs * + subband->nYCBs, sizeof(JPXCodeBlock)); sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW); sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH); @@ -1651,9 +1768,9 @@ GBool JPXStream::readTilePart() { cb->nextPass = jpxPassCleanup; cb->nZeroBitPlanes = 0; cb->coeffs = - (JPXCoeff *)gmalloc((1 << (tileComp->codeBlockW - + tileComp->codeBlockH)) - * sizeof(JPXCoeff)); + (JPXCoeff *)gmallocn((1 << (tileComp->codeBlockW + + tileComp->codeBlockH)), + sizeof(JPXCoeff)); for (cbi = 0; cbi < (Guint)(1 << (tileComp->codeBlockW + tileComp->codeBlockH)); @@ -1662,10 +1779,8 @@ GBool JPXStream::readTilePart() { cb->coeffs[cbi].len = 0; cb->coeffs[cbi].mag = 0; } - cb->stats = new JArithmeticDecoderStats(jpxNContexts); - cb->stats->setEntry(jpxContextSigProp, 4, 0); - cb->stats->setEntry(jpxContextRunLength, 3, 0); - cb->stats->setEntry(jpxContextUniform, 46, 0); + cb->arithDecoder = NULL; + cb->stats = NULL; ++cb; } } @@ -1963,14 +2078,21 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, Guint res, Guint sb, JPXCodeBlock *cb) { JPXCoeff *coeff0, *coeff1, *coeff; - JArithmeticDecoder *arithDecoder; Guint horiz, vert, diag, all, cx, xorBit; int horizSign, vertSign; Guint i, x, y0, y1, y2; - arithDecoder = new JArithmeticDecoder(); - arithDecoder->setStream(str, cb->dataLen); - arithDecoder->start(); + if (cb->arithDecoder) { + cb->arithDecoder->restart(cb->dataLen); + } else { + cb->arithDecoder = new JArithmeticDecoder(); + cb->arithDecoder->setStream(str, cb->dataLen); + cb->arithDecoder->start(); + cb->stats = new JArithmeticDecoderStats(jpxNContexts); + cb->stats->setEntry(jpxContextSigProp, 4, 0); + cb->stats->setEntry(jpxContextRunLength, 3, 0); + cb->stats->setEntry(jpxContextUniform, 46, 0); + } for (i = 0; i < cb->nCodingPasses; ++i) { switch (cb->nextPass) { @@ -2033,12 +2155,12 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; if (cx != 0) { - if (arithDecoder->decodeBit(cx, cb->stats)) { + if (cb->arithDecoder->decodeBit(cx, cb->stats)) { coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; coeff->mag = (coeff->mag << 1) | 1; cx = signContext[horizSign][vertSign][0]; xorBit = signContext[horizSign][vertSign][1]; - if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { coeff->flags |= jpxCoeffSign; } } @@ -2102,7 +2224,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, cx = 16; } coeff->mag = (coeff->mag << 1) | - arithDecoder->decodeBit(cx, cb->stats); + cb->arithDecoder->decodeBit(cx, cb->stats); ++coeff->len; coeff->flags |= jpxCoeffTouched; coeff->flags &= ~jpxCoeffFirstMagRef; @@ -2131,9 +2253,11 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, !(coeff1[-(int)tileComp->cbW - 1].flags & jpxCoeffSignificant)) && (y0 == cb->y0 || - !(coeff1[-(int)tileComp->cbW].flags & jpxCoeffSignificant)) && + !(coeff1[-(int)tileComp->cbW].flags + & jpxCoeffSignificant)) && (x == cb->x1 - 1 || y0 == cb->y0 || - !(coeff1[-(int)tileComp->cbW + 1].flags & jpxCoeffSignificant)) && + !(coeff1[-(int)tileComp->cbW + 1].flags + & jpxCoeffSignificant)) && (x == cb->x0 || (!(coeff1[-1].flags & jpxCoeffSignificant) && !(coeff1[tileComp->cbW - 1].flags @@ -2157,10 +2281,10 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, (x == cb->x1 - 1 || y0+4 == cb->y1 || !(coeff1[4 * tileComp->cbW + 1].flags & jpxCoeffSignificant))) { - if (arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) { - y1 = arithDecoder->decodeBit(jpxContextUniform, cb->stats); + if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) { + y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); y1 = (y1 << 1) | - arithDecoder->decodeBit(jpxContextUniform, cb->stats); + cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); for (y2 = 0, coeff = coeff1; y2 < y1; ++y2, coeff += tileComp->cbW) { @@ -2171,7 +2295,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, ++coeff->len; cx = signContext[2][2][0]; xorBit = signContext[2][2][1]; - if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { coeff->flags |= jpxCoeffSign; } ++y1; @@ -2233,12 +2357,12 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } } cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; - if (arithDecoder->decodeBit(cx, cb->stats)) { + if (cb->arithDecoder->decodeBit(cx, cb->stats)) { coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; coeff->mag = (coeff->mag << 1) | 1; cx = signContext[horizSign][vertSign][0]; xorBit = signContext[horizSign][vertSign][1]; - if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { coeff->flags |= jpxCoeffSign; } } @@ -2254,7 +2378,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } } - delete arithDecoder; + cb->arithDecoder->cleanup(); return gTrue; } @@ -2266,7 +2390,8 @@ void JPXStream::inverseTransform(JPXTileComp *tileComp) { JPXSubband *subband; JPXCodeBlock *cb; JPXCoeff *coeff0, *coeff; - Guint qStyle, guard, eps, shift, shift2; + Guint qStyle, guard, eps, shift; + int shift2; double mu; int val; int *dataPtr; @@ -2368,7 +2493,8 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, JPXSubband *subband; JPXCodeBlock *cb; JPXCoeff *coeff0, *coeff; - Guint qStyle, guard, eps, shift, shift2, t; + Guint qStyle, guard, eps, shift, t; + int shift2; double mu; int val; int *dataPtr; @@ -2578,7 +2704,7 @@ void JPXStream::inverseTransform1D(JPXTileComp *tileComp, // converts fixed point samples back to integers. GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { JPXTileComp *tileComp; - int coeff, d0, d1, d2, minVal, maxVal, zeroVal; + int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal; int *dataPtr; Guint j, comp, x, y; @@ -2617,9 +2743,9 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { d0 = tile->tileComps[0].data[j]; d1 = tile->tileComps[1].data[j]; d2 = tile->tileComps[2].data[j]; - tile->tileComps[0].data[j] = d0 - ((d2 + d1) >> 2); - tile->tileComps[1].data[j] = d2 - d1; - tile->tileComps[2].data[j] = d0 - d1; + tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2); + tile->tileComps[0].data[j] = d2 + t; + tile->tileComps[2].data[j] = d1 + t; ++j; } } diff --git a/xpdf/xpdf/JPXStream.h b/xpdf/xpdf/JPXStream.h index 9b9880b3b..3bc56e0fa 100644 --- a/xpdf/xpdf/JPXStream.h +++ b/xpdf/xpdf/JPXStream.h @@ -44,18 +44,22 @@ enum JPXColorSpaceType { jpxCSYPbPr1250 = 24 }; +struct JPXColorSpecCIELab { + Guint rl, ol, ra, oa, rb, ob, il; +}; + +struct JPXColorSpecEnumerated { + JPXColorSpaceType type; // color space type + union { + JPXColorSpecCIELab cieLab; + }; +}; + struct JPXColorSpec { Guint meth; // method int prec; // precedence union { - struct { - JPXColorSpaceType type; // color space type - union { - struct { - Guint rl, ol, ra, oa, rb, ob, il; - } cieLab; - }; - } enumerated; + JPXColorSpecEnumerated enumerated; }; }; @@ -135,6 +139,8 @@ struct JPXCodeBlock { //----- coefficient data JPXCoeff *coeffs; // the coefficients + JArithmeticDecoder // arithmetic decoder + *arithDecoder; JArithmeticDecoderStats // arithmetic decoder stats *stats; }; @@ -275,10 +281,13 @@ public: virtual int lookChar(); virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); + virtual void getImageParams(int *bitsPerComponent, + StreamColorSpaceMode *csMode); private: void fillReadBuf(); + void getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode); GBool readBoxes(); GBool readColorSpecBox(Guint dataLen); GBool readCodestream(Guint len); diff --git a/xpdf/xpdf/Lexer.cc b/xpdf/xpdf/Lexer.cc index 6121fc414..7cef92178 100644 --- a/xpdf/xpdf/Lexer.cc +++ b/xpdf/xpdf/Lexer.cc @@ -171,6 +171,13 @@ Object *Lexer::getObj(Object *obj) { scale = 0.1; while (1) { c = lookChar(); + if (c == '-') { + // ignore minus signs in the middle of numbers to match + // Adobe's behavior + error(getPos(), "Badly formatted number"); + getChar(); + continue; + } if (!isdigit(c)) { break; } @@ -472,3 +479,7 @@ void Lexer::skipToNextLine() { } } } + +GBool Lexer::isSpace(int c) { + return c >= 0 && c <= 0xff && Lexer_specialChars[c] == 1; +} diff --git a/xpdf/xpdf/Lexer.h b/xpdf/xpdf/Lexer.h index 398d27c35..f6ad9ce96 100644 --- a/xpdf/xpdf/Lexer.h +++ b/xpdf/xpdf/Lexer.h @@ -62,6 +62,9 @@ public: void setPos(Guint pos, int dir = 0) { if (!curStr.isNone()) curStr.streamSetPos(pos, dir); } + // Returns true if is a whitespace character. + static GBool isSpace(int c); + private: int getChar(); diff --git a/xpdf/xpdf/Link.cc b/xpdf/xpdf/Link.cc index 77b02f5d0..26f3054d5 100644 --- a/xpdf/xpdf/Link.cc +++ b/xpdf/xpdf/Link.cc @@ -117,14 +117,19 @@ GString *LinkAction::getFileSpecName(Object *fileSpecObj) { // dictionary } else if (fileSpecObj->isDict()) { +#ifdef WIN32 + if (!fileSpecObj->dictLookup("DOS", &obj1)->isString()) { +#else if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { +#endif obj1.free(); fileSpecObj->dictLookup("F", &obj1); } - if (obj1.isString()) + if (obj1.isString()) { name = obj1.getString()->copy(); - else + } else { error(-1, "Illegal file spec in link"); + } obj1.free(); // error @@ -132,6 +137,55 @@ GString *LinkAction::getFileSpecName(Object *fileSpecObj) { error(-1, "Illegal file spec in link"); } + // system-dependent path manipulation + if (name) { +#ifdef WIN32 + int i, j; + + // "//...." --> "\...." + // "/x/...." --> "x:\...." + // "/server/share/...." --> "\\server\share\...." + // convert escaped slashes to slashes and unescaped slashes to backslashes + i = 0; + if (name->getChar(0) == '/') { + if (name->getLength() >= 2 && name->getChar(1) == '/') { + name->del(0); + i = 0; + } else if (name->getLength() >= 2 && + ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') || + (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) && + (name->getLength() == 2 || name->getChar(2) == '/')) { + name->setChar(0, name->getChar(1)); + name->setChar(1, ':'); + i = 2; + } else { + for (j = 2; j < name->getLength(); ++j) { + if (name->getChar(j-1) != '\\' && + name->getChar(j) == '/') { + break; + } + } + if (j < name->getLength()) { + name->setChar(0, '\\'); + name->insert(0, '\\'); + i = 2; + } + } + } + for (; i < name->getLength(); ++i) { + if (name->getChar(i) == '/') { + name->setChar(i, '\\'); + } else if (name->getChar(i) == '\\' && + i+1 < name->getLength() && + name->getChar(i+1) == '/') { + name->del(i); + } + } +#else + // no manipulation needed for Unix +#endif + } + return name; } @@ -497,7 +551,7 @@ LinkURI::LinkURI(Object *uriObj, GString *baseURI) { uri = NULL; if (uriObj->isString()) { uri2 = uriObj->getString()->copy(); - if (baseURI) { + if (baseURI && baseURI->getLength() > 0) { n = strcspn(uri2->getCString(), "/:"); if (n == uri2->getLength() || uri2->getChar(n) == '/') { uri = baseURI->copy(); @@ -690,7 +744,7 @@ Link::Link(Dict *dict, GString *baseURI) { obj2.free(); if (obj1.dictLookup("D", &obj2)->isArray()) { borderDashLength = obj2.arrayGetLength(); - borderDash = (double *)gmalloc(borderDashLength * sizeof(double)); + borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); for (i = 0; i < borderDashLength; ++i) { if (obj2.arrayGet(i, &obj3)->isNum()) { borderDash[i] = obj3.getNum(); @@ -713,7 +767,7 @@ Link::Link(Dict *dict, GString *baseURI) { if (obj1.arrayGet(3, &obj2)->isArray()) { borderType = linkBorderDashed; borderDashLength = obj2.arrayGetLength(); - borderDash = (double *)gmalloc(borderDashLength * sizeof(double)); + borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); for (i = 0; i < borderDashLength; ++i) { if (obj2.arrayGet(i, &obj3)->isNum()) { borderDash[i] = obj3.getNum(); @@ -722,6 +776,10 @@ Link::Link(Dict *dict, GString *baseURI) { } obj3.free(); } + } else { + // Adobe draws no border at all if the last element is of + // the wrong type. + borderWidth = 0; } obj2.free(); } @@ -805,7 +863,7 @@ Links::Links(Object *annots, GString *baseURI) { if (link->isOk()) { if (numLinks >= size) { size += 16; - links = (Link **)grealloc(links, size * sizeof(Link *)); + links = (Link **)greallocn(links, size, sizeof(Link *)); } links[numLinks++] = link; } else { diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am index 97a2ada5f..db2709e24 100644 --- a/xpdf/xpdf/Makefile.am +++ b/xpdf/xpdf/Makefile.am @@ -8,7 +8,7 @@ libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ GfxFont.cc GfxState.cc GlobalParams.cc JArithmeticDecoder.cc \ JBIG2Stream.cc Lexer.cc Link.cc NameToCharCode.cc Object.cc Outline.cc \ OutputDev.cc PDFDoc.cc PDFDocEncoding.cc PSTokenizer.cc \ - Page.cc Parser.cc PSOutputDev.cc SplashOutputDev.cc Stream.cc JPXStream.cc \ + Page.cc Parser.cc PSOutputDev.cc SecurityHandler.cc SplashOutputDev.cc Stream.cc JPXStream.cc \ TextOutputDev.cc UnicodeMap.cc UnicodeTypeTable.cc XRef.cc noinst_LTLIBRARIES = libxpdf.la diff --git a/xpdf/xpdf/NameToCharCode.cc b/xpdf/xpdf/NameToCharCode.cc index ecc62582a..a2438cb96 100644 --- a/xpdf/xpdf/NameToCharCode.cc +++ b/xpdf/xpdf/NameToCharCode.cc @@ -30,7 +30,7 @@ NameToCharCode::NameToCharCode() { size = 31; len = 0; - tab = (NameToCharCodeEntry *)gmalloc(size * sizeof(NameToCharCodeEntry)); + tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); for (i = 0; i < size; ++i) { tab[i].name = NULL; } @@ -56,7 +56,7 @@ void NameToCharCode::add(const char *name, CharCode c) { oldSize = size; oldTab = tab; size = 2*size + 1; - tab = (NameToCharCodeEntry *)gmalloc(size * sizeof(NameToCharCodeEntry)); + tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); for (h = 0; h < size; ++h) { tab[h].name = NULL; } diff --git a/xpdf/xpdf/NameToUnicodeTable.h b/xpdf/xpdf/NameToUnicodeTable.h index 6c24d12b3..7ef1cf029 100644 --- a/xpdf/xpdf/NameToUnicodeTable.h +++ b/xpdf/xpdf/NameToUnicodeTable.h @@ -2,7 +2,7 @@ // // NameToUnicodeTable.h // -// Copyright 2001-2003 Glyph & Cog, LLC +// Copyright 2001-2004 Glyph & Cog, LLC // //======================================================================== @@ -44,45 +44,45 @@ static struct { {0x0041, "A"}, {0x00c6, "AE"}, {0x01fc, "AEacute"}, - {0x00c6, "AEsmall"}, + {0xf7e6, "AEsmall"}, {0x00c1, "Aacute"}, - {0x00c1, "Aacutesmall"}, + {0xf7e1, "Aacutesmall"}, {0x0102, "Abreve"}, {0x00c2, "Acircumflex"}, - {0x00c2, "Acircumflexsmall"}, + {0xf7e2, "Acircumflexsmall"}, {0xf6c9, "Acute"}, - {0xf6c9, "Acutesmall"}, + {0xf7b4, "Acutesmall"}, {0x00c4, "Adieresis"}, - {0x00c4, "Adieresissmall"}, + {0xf7e4, "Adieresissmall"}, {0x00c0, "Agrave"}, - {0x00c0, "Agravesmall"}, + {0xf7e0, "Agravesmall"}, {0x0391, "Alpha"}, {0x0386, "Alphatonos"}, {0x0100, "Amacron"}, {0x0104, "Aogonek"}, {0x00c5, "Aring"}, {0x01fa, "Aringacute"}, - {0x00c5, "Aringsmall"}, - {0x0041, "Asmall"}, + {0xf7e5, "Aringsmall"}, + {0xf761, "Asmall"}, {0x00c3, "Atilde"}, - {0x00c3, "Atildesmall"}, + {0xf7e3, "Atildesmall"}, {0x0042, "B"}, {0x0392, "Beta"}, {0xf6f4, "Brevesmall"}, - {0x0042, "Bsmall"}, + {0xf762, "Bsmall"}, {0x0043, "C"}, {0x0106, "Cacute"}, {0xf6ca, "Caron"}, - {0xf6ca, "Caronsmall"}, + {0xf6f5, "Caronsmall"}, {0x010c, "Ccaron"}, {0x00c7, "Ccedilla"}, - {0x00c7, "Ccedillasmall"}, + {0xf7e7, "Ccedillasmall"}, {0x0108, "Ccircumflex"}, {0x010a, "Cdotaccent"}, {0xf7b8, "Cedillasmall"}, {0x03a7, "Chi"}, {0xf6f6, "Circumflexsmall"}, - {0x0043, "Csmall"}, + {0xf763, "Csmall"}, {0x0044, "D"}, {0x010e, "Dcaron"}, {0x0110, "Dcroat"}, @@ -90,34 +90,34 @@ static struct { {0xf6cb, "Dieresis"}, {0xf6cc, "DieresisAcute"}, {0xf6cd, "DieresisGrave"}, - {0xf6cb, "Dieresissmall"}, + {0xf7a8, "Dieresissmall"}, {0xf6f7, "Dotaccentsmall"}, - {0x0044, "Dsmall"}, + {0xf764, "Dsmall"}, {0x0045, "E"}, {0x00c9, "Eacute"}, - {0x00c9, "Eacutesmall"}, + {0xf7e9, "Eacutesmall"}, {0x0114, "Ebreve"}, {0x011a, "Ecaron"}, {0x00ca, "Ecircumflex"}, - {0x00ca, "Ecircumflexsmall"}, + {0xf7ea, "Ecircumflexsmall"}, {0x00cb, "Edieresis"}, - {0x00cb, "Edieresissmall"}, + {0xf7eb, "Edieresissmall"}, {0x0116, "Edotaccent"}, {0x00c8, "Egrave"}, - {0x00c8, "Egravesmall"}, + {0xf7e8, "Egravesmall"}, {0x0112, "Emacron"}, {0x014a, "Eng"}, {0x0118, "Eogonek"}, {0x0395, "Epsilon"}, {0x0388, "Epsilontonos"}, - {0x0045, "Esmall"}, + {0xf765, "Esmall"}, {0x0397, "Eta"}, {0x0389, "Etatonos"}, {0x00d0, "Eth"}, - {0x00d0, "Ethsmall"}, + {0xf7f0, "Ethsmall"}, {0x20ac, "Euro"}, {0x0046, "F"}, - {0x0046, "Fsmall"}, + {0xf766, "Fsmall"}, {0x0047, "G"}, {0x0393, "Gamma"}, {0x011e, "Gbreve"}, @@ -126,8 +126,8 @@ static struct { {0x0122, "Gcommaaccent"}, {0x0120, "Gdotaccent"}, {0xf6ce, "Grave"}, - {0xf6ce, "Gravesmall"}, - {0x0047, "Gsmall"}, + {0xf760, "Gravesmall"}, + {0xf767, "Gsmall"}, {0x0048, "H"}, {0x25cf, "H18533"}, {0x25aa, "H18543"}, @@ -135,36 +135,36 @@ static struct { {0x25a1, "H22073"}, {0x0126, "Hbar"}, {0x0124, "Hcircumflex"}, - {0x0048, "Hsmall"}, + {0xf768, "Hsmall"}, {0xf6cf, "Hungarumlaut"}, - {0xf6cf, "Hungarumlautsmall"}, + {0xf6f8, "Hungarumlautsmall"}, {0x0049, "I"}, {0x0132, "IJ"}, {0x00cd, "Iacute"}, - {0x00cd, "Iacutesmall"}, + {0xf7ed, "Iacutesmall"}, {0x012c, "Ibreve"}, {0x00ce, "Icircumflex"}, - {0x00ce, "Icircumflexsmall"}, + {0xf7ee, "Icircumflexsmall"}, {0x00cf, "Idieresis"}, - {0x00cf, "Idieresissmall"}, + {0xf7ef, "Idieresissmall"}, {0x0130, "Idotaccent"}, {0x2111, "Ifraktur"}, {0x00cc, "Igrave"}, - {0x00cc, "Igravesmall"}, + {0xf7ec, "Igravesmall"}, {0x012a, "Imacron"}, {0x012e, "Iogonek"}, {0x0399, "Iota"}, {0x03aa, "Iotadieresis"}, {0x038a, "Iotatonos"}, - {0x0049, "Ismall"}, + {0xf769, "Ismall"}, {0x0128, "Itilde"}, {0x004a, "J"}, {0x0134, "Jcircumflex"}, - {0x004a, "Jsmall"}, + {0xf76a, "Jsmall"}, {0x004b, "K"}, {0x039a, "Kappa"}, {0x0136, "Kcommaaccent"}, - {0x004b, "Ksmall"}, + {0xf76b, "Ksmall"}, {0x004c, "L"}, {0xf6bf, "LL"}, {0x0139, "Lacute"}, @@ -173,34 +173,34 @@ static struct { {0x013b, "Lcommaaccent"}, {0x013f, "Ldot"}, {0x0141, "Lslash"}, - {0x0141, "Lslashsmall"}, - {0x004c, "Lsmall"}, + {0xf6f9, "Lslashsmall"}, + {0xf76c, "Lsmall"}, {0x004d, "M"}, {0xf6d0, "Macron"}, - {0xf6d0, "Macronsmall"}, - {0x004d, "Msmall"}, + {0xf7af, "Macronsmall"}, + {0xf76d, "Msmall"}, {0x039c, "Mu"}, {0x004e, "N"}, {0x0143, "Nacute"}, {0x0147, "Ncaron"}, {0x0145, "Ncommaaccent"}, - {0x004e, "Nsmall"}, + {0xf76e, "Nsmall"}, {0x00d1, "Ntilde"}, - {0x00d1, "Ntildesmall"}, + {0xf7f1, "Ntildesmall"}, {0x039d, "Nu"}, {0x004f, "O"}, {0x0152, "OE"}, - {0x0152, "OEsmall"}, + {0xf6fa, "OEsmall"}, {0x00d3, "Oacute"}, - {0x00d3, "Oacutesmall"}, + {0xf7f3, "Oacutesmall"}, {0x014e, "Obreve"}, {0x00d4, "Ocircumflex"}, - {0x00d4, "Ocircumflexsmall"}, + {0xf7f4, "Ocircumflexsmall"}, {0x00d6, "Odieresis"}, - {0x00d6, "Odieresissmall"}, + {0xf7f6, "Odieresissmall"}, {0xf6fb, "Ogoneksmall"}, {0x00d2, "Ograve"}, - {0x00d2, "Ogravesmall"}, + {0xf7f2, "Ogravesmall"}, {0x01a0, "Ohorn"}, {0x0150, "Ohungarumlaut"}, {0x014c, "Omacron"}, @@ -210,17 +210,17 @@ static struct { {0x038c, "Omicrontonos"}, {0x00d8, "Oslash"}, {0x01fe, "Oslashacute"}, - {0x00d8, "Oslashsmall"}, - {0x004f, "Osmall"}, + {0xf7f8, "Oslashsmall"}, + {0xf76f, "Osmall"}, {0x00d5, "Otilde"}, - {0x00d5, "Otildesmall"}, + {0xf7f5, "Otildesmall"}, {0x0050, "P"}, {0x03a6, "Phi"}, {0x03a0, "Pi"}, {0x03a8, "Psi"}, - {0x0050, "Psmall"}, + {0xf770, "Psmall"}, {0x0051, "Q"}, - {0x0051, "Qsmall"}, + {0xf771, "Qsmall"}, {0x0052, "R"}, {0x0154, "Racute"}, {0x0158, "Rcaron"}, @@ -228,7 +228,7 @@ static struct { {0x211c, "Rfraktur"}, {0x03a1, "Rho"}, {0xf6fc, "Ringsmall"}, - {0x0052, "Rsmall"}, + {0xf772, "Rsmall"}, {0x0053, "S"}, {0x250c, "SF010000"}, {0x2514, "SF020000"}, @@ -272,12 +272,12 @@ static struct { {0x256a, "SF540000"}, {0x015a, "Sacute"}, {0x0160, "Scaron"}, - {0x0160, "Scaronsmall"}, + {0xf6fd, "Scaronsmall"}, {0x015e, "Scedilla"}, {0x015c, "Scircumflex"}, {0x0218, "Scommaaccent"}, {0x03a3, "Sigma"}, - {0x0053, "Ssmall"}, + {0xf773, "Ssmall"}, {0x0054, "T"}, {0x03a4, "Tau"}, {0x0166, "Tbar"}, @@ -285,19 +285,19 @@ static struct { {0x0162, "Tcommaaccent"}, {0x0398, "Theta"}, {0x00de, "Thorn"}, - {0x00de, "Thornsmall"}, + {0xf7fe, "Thornsmall"}, {0xf6fe, "Tildesmall"}, - {0x0054, "Tsmall"}, + {0xf774, "Tsmall"}, {0x0055, "U"}, {0x00da, "Uacute"}, - {0x00da, "Uacutesmall"}, + {0xf7fa, "Uacutesmall"}, {0x016c, "Ubreve"}, {0x00db, "Ucircumflex"}, - {0x00db, "Ucircumflexsmall"}, + {0xf7fb, "Ucircumflexsmall"}, {0x00dc, "Udieresis"}, - {0x00dc, "Udieresissmall"}, + {0xf7fc, "Udieresissmall"}, {0x00d9, "Ugrave"}, - {0x00d9, "Ugravesmall"}, + {0xf7f9, "Ugravesmall"}, {0x01af, "Uhorn"}, {0x0170, "Uhungarumlaut"}, {0x016a, "Umacron"}, @@ -307,34 +307,34 @@ static struct { {0x03ab, "Upsilondieresis"}, {0x038e, "Upsilontonos"}, {0x016e, "Uring"}, - {0x0055, "Usmall"}, + {0xf775, "Usmall"}, {0x0168, "Utilde"}, {0x0056, "V"}, - {0x0056, "Vsmall"}, + {0xf776, "Vsmall"}, {0x0057, "W"}, {0x1e82, "Wacute"}, {0x0174, "Wcircumflex"}, {0x1e84, "Wdieresis"}, {0x1e80, "Wgrave"}, - {0x0057, "Wsmall"}, + {0xf777, "Wsmall"}, {0x0058, "X"}, {0x039e, "Xi"}, - {0x0058, "Xsmall"}, + {0xf778, "Xsmall"}, {0x0059, "Y"}, {0x00dd, "Yacute"}, - {0x00dd, "Yacutesmall"}, + {0xf7fd, "Yacutesmall"}, {0x0176, "Ycircumflex"}, {0x0178, "Ydieresis"}, - {0x0178, "Ydieresissmall"}, + {0xf7ff, "Ydieresissmall"}, {0x1ef2, "Ygrave"}, - {0x0059, "Ysmall"}, + {0xf779, "Ysmall"}, {0x005a, "Z"}, {0x0179, "Zacute"}, {0x017d, "Zcaron"}, - {0x017d, "Zcaronsmall"}, + {0xf6ff, "Zcaronsmall"}, {0x017b, "Zdotaccent"}, {0x0396, "Zeta"}, - {0x005a, "Zsmall"}, + {0xf77a, "Zsmall"}, {0x0022, "\""}, {0x005c, "\\"}, {0x005d, "]"}, @@ -601,7 +601,7 @@ static struct { {0x03ac, "alphatonos"}, {0x0101, "amacron"}, {0x0026, "ampersand"}, - {0x0026, "ampersandsmall"}, + {0xf726, "ampersandsmall"}, {0x2220, "angle"}, {0x2329, "angleleft"}, {0x232a, "angleright"}, @@ -668,7 +668,7 @@ static struct { {0x00b8, "cedilla"}, {0x00a2, "cent"}, {0xf6df, "centinferior"}, - {0x00a2, "centoldstyle"}, + {0xf7a2, "centoldstyle"}, {0xf6e0, "centsuperior"}, {0x03c7, "chi"}, {0x25cb, "circle"}, @@ -710,7 +710,7 @@ static struct { {0x2584, "dnblock"}, {0x0024, "dollar"}, {0xf6e3, "dollarinferior"}, - {0x0024, "dollaroldstyle"}, + {0xf724, "dollaroldstyle"}, {0xf6e4, "dollarsuperior"}, {0x20ab, "dong"}, {0x02d9, "dotaccent"}, @@ -729,7 +729,7 @@ static struct { {0x00e8, "egrave"}, {0x0038, "eight"}, {0x2088, "eightinferior"}, - {0x0038, "eightoldstyle"}, + {0xf738, "eightoldstyle"}, {0x2078, "eightsuperior"}, {0x2208, "element"}, {0x2026, "ellipsis"}, @@ -751,9 +751,9 @@ static struct { {0x0021, "exclam"}, {0x203c, "exclamdbl"}, {0x00a1, "exclamdown"}, - {0x00a1, "exclamdownsmall"}, + {0xf7a1, "exclamdownsmall"}, {0x0021, "exclamleft"}, - {0x0021, "exclamsmall"}, + {0xf721, "exclamsmall"}, {0x2203, "existential"}, {0x0066, "f"}, {0x2640, "female"}, @@ -767,13 +767,13 @@ static struct { {0x0035, "five"}, {0x215d, "fiveeighths"}, {0x2085, "fiveinferior"}, - {0x0035, "fiveoldstyle"}, + {0xf735, "fiveoldstyle"}, {0x2075, "fivesuperior"}, {0xfb02, "fl"}, {0x0192, "florin"}, {0x0034, "four"}, {0x2084, "fourinferior"}, - {0x0034, "fouroldstyle"}, + {0xf734, "fouroldstyle"}, {0x2074, "foursuperior"}, {0x2044, "fraction"}, {0x20a3, "franc"}, @@ -871,7 +871,7 @@ static struct { {0x0146, "ncommaaccent"}, {0x0039, "nine"}, {0x2089, "nineinferior"}, - {0x0039, "nineoldstyle"}, + {0xf739, "nineoldstyle"}, {0x2079, "ninesuperior"}, {0x00a0, "nonbreakingspace"}, {0x2209, "notelement"}, @@ -903,7 +903,7 @@ static struct { {0xf6dc, "onefitted"}, {0x00bd, "onehalf"}, {0x2081, "oneinferior"}, - {0x0031, "oneoldstyle"}, + {0xf731, "oneoldstyle"}, {0x00bc, "onequarter"}, {0x00b9, "onesuperior"}, {0x2153, "onethird"}, @@ -952,8 +952,8 @@ static struct { {0x0071, "q"}, {0x003f, "question"}, {0x00bf, "questiondown"}, - {0x00bf, "questiondownsmall"}, - {0x003f, "questionsmall"}, + {0xf7bf, "questiondownsmall"}, + {0xf73f, "questionsmall"}, {0x0022, "quotedbl"}, {0x201e, "quotedblbase"}, {0x201c, "quotedblleft"}, @@ -992,7 +992,7 @@ static struct { {0x0037, "seven"}, {0x215e, "seveneighths"}, {0x2087, "seveninferior"}, - {0x0037, "sevenoldstyle"}, + {0xf737, "sevenoldstyle"}, {0x2077, "sevensuperior"}, {0x2592, "shade"}, {0x03c3, "sigma"}, @@ -1000,7 +1000,7 @@ static struct { {0x223c, "similar"}, {0x0036, "six"}, {0x2086, "sixinferior"}, - {0x0036, "sixoldstyle"}, + {0xf736, "sixoldstyle"}, {0x2076, "sixsuperior"}, {0x002f, "slash"}, {0x263a, "smileface"}, @@ -1023,7 +1023,7 @@ static struct { {0x0033, "three"}, {0x215c, "threeeighths"}, {0x2083, "threeinferior"}, - {0x0033, "threeoldstyle"}, + {0xf733, "threeoldstyle"}, {0x00be, "threequarters"}, {0xf6de, "threequartersemdash"}, {0x00b3, "threesuperior"}, @@ -1041,7 +1041,7 @@ static struct { {0x0032, "two"}, {0x2025, "twodotenleader"}, {0x2082, "twoinferior"}, - {0x0032, "twooldstyle"}, + {0xf732, "twooldstyle"}, {0x00b2, "twosuperior"}, {0x2154, "twothirds"}, {0x0075, "u"}, @@ -1086,7 +1086,7 @@ static struct { {0x017c, "zdotaccent"}, {0x0030, "zero"}, {0x2080, "zeroinferior"}, - {0x0030, "zerooldstyle"}, + {0xf730, "zerooldstyle"}, {0x2070, "zerosuperior"}, {0x03b6, "zeta"}, {0x007b, "{"}, diff --git a/xpdf/xpdf/Object.cc b/xpdf/xpdf/Object.cc index fe334f2a3..9960dc5a8 100644 --- a/xpdf/xpdf/Object.cc +++ b/xpdf/xpdf/Object.cc @@ -161,7 +161,7 @@ void Object::print(FILE *f) { break; case objString: fprintf(f, "("); - fwrite(string->getCString(), 1, string->getLength(), stdout); + fwrite(string->getCString(), 1, string->getLength(), f); fprintf(f, ")"); break; case objName: diff --git a/xpdf/xpdf/Outline.cc b/xpdf/xpdf/Outline.cc index 04891f3c3..39e89a3c3 100644 --- a/xpdf/xpdf/Outline.cc +++ b/xpdf/xpdf/Outline.cc @@ -58,14 +58,14 @@ OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { if ((s->getChar(0) & 0xff) == 0xfe && (s->getChar(1) & 0xff) == 0xff) { titleLen = (s->getLength() - 2) / 2; - title = (Unicode *)gmalloc(titleLen * sizeof(Unicode)); + title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); for (i = 0; i < titleLen; ++i) { title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) | (s->getChar(3 + 2*i) & 0xff); } } else { titleLen = s->getLength(); - title = (Unicode *)gmalloc(titleLen * sizeof(Unicode)); + title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); for (i = 0; i < titleLen; ++i) { title[i] = pdfDocEncoding[s->getChar(i) & 0xff]; } @@ -79,7 +79,7 @@ OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { action = LinkAction::parseDest(&obj1); } else { obj1.free(); - if (dict->lookup("A", &obj1)) { + if (!dict->lookup("A", &obj1)->isNull()) { action = LinkAction::parseAction(&obj1); } } diff --git a/xpdf/xpdf/OutputDev.cc b/xpdf/xpdf/OutputDev.cc index eeff18ae4..6fd37d0a2 100644 --- a/xpdf/xpdf/OutputDev.cc +++ b/xpdf/xpdf/OutputDev.cc @@ -55,8 +55,15 @@ void OutputDev::updateAll(GfxState *state) { updateLineCap(state); updateMiterLimit(state); updateLineWidth(state); + updateFillColorSpace(state); updateFillColor(state); + updateStrokeColorSpace(state); updateStrokeColor(state); + updateBlendMode(state); + updateFillOpacity(state); + updateStrokeOpacity(state); + updateFillOverprint(state); + updateStrokeOverprint(state); updateFont(state); } @@ -95,8 +102,26 @@ void OutputDev::drawImage(GfxState */*state*/, Object */*ref*/, Stream *str, } } +void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream */*maskStr*/, + int /*maskWidth*/, int /*maskHeight*/, + GBool /*maskInvert*/) { + drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); +} + +void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream */*maskStr*/, + int /*maskWidth*/, int /*maskHeight*/, + GfxImageColorMap */*maskColorMap*/) { + drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); +} + #if OPI_SUPPORT -void OutputDev::opiBegin(GfxState */*state*/, Dict *opiDict) { +void OutputDev::opiBegin(GfxState *state, Dict *opiDict) { } void OutputDev::opiEnd(GfxState *state, Dict *opiDict) { diff --git a/xpdf/xpdf/OutputDev.h b/xpdf/xpdf/OutputDev.h index 919d9c3a9..39adf8a59 100644 --- a/xpdf/xpdf/OutputDev.h +++ b/xpdf/xpdf/OutputDev.h @@ -22,6 +22,9 @@ class GString; class GfxState; class GfxColorSpace; class GfxImageColorMap; +class GfxFunctionShading; +class GfxAxialShading; +class GfxRadialShading; class Stream; class Link; class Catalog; @@ -48,6 +51,16 @@ public: // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() = 0; + // Does this device use tilingPatternFill()? If this returns false, + // tiling pattern fills will be reduced to a series of other drawing + // operations. + virtual GBool useTilingPatternFill() { return gFalse; } + + // Does this device use functionShadedFill(), axialShadedFill(), and + // radialShadedFill()? If this returns false, these shaded fills + // will be reduced to a series of other drawing operations. + virtual GBool useShadedFills() { return gFalse; } + // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() = 0; @@ -75,6 +88,9 @@ public: virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy); virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy); + double *getDefCTM() { return defCTM; } + double *getDefICTM() { return defICTM; } + //----- link borders virtual void drawLink(Link */*link*/, Catalog */*catalog*/) {} @@ -92,10 +108,15 @@ public: virtual void updateLineCap(GfxState */*state*/) {} virtual void updateMiterLimit(GfxState */*state*/) {} virtual void updateLineWidth(GfxState */*state*/) {} + virtual void updateFillColorSpace(GfxState */*state*/) {} + virtual void updateStrokeColorSpace(GfxState */*state*/) {} virtual void updateFillColor(GfxState */*state*/) {} virtual void updateStrokeColor(GfxState */*state*/) {} + virtual void updateBlendMode(GfxState */*state*/) {} virtual void updateFillOpacity(GfxState */*state*/) {} virtual void updateStrokeOpacity(GfxState */*state*/) {} + virtual void updateFillOverprint(GfxState */*state*/) {} + virtual void updateStrokeOverprint(GfxState */*state*/) {} //----- update text state virtual void updateFont(GfxState */*state*/) {} @@ -112,18 +133,29 @@ public: virtual void stroke(GfxState */*state*/) {} virtual void fill(GfxState */*state*/) {} virtual void eoFill(GfxState */*state*/) {} + virtual void tilingPatternFill(GfxState */*state*/, Object */*str*/, + int /*paintType*/, Dict */*resDict*/, + double */*mat*/, double */*bbox*/, + int /*x0*/, int /*y0*/, int /*x1*/, int /*y1*/, + double /*xStep*/, double /*yStep*/) {} + virtual void functionShadedFill(GfxState */*state*/, + GfxFunctionShading */*shading*/) {} + virtual void axialShadedFill(GfxState */*state*/, GfxAxialShading */*shading*/) {} + virtual void radialShadedFill(GfxState */*state*/, GfxRadialShading */*shading*/) {} //----- path clipping virtual void clip(GfxState */*state*/) {} virtual void eoClip(GfxState */*state*/) {} //----- text drawing + virtual void beginStringOp(GfxState */*state*/) {} + virtual void endStringOp(GfxState */*state*/) {} virtual void beginString(GfxState */*state*/, GString */*s*/) {} virtual void endString(GfxState */*state*/) {} virtual void drawChar(GfxState */*state*/, double /*x*/, double /*y*/, double /*dx*/, double /*dy*/, double /*originX*/, double /*originY*/, - CharCode /*code*/, Unicode */*u*/, int /*uLen*/) {} + CharCode /*code*/, int /*nBytes*/, Unicode */*u*/, int /*uLen*/) {} virtual void drawString(GfxState */*state*/, GString */*s*/) {} virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, @@ -138,6 +170,17 @@ public: virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap); #if OPI_SUPPORT //----- OPI functions diff --git a/xpdf/xpdf/PDFDoc.cc b/xpdf/xpdf/PDFDoc.cc index 627720a69..9849d74a3 100644 --- a/xpdf/xpdf/PDFDoc.cc +++ b/xpdf/xpdf/PDFDoc.cc @@ -29,6 +29,7 @@ #include "ErrorCodes.h" #include "Lexer.h" #include "Parser.h" +#include "SecurityHandler.h" #ifndef DISABLE_OUTLINE #include "Outline.h" #endif @@ -44,13 +45,15 @@ //------------------------------------------------------------------------ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, - GString *userPassword) { + GString *userPassword, void *guiDataA) { Object obj; GString *fileName1, *fileName2; ok = gFalse; errCode = errNone; + guiData = guiDataA; + file = NULL; str = NULL; xref = NULL; @@ -96,10 +99,68 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, ok = setup(ownerPassword, userPassword); } +#ifdef WIN32 +PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword, + GString *userPassword, void *guiDataA) { + OSVERSIONINFO version; + wchar_t fileName2[_MAX_PATH + 1]; + Object obj; + int i; + + ok = gFalse; + errCode = errNone; + + guiData = guiDataA; + + file = NULL; + str = NULL; + xref = NULL; + catalog = NULL; + links = NULL; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif + + //~ file name should be stored in Unicode (?) + fileName = new GString(); + for (i = 0; i < fileNameLen; ++i) { + fileName->append((char)fileNameA[i]); + } + + // zero-terminate the file name string + for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) { + fileName2[i] = fileNameA[i]; + } + fileName2[i] = 0; + + // try to open file + // NB: _wfopen is only available in NT + version.dwOSVersionInfoSize = sizeof(version); + GetVersionEx(&version); + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { + file = _wfopen(fileName2, L"rb"); + } else { + file = fopen(fileName->getCString(), "rb"); + } + if (!file) { + error(-1, "Couldn't open file '%s'", fileName->getCString()); + errCode = errOpenFile; + return; + } + + // create stream + obj.initNull(); + str = new FileStream(file, 0, gFalse, 0, &obj); + + ok = setup(ownerPassword, userPassword); +} +#endif + PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, - GString *userPassword) { + GString *userPassword, void *guiDataA) { ok = gFalse; errCode = errNone; + guiData = guiDataA; fileName = NULL; file = NULL; str = strA; @@ -150,13 +211,19 @@ GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { checkHeader(); // read xref table - xref = new XRef(str, ownerPassword, userPassword); + xref = new XRef(str); if (!xref->isOk()) { error(-1, "Couldn't read xref table"); errCode = xref->getErrorCode(); return gFalse; } + // check for encryption + if (!checkEncryption(ownerPassword, userPassword)) { + errCode = errEncrypted; + return gFalse; + } + // read catalog catalog = new Catalog(xref); if (!catalog->isOk()) { @@ -222,7 +289,10 @@ void PDFDoc::checkHeader() { return; } str->moveStart(i); - p = strtok(&hdrBuf[i+5], " \t\n\r"); + if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) { + error(-1, "May not be a PDF file (continuing anyway)"); + return; + } pdfVersion = atof(p); if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') || pdfVersion > supportedPDFVersionNum + 0.0001) { @@ -231,8 +301,43 @@ void PDFDoc::checkHeader() { } } +GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) { + Object encrypt; + GBool encrypted; + SecurityHandler *secHdlr; + GBool ret; + + xref->getTrailerDict()->dictLookup("Encrypt", &encrypt); + if ((encrypted = encrypt.isDict())) { + if ((secHdlr = SecurityHandler::make(this, &encrypt))) { + if (secHdlr->checkEncryption(ownerPassword, userPassword)) { + // authorization succeeded + xref->setEncryption(secHdlr->getPermissionFlags(), + secHdlr->getOwnerPasswordOk(), + secHdlr->getFileKey(), + secHdlr->getFileKeyLength(), + secHdlr->getEncVersion()); + ret = gTrue; + } else { + // authorization failed + ret = gFalse; + } + delete secHdlr; + } else { + // couldn't find the matching security handler + ret = gFalse; + } + } else { + // document is not encrypted + ret = gTrue; + } + encrypt.free(); + return ret; +} + void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool crop, GBool doLinks, + int rotate, GBool useMediaBox, GBool crop, + GBool doLinks, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { Page *p; @@ -246,52 +351,70 @@ void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, delete links; } getLinks(p); - p->display(out, hDPI, vDPI, rotate, crop, links, catalog, + p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog, abortCheckCbk, abortCheckCbkData); } else { - p->display(out, hDPI, vDPI, rotate, crop, NULL, catalog, + p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog, abortCheckCbk, abortCheckCbkData); } } void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, double hDPI, double vDPI, int rotate, - GBool crop, GBool doLinks, + GBool useMediaBox, GBool crop, GBool doLinks, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { int page; for (page = firstPage; page <= lastPage; ++page) { - displayPage(out, page, hDPI, vDPI, rotate, crop, doLinks, + displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, doLinks, abortCheckCbk, abortCheckCbkData); } } void PDFDoc::displayPages(OutputDev *out, list &pages, double hDPI, double vDPI, int rotate, - GBool crop, GBool doLinks, + GBool useMediaBox, GBool crop, GBool doLinks, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { list::const_iterator i; for(i = pages.begin(); i != pages.end(); ++i) - displayPage(out, *i, hDPI, vDPI, rotate, crop, doLinks, + displayPage(out, *i, hDPI, vDPI, rotate, useMediaBox, crop, doLinks, abortCheckCbk, abortCheckCbkData); } void PDFDoc::displayPageSlice(OutputDev *out, int page, - double hDPI, double vDPI, - int rotate, GBool crop, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool doLinks, int sliceX, int sliceY, int sliceW, int sliceH, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { Page *p; p = catalog->getPage(page); - p->displaySlice(out, hDPI, vDPI, rotate, crop, + if (doLinks) { + if (links) { + delete links; + } + getLinks(p); + p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + links, catalog, abortCheckCbk, abortCheckCbkData); + } else { + p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, NULL, catalog, abortCheckCbk, abortCheckCbkData); + } +} + +Links *PDFDoc::takeLinks() { + Links *ret; + + ret = links; + links = NULL; + return ret; } GBool PDFDoc::isLinearized() { diff --git a/xpdf/xpdf/PDFDoc.h b/xpdf/xpdf/PDFDoc.h index df2e690a7..e2131edbd 100644 --- a/xpdf/xpdf/PDFDoc.h +++ b/xpdf/xpdf/PDFDoc.h @@ -40,9 +40,13 @@ class PDFDoc { public: PDFDoc(GString *fileNameA, GString *ownerPassword = NULL, - GString *userPassword = NULL); + GString *userPassword = NULL, void *guiDataA = NULL); +#ifdef WIN32 + PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword = NULL, + GString *userPassword = NULL, void *guiDataA = NULL); +#endif PDFDoc(BaseStream *strA, GString *ownerPassword = NULL, - GString *userPassword = NULL); + GString *userPassword = NULL, void *guiDataA = NULL); ~PDFDoc(); // Was PDF document successfully opened? @@ -64,10 +68,14 @@ public: BaseStream *getBaseStream() { return str; } // Get page parameters. - double getPageWidth(int page) - { return catalog->getPage(page)->getWidth(); } - double getPageHeight(int page) - { return catalog->getPage(page)->getHeight(); } + double getPageMediaWidth(int page) + { return catalog->getPage(page)->getMediaWidth(); } + double getPageMediaHeight(int page) + { return catalog->getPage(page)->getMediaHeight(); } + double getPageCropWidth(int page) + { return catalog->getPage(page)->getCropWidth(); } + double getPageCropHeight(int page) + { return catalog->getPage(page)->getCropHeight(); } int getPageRotate(int page) { return catalog->getPage(page)->getRotate(); } @@ -83,14 +91,15 @@ public: // Display a page. void displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool crop, GBool doLinks, + int rotate, GBool useMediaBox, GBool crop, + GBool doLinks, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); // Display a range of pages. void displayPages(OutputDev *out, int firstPage, int lastPage, double hDPI, double vDPI, int rotate, - GBool crop, GBool doLinks, + GBool useMediaBox, GBool crop, GBool doLinks, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); @@ -98,15 +107,15 @@ public: // Display some pages void displayPages(OutputDev *out, list &pages, double hDPI, double vDPI, int rotate, - GBool crop, GBool doLinks, + GBool useMediaBox, GBool crop, GBool doLinks, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); // Display part of a page. void displayPageSlice(OutputDev *out, int page, - double hDPI, double vDPI, - int rotate, GBool crop, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool doLinks, int sliceX, int sliceY, int sliceW, int sliceH, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); @@ -115,13 +124,9 @@ public: // not found. int findPage(int num, int gen) { return catalog->findPage(num, gen); } - // If point , is in a link, return the associated action; - // else return NULL. - LinkAction *findLink(double x, double y) - { return links ? links->find(x, y) : (LinkAction *)NULL; } - - // Return true if , is in a link. - GBool onLink(double x, double y) { return links->onLink(x, y); } + // Returns the links for the current page, transferring ownership to + // the caller. + Links *takeLinks(); // Find a named destination. Returns the link destination, or // NULL if is not a destination. @@ -159,16 +164,21 @@ public: // Save this file with another name. GBool saveAs(GString *name); + // Return a pointer to the GUI (XPDFCore or WinPDFCore object). + void *getGUIData() { return guiData; } + private: GBool setup(GString *ownerPassword, GString *userPassword); void checkHeader(); + GBool checkEncryption(GString *ownerPassword, GString *userPassword); void getLinks(Page *page); GString *fileName; FILE *file; BaseStream *str; + void *guiData; double pdfVersion; XRef *xref; Catalog *catalog; diff --git a/xpdf/xpdf/PSOutputDev.cc b/xpdf/xpdf/PSOutputDev.cc index 595da7674..5322264b3 100644 --- a/xpdf/xpdf/PSOutputDev.cc +++ b/xpdf/xpdf/PSOutputDev.cc @@ -46,18 +46,25 @@ // PostScript prolog and setup //------------------------------------------------------------------------ +// The '~' escapes mark prolog code that is emitted only in certain +// levels: +// +// ~[123][sn] +// ^ ^----- s=psLevel*Sep, n=psLevel* +// +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3* + static const char *prolog[] = { "/xpdf 75 dict def xpdf begin", "% PDF special state", "/pdfDictSize 15 def", - "~1", + "~1sn", "/pdfStates 64 array def", " 0 1 63 {", " pdfStates exch pdfDictSize dict", " dup /pdfStateIdx 3 index put", " put", " } for", - "~a", + "~123sn", "/pdfSetup {", " 3 1 roll 2 array astore", " /setpagedevice where {", @@ -71,21 +78,35 @@ static const char *prolog[] = { " pop pop", " } ifelse", "} def", - "~1", + "~1sn", "/pdfOpNames [", " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke", " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender", " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath", "] def", - "~a", + "~123sn", "/pdfStartPage {", - "~1", + "~1sn", " pdfStates 0 get begin", - "~2", + "~23sn", " pdfDictSize dict begin", - "~a", + "~23n", + " /pdfFillCS [] def", + " /pdfFillXform {} def", + " /pdfStrokeCS [] def", + " /pdfStrokeXform {} def", + "~1n", + " /pdfFill 0 def", + " /pdfStroke 0 def", + "~1s", + " /pdfFill [0 0 0 1] def", + " /pdfStroke [0 0 0 1] def", + "~23sn", " /pdfFill [0] def", " /pdfStroke [0] def", + " /pdfFillOP false def", + " /pdfStrokeOP false def", + "~123sn", " /pdfLastFill false def", " /pdfLastStroke false def", " /pdfTextMat [1 0 0 1 0 0] def", @@ -98,6 +119,7 @@ static const char *prolog[] = { " /pdfTextClipPath [] def", "} def", "/pdfEndPage { end } def", + "~23s", "% separation convention operators", "/findcmykcustomcolor where {", " pop", @@ -139,45 +161,111 @@ static const char *prolog[] = { " grestore", " } def", "} ifelse", + "~123sn", "% PDF color state", + "~1n", + "/g { dup /pdfFill exch def setgray", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/G { dup /pdfStroke exch def setgray", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/fCol {", + " pdfLastFill not {", + " pdfFill setgray", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", "/sCol {", " pdfLastStroke not {", - " pdfStroke aload length", - " dup 1 eq {", - " pop setgray", - " }{", - " dup 3 eq {", - " pop setrgbcolor", - " }{", - " 4 eq {", - " setcmykcolor", - " }{", - " findcmykcustomcolor exch setcustomcolor", - " } ifelse", - " } ifelse", - " } ifelse", + " pdfStroke setgray", " /pdfLastStroke true def /pdfLastFill false def", " } if", "} def", + "~1s", + "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor", + " /pdfLastStroke true def /pdfLastFill false def } def", "/fCol {", " pdfLastFill not {", - " pdfFill aload length", - " dup 1 eq {", - " pop setgray", - " }{", - " dup 3 eq {", - " pop setrgbcolor", - " }{", - " 4 eq {", + " pdfFill aload pop setcmykcolor", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStroke aload pop setcmykcolor", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~23n", + "/cs { /pdfFillXform exch def dup /pdfFillCS exch def", + " setcolorspace } def", + "/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def", + " setcolorspace } def", + "/sc { pdfLastFill not { pdfFillCS setcolorspace } if", + " dup /pdfFill exch def aload pop pdfFillXform setcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if", + " dup /pdfStroke exch def aload pop pdfStrokeXform setcolor", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/op { /pdfFillOP exch def", + " pdfLastFill { pdfFillOP setoverprint } if } def", + "/OP { /pdfStrokeOP exch def", + " pdfLastStroke { pdfStrokeOP setoverprint } if } def", + "/fCol {", + " pdfLastFill not {", + " pdfFillCS setcolorspace", + " pdfFill aload pop pdfFillXform setcolor", + " pdfFillOP setoverprint", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStrokeCS setcolorspace", + " pdfStroke aload pop pdfStrokeXform setcolor", + " pdfStrokeOP setoverprint", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~23s", + "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/ck { 6 copy 6 array astore /pdfFill exch def", + " findcmykcustomcolor exch setcustomcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/CK { 6 copy 6 array astore /pdfStroke exch def", + " findcmykcustomcolor exch setcustomcolor", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/op { /pdfFillOP exch def", + " pdfLastFill { pdfFillOP setoverprint } if } def", + "/OP { /pdfStrokeOP exch def", + " pdfLastStroke { pdfStrokeOP setoverprint } if } def", + "/fCol {", + " pdfLastFill not {", + " pdfFill aload length 4 eq {", " setcmykcolor", " }{", " findcmykcustomcolor exch setcustomcolor", " } ifelse", - " } ifelse", - " } ifelse", + " pdfFillOP setoverprint", " /pdfLastFill true def /pdfLastStroke false def", " } if", "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStroke aload length 4 eq {", + " setcmykcolor", + " }{", + " findcmykcustomcolor exch setcustomcolor", + " } ifelse", + " pdfStrokeOP setoverprint", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~123sn", "% build a font", "/pdfMakeFont {", " 4 3 roll findfont", @@ -198,6 +286,7 @@ static const char *prolog[] = { " end", " definefont pop", "} def", + "~3sn", "/pdfMakeFont16L3 {", " 1 index /CIDFont resourcestatus {", " pop pop 1 index /CIDFont findresource /CIDFontType known", @@ -211,18 +300,30 @@ static const char *prolog[] = { " pdfMakeFont16", " } ifelse", "} def", + "~123sn", "% graphics state operators", - "~1", + "~1sn", "/q {", " gsave", " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for", " pdfStates pdfStateIdx 1 add get begin", " pdfOpNames { exch def } forall", "} def", - "~2", - "/q { gsave pdfDictSize dict begin } def", - "~a", "/Q { end grestore } def", + "~23sn", + "/q { gsave pdfDictSize dict begin } def", + "/Q {", + " end grestore", + " /pdfLastFill where {", + " pop", + " pdfLastFill {", + " pdfFillOP setoverprint", + " } {", + " pdfStrokeOP setoverprint", + " } ifelse", + " } if", + "} def", + "~123sn", "/cm { concat } def", "/d { setdash } def", "/i { setflat } def", @@ -230,25 +331,6 @@ static const char *prolog[] = { "/J { setlinecap } def", "/M { setmiterlimit } def", "/w { setlinewidth } def", - "% color operators", - "/g { dup 1 array astore /pdfFill exch def setgray", - " /pdfLastFill true def /pdfLastStroke false def } def", - "/G { dup 1 array astore /pdfStroke exch def setgray", - " /pdfLastStroke true def /pdfLastFill false def } def", - "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor", - " /pdfLastFill true def /pdfLastStroke false def } def", - "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor", - " /pdfLastStroke true def /pdfLastFill false def } def", - "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor", - " /pdfLastFill true def /pdfLastStroke false def } def", - "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor", - " /pdfLastStroke true def /pdfLastFill false def } def", - "/ck { 6 copy 6 array astore /pdfFill exch def", - " findcmykcustomcolor exch setcustomcolor", - " /pdfLastFill true def /pdfLastStroke false def } def", - "/CK { 6 copy 6 array astore /pdfStroke exch def", - " findcmykcustomcolor exch setcustomcolor", - " /pdfLastStroke true def /pdfLastFill false def } def", "% path segment operators", "/m { moveto } def", "/l { lineto } def", @@ -372,12 +454,14 @@ static const char *prolog[] = { " pdfTextMat dtransform rmoveto } def", "/Tclip { pdfTextClipPath cvx exec clip newpath", " /pdfTextClipPath [] def } def", - "~1", + "~1ns", "% Level 1 image operators", + "~1n", "/pdfIm1 {", " /pdfImBuf1 4 index string def", " { currentfile pdfImBuf1 readhexstring pop } image", "} def", + "~1s", "/pdfIm1Sep {", " /pdfImBuf1 4 index string def", " /pdfImBuf2 4 index string def", @@ -389,15 +473,16 @@ static const char *prolog[] = { " { currentfile pdfImBuf4 readhexstring pop }", " true 4 colorimage", "} def", + "~1ns", "/pdfImM1 {", - " /pdfImBuf1 4 index 7 add 8 idiv string def", + " fCol /pdfImBuf1 4 index 7 add 8 idiv string def", " { currentfile pdfImBuf1 readhexstring pop } imagemask", "} def", "/pdfImM1a {", " { 2 copy get exch 1 add exch } imagemask", " pop pop", "} def", - "~2", + "~23sn", "% Level 2 image operators", "/pdfImBuf 100 string def", "/pdfIm {", @@ -406,6 +491,7 @@ static const char *prolog[] = { " not { pop exit } if", " (%-EOD-) eq { exit } if } loop", "} def", + "~23s", "/pdfImSep {", " findcmykcustomcolor exch", " dup /Width get /pdfImBuf1 exch string def", @@ -424,13 +510,147 @@ static const char *prolog[] = { " not { pop exit } if", " (%-EOD-) eq { exit } if } loop", "} def", + "~23sn", "/pdfImM {", " fCol imagemask", " { currentfile pdfImBuf readline", " not { pop exit } if", " (%-EOD-) eq { exit } if } loop", "} def", - "~a", + "/pdfImClip {", + " gsave", + " 0 2 4 index length 1 sub {", + " dup 4 index exch 2 copy", + " get 5 index div put", + " 1 add 3 index exch 2 copy", + " get 3 index div put", + " } for", + " pop pop rectclip", + "} def", + "/pdfImClipEnd { grestore } def", + "~23n", + "% shading operators", + "/colordelta {", + " false 0 1 3 index length 1 sub {", + " dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {", + " pop true", + " } if", + " } for", + " exch pop exch pop", + "} def", + "/funcCol { func n array astore } def", + "/funcSH {", + " dup 0 eq {", + " true", + " } {", + " dup 6 eq {", + " false", + " } {", + " 4 index 4 index funcCol dup", + " 6 index 4 index funcCol dup", + " 3 1 roll colordelta 3 1 roll", + " 5 index 5 index funcCol dup", + " 3 1 roll colordelta 3 1 roll", + " 6 index 8 index funcCol dup", + " 3 1 roll colordelta 3 1 roll", + " colordelta or or or", + " } ifelse", + " } ifelse", + " {", + " 1 add", + " 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch", + " 6 index 6 index 4 index 4 index 4 index funcSH", + " 2 index 6 index 6 index 4 index 4 index funcSH", + " 6 index 2 index 4 index 6 index 4 index funcSH", + " 5 3 roll 3 2 roll funcSH pop pop", + " } {", + " pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul", + " funcCol sc", + " dup 4 index exch mat transform m", + " 3 index 3 index mat transform l", + " 1 index 3 index mat transform l", + " mat transform l pop pop h f*", + " } ifelse", + "} def", + "/axialCol {", + " dup 0 lt {", + " pop t0", + " } {", + " dup 1 gt {", + " pop t1", + " } {", + " dt mul t0 add", + " } ifelse", + " } ifelse", + " func n array astore", + "} def", + "/axialSH {", + " dup 0 eq {", + " true", + " } {", + " dup 8 eq {", + " false", + " } {", + " 2 index axialCol 2 index axialCol colordelta", + " } ifelse", + " } ifelse", + " {", + " 1 add 3 1 roll 2 copy add 0.5 mul", + " dup 4 3 roll exch 4 index axialSH", + " exch 3 2 roll axialSH", + " } {", + " pop 2 copy add 0.5 mul axialCol sc", + " exch dup dx mul x0 add exch dy mul y0 add", + " 3 2 roll dup dx mul x0 add exch dy mul y0 add", + " dx abs dy abs ge {", + " 2 copy yMin sub dy mul dx div add yMin m", + " yMax sub dy mul dx div add yMax l", + " 2 copy yMax sub dy mul dx div add yMax l", + " yMin sub dy mul dx div add yMin l", + " h f*", + " } {", + " exch 2 copy xMin sub dx mul dy div add xMin exch m", + " xMax sub dx mul dy div add xMax exch l", + " exch 2 copy xMax sub dx mul dy div add xMax exch l", + " xMin sub dx mul dy div add xMin exch l", + " h f*", + " } ifelse", + " } ifelse", + "} def", + "/radialCol {", + " dup t0 lt {", + " pop t0", + " } {", + " dup t1 gt {", + " pop t1", + " } if", + " } ifelse", + " func n array astore", + "} def", + "/radialSH {", + " dup 0 eq {", + " true", + " } {", + " dup 8 eq {", + " false", + " } {", + " 2 index dt mul t0 add radialCol", + " 2 index dt mul t0 add radialCol colordelta", + " } ifelse", + " } ifelse", + " {", + " 1 add 3 1 roll 2 copy add 0.5 mul", + " dup 4 3 roll exch 4 index radialSH", + " exch 3 2 roll radialSH", + " } {", + " pop 2 copy add 0.5 mul dt mul t0 add axialCol sc", + " exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", + " 0 360 arc h", + " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", + " 0 360 arc h f*", + " } ifelse", + "} def", + "~123sn", "end", NULL }; @@ -632,7 +852,7 @@ void DeviceNRecoder::reset() { GBool DeviceNRecoder::fillBuf() { Guchar pixBuf[gfxColorMaxComps]; GfxColor color; - double y[gfxColorMaxComps]; + double x[gfxColorMaxComps], y[gfxColorMaxComps]; int i; if (pixelIdx >= width * height) { @@ -640,7 +860,12 @@ GBool DeviceNRecoder::fillBuf() { } imgStr->getPixel(pixBuf); colorMap->getColor(pixBuf, &color); - func->transform(color.c, y); + for (i = 0; + i < ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->getNComps(); + ++i) { + x[i] = colToDbl(color.c[i]); + } + func->transform(x, y); for (i = 0; i < bufSize; ++i) { buf[i] = (int)(y[i] * 255 + 0.5); } @@ -772,8 +997,8 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, // this check is needed in case the document has zero pages if (firstPage > 0 && firstPage <= catalog->getNumPages()) { page = catalog->getPage(firstPage); - paperWidth = (int)(page->getWidth() + 0.5); - paperHeight = (int)(page->getHeight() + 0.5); + paperWidth = (int)ceil(page->getMediaWidth()); + paperHeight = (int)ceil(page->getMediaHeight()); } else { paperWidth = 1; paperHeight = 1; @@ -796,28 +1021,30 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, #endif tx0 = ty0 = 0; - xScale0 = yScale0 = 1; - rotate0 = 0; + xScale0 = yScale0 = 0; + rotate0 = -1; clipLLX0 = clipLLY0 = 0; clipURX0 = clipURY0 = -1; // initialize fontIDs, fontFileIDs, and fontFileNames lists fontIDSize = 64; fontIDLen = 0; - fontIDs = (Ref *)gmalloc(fontIDSize * sizeof(Ref)); + fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref)); fontFileIDSize = 64; fontFileIDLen = 0; - fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref)); + fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref)); fontFileNameSize = 64; fontFileNameLen = 0; - fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *)); - psFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *)); + fontFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *)); + psFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *)); nextTrueTypeNum = 0; font16EncLen = 0; font16EncSize = 0; xobjStack = new GList(); numSaves = 0; + numTilingPatterns = 0; + nextFunc = 0; // initialize embedded font resource comment list embFontList = new GString(); @@ -826,11 +1053,12 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, // this check is needed in case the document has zero pages if (firstPage > 0 && firstPage <= catalog->getNumPages()) { writeHeader(firstPage, lastPage, - catalog->getPage(firstPage)->getBox(), - catalog->getPage(firstPage)->getCropBox()); + catalog->getPage(firstPage)->getMediaBox(), + catalog->getPage(firstPage)->getCropBox(), + catalog->getPage(firstPage)->getRotate()); } else { box = new PDFRectangle(0, 0, 1, 1); - writeHeader(firstPage, lastPage, box, box); + writeHeader(firstPage, lastPage, box, box, 0); delete box; } if (mode != psModeForm) { @@ -917,7 +1145,10 @@ PSOutputDev::~PSOutputDev() { } void PSOutputDev::writeHeader(int firstPage, int lastPage, - PDFRectangle *mediaBox, PDFRectangle *cropBox) { + PDFRectangle *mediaBox, PDFRectangle *cropBox, + int pageRotate) { + double x1, y1, x2, y2; + switch (mode) { case psModePS: writePS("%!PS-Adobe-3.0\n"); @@ -949,15 +1180,26 @@ void PSOutputDev::writeHeader(int firstPage, int lastPage, writePS("%%DocumentProcessColors: (atend)\n"); writePS("%%DocumentCustomColors: (atend)\n"); } + epsX1 = cropBox->x1; + epsY1 = cropBox->y1; + epsX2 = cropBox->x2; + epsY2 = cropBox->y2; + if (pageRotate == 0 || pageRotate == 180) { + x1 = epsX1; + y1 = epsY1; + x2 = epsX2; + y2 = epsY2; + } else { // pageRotate == 90 || pageRotate == 270 + x1 = 0; + y1 = 0; + x2 = epsY2 - epsY1; + y2 = epsX2 - epsX1; + } writePSFmt("%%%%BoundingBox: %d %d %d %d\n", - (int)floor(cropBox->x1), (int)floor(cropBox->y1), - (int)ceil(cropBox->x2), (int)ceil(cropBox->y2)); - if (floor(cropBox->x1) != ceil(cropBox->x1) || - floor(cropBox->y1) != ceil(cropBox->y1) || - floor(cropBox->x2) != ceil(cropBox->x2) || - floor(cropBox->y2) != ceil(cropBox->y2)) { - writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", - cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); + (int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2)); + if (floor(x1) != ceil(x1) || floor(y1) != ceil(y1) || + floor(x2) != ceil(x2) || floor(y2) != ceil(y2)) { + writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", x1, y1, x2, y2); } writePS("%%DocumentSuppliedResources: (atend)\n"); writePS("%%EndComments\n"); @@ -985,21 +1227,30 @@ void PSOutputDev::writeHeader(int firstPage, int lastPage, } void PSOutputDev::writeXpdfProcset() { - char prologLevel; + GBool lev1, lev2, lev3, sep, nonSep; const char **p; + const char *q; writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion); - prologLevel = 'a'; + lev1 = lev2 = lev3 = sep = nonSep = gTrue; for (p = prolog; *p; ++p) { - if ((*p)[0] == '~' && (*p)[1] == '1') { - prologLevel = '1'; - } else if ((*p)[0] == '~' && (*p)[1] == '2') { - prologLevel = '2'; - } else if ((*p)[0] == '~' && (*p)[1] == 'a') { - prologLevel = 'a'; - } else if (prologLevel == 'a' || - (prologLevel == '1' && level < psLevel2) || - (prologLevel == '2' && level >= psLevel2)) { + if ((*p)[0] == '~') { + lev1 = lev2 = lev3 = sep = nonSep = gFalse; + for (q = *p + 1; *q; ++q) { + switch (*q) { + case '1': lev1 = gTrue; break; + case '2': lev2 = gTrue; break; + case '3': lev3 = gTrue; break; + case 's': sep = gTrue; break; + case 'n': nonSep = gTrue; break; + } + } + } else if ((level == psLevel1 && lev1 && nonSep) || + (level == psLevel1Sep && lev1 && sep) || + (level == psLevel2 && lev2 && nonSep) || + (level == psLevel2Sep && lev2 && sep) || + (level == psLevel3 && lev3 && nonSep) || + (level == psLevel3Sep && lev3 && sep)) { writePSFmt("%s\n", *p); } } @@ -1031,7 +1282,7 @@ void PSOutputDev::writeDocSetup(Catalog *catalog, if ((resDict = page->getResourceDict())) { setupResources(resDict); } - annots = new Annots(xref, page->getAnnots(&obj1)); + annots = new Annots(xref, catalog, page->getAnnots(&obj1)); obj1.free(); for (i = 0; i < annots->getNumAnnots(); ++i) { if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) { @@ -1105,7 +1356,7 @@ void PSOutputDev::writeTrailer() { } void PSOutputDev::setupResources(Dict *resDict) { - Object xObjDict, xObjRef, xObj, resObj; + Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj; Ref ref0, ref1; GBool skip; int i, j; @@ -1113,6 +1364,7 @@ void PSOutputDev::setupResources(Dict *resDict) { setupFonts(resDict); setupImages(resDict); + //----- recursively scan XObjects resDict->lookup("XObject", &xObjDict); if (xObjDict.isDict()) { for (i = 0; i < xObjDict.dictGetLength(); ++i) { @@ -1153,6 +1405,50 @@ void PSOutputDev::setupResources(Dict *resDict) { } } xObjDict.free(); + + //----- recursively scan Patterns + resDict->lookup("Pattern", &patDict); + if (patDict.isDict()) { + inType3Char = gTrue; + for (i = 0; i < patDict.dictGetLength(); ++i) { + + // avoid infinite recursion on Patterns + skip = gFalse; + if ((patDict.dictGetValNF(i, &patRef)->isRef())) { + ref0 = patRef.getRef(); + for (j = 0; j < xobjStack->getLength(); ++j) { + ref1 = *(Ref *)xobjStack->get(j); + if (ref1.num == ref0.num && ref1.gen == ref0.gen) { + skip = gTrue; + break; + } + } + if (!skip) { + xobjStack->append(&ref0); + } + } + if (!skip) { + + // process the Pattern's resource dictionary + patDict.dictGetVal(i, &pat); + if (pat.isStream()) { + pat.streamGetDict()->lookup("Resources", &resObj); + if (resObj.isDict()) { + setupResources(resObj.getDict()); + } + resObj.free(); + } + pat.free(); + } + + if (patRef.isRef() && !skip) { + xobjStack->del(xobjStack->getLength() - 1); + } + patRef.free(); + } + inType3Char = gFalse; + } + patDict.free(); } void PSOutputDev::setupFonts(Dict *resDict) { @@ -1212,7 +1508,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { // add entry to fontIDs list if (fontIDLen >= fontIDSize) { fontIDSize += 64; - fontIDs = (Ref *)grealloc(fontIDs, fontIDSize * sizeof(Ref)); + fontIDs = (Ref *)greallocn(fontIDs, fontIDSize, sizeof(Ref)); } fontIDs[fontIDLen++] = *font->getID(); @@ -1271,7 +1567,8 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { font->getType() == fontCIDType2 && font->getEmbeddedFontID(&fontFileID)) { psName = filterPSName(font->getEmbeddedFontName()); - setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName); + //~ should check to see if font actually uses vertical mode + setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue); } else if (font->getType() == fontType3) { sprintf(type3Name, "T3_%d_%d", @@ -1353,8 +1650,8 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { psName = fontParam->psFontName->copy(); if (font16EncLen >= font16EncSize) { font16EncSize += 16; - font16Enc = (PSFont16Enc *)grealloc(font16Enc, - font16EncSize * sizeof(PSFont16Enc)); + font16Enc = (PSFont16Enc *)greallocn(font16Enc, + font16EncSize, sizeof(PSFont16Enc)); } font16Enc[font16EncLen].fontID = *font->getID(); font16Enc[font16EncLen].enc = fontParam->encoding->copy(); @@ -1418,6 +1715,12 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { } writePS("/"); writePSName(charName ? charName : (const char *)".notdef"); + // the empty name is legal in PDF and PostScript, but PostScript + // uses a double-slash (//...) for "immediately evaluated names", + // so we need to add a space character here + if (charName && !charName[0]) { + writePS(" "); + } } writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n"); } @@ -1447,7 +1750,7 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, GString *psName) { // add entry to fontFileIDs list if (fontFileIDLen >= fontFileIDSize) { fontFileIDSize += 64; - fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref)); + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); } fontFileIDs[fontFileIDLen++] = *id; @@ -1512,9 +1815,11 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, GString *psName) { writePSChar(hexChar[(start[i] >> 4) & 0x0f]); writePSChar(hexChar[start[i] & 0x0f]); } +#if 0 // this causes trouble for various PostScript printers // if Length2 is incorrect (too small), font data gets chopped, so // we take a few extra characters from the trailer just in case length2 += length3 >= 8 ? 8 : length3; +#endif while (i < length2) { if ((c = strObj.streamGetChar()) == EOF) { break; @@ -1574,10 +1879,10 @@ void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) { // add entry to fontFileNames list if (fontFileNameLen >= fontFileNameSize) { fontFileNameSize += 64; - fontFileNames = (GString **)grealloc(fontFileNames, - fontFileNameSize * sizeof(GString *)); - psFileNames = (GString **)grealloc(psFileNames, - fontFileNameSize * sizeof(GString *)); + fontFileNames = (GString **)greallocn(fontFileNames, + fontFileNameSize, sizeof(GString *)); + psFileNames = (GString **)greallocn(psFileNames, + fontFileNameSize, sizeof(GString *)); } fontFileNames[fontFileNameLen] = fileName->copy(); psFileNames[fontFileNameLen] = psName->copy(); @@ -1620,7 +1925,7 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, // add entry to fontFileIDs list if (fontFileIDLen >= fontFileIDSize) { fontFileIDSize += 64; - fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref)); + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); } fontFileIDs[fontFileIDLen++] = *id; @@ -1665,7 +1970,7 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, if (i == fontFileIDLen) { if (fontFileIDLen >= fontFileIDSize) { fontFileIDSize += 64; - fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref)); + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); } fontFileIDs[fontFileIDLen++] = *id; } @@ -1717,11 +2022,11 @@ GString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) { if (fontFileNameLen >= fontFileNameSize) { fontFileNameSize += 64; fontFileNames = - (GString **)grealloc(fontFileNames, - fontFileNameSize * sizeof(GString *)); + (GString **)greallocn(fontFileNames, + fontFileNameSize, sizeof(GString *)); psFileNames = - (GString **)grealloc(psFileNames, - fontFileNameSize * sizeof(GString *)); + (GString **)greallocn(psFileNames, + fontFileNameSize, sizeof(GString *)); } } fontFileNames[fontFileNameLen] = fileName->copy(); @@ -1810,12 +2115,12 @@ GString *PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileN if (globalParams->getPSLevel() >= psLevel3) { // Level 3: use a CID font ffTT->convertToCIDType2(psName->getCString(), - codeToGID, n, + codeToGID, n, gTrue, outputFunc, outputStream); } else { // otherwise: use a non-CID composite font ffTT->convertToType0(psName->getCString(), - codeToGID, n, + codeToGID, n, gTrue, outputFunc, outputStream); } gfree(codeToGID); @@ -1844,7 +2149,7 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, // add entry to fontFileIDs list if (fontFileIDLen >= fontFileIDSize) { fontFileIDSize += 64; - fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref)); + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); } fontFileIDs[fontFileIDLen++] = *id; @@ -1873,7 +2178,9 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, } void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, - GString *psName) { + GString *psName, + GBool needVerticalMetrics) { + char unique[32]; char *fontBuf; int fontLen; FoFiTrueType *ffTT; @@ -1882,14 +2189,17 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, // check if font is already embedded for (i = 0; i < fontFileIDLen; ++i) { if (fontFileIDs[i].num == id->num && - fontFileIDs[i].gen == id->gen) - return; + fontFileIDs[i].gen == id->gen) { + sprintf(unique, "_%d", nextTrueTypeNum++); + psName->append(unique); + break; + } } // add entry to fontFileIDs list if (fontFileIDLen >= fontFileIDSize) { fontFileIDSize += 64; - fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref)); + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); } fontFileIDs[fontFileIDLen++] = *id; @@ -1907,12 +2217,14 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, ffTT->convertToCIDType2(psName->getCString(), ((GfxCIDFont *)font)->getCIDToGID(), ((GfxCIDFont *)font)->getCIDToGIDLen(), + needVerticalMetrics, outputFunc, outputStream); } else { // otherwise: use a non-CID composite font ffTT->convertToType0(psName->getCString(), ((GfxCIDFont *)font)->getCIDToGID(), ((GfxCIDFont *)font)->getCIDToGIDLen(), + needVerticalMetrics, outputFunc, outputStream); } delete ffTT; @@ -1976,7 +2288,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, GString *psName, box.y1 = m[1]; box.x2 = m[2]; box.y2 = m[3]; - gfx = new Gfx(xref, this, resDict, &box, gFalse, NULL); + gfx = new Gfx(xref, this, resDict, &box, NULL); inType3Char = gTrue; t3Cacheable = gFalse; for (i = 0; i < charProcs->getLength(); ++i) { @@ -2139,44 +2451,85 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { void PSOutputDev::startPage(int pageNum, GfxState *state) { int x1, y1, x2, y2, width, height; int imgWidth, imgHeight, imgWidth2, imgHeight2; + GBool landscape; - switch (mode) { - - case psModePS: + if (mode == psModePS) { writePSFmt("%%%%Page: %d %d\n", pageNum, seqPage); writePS("%%BeginPageSetup\n"); + } + + // underlays + if (underlayCbk) { + (*underlayCbk)(this, underlayCbkData); + } + if (overlayCbk) { + saveState(NULL); + } + + switch (mode) { + case psModePS: // rotate, translate, and scale page imgWidth = imgURX - imgLLX; imgHeight = imgURY - imgLLY; - x1 = (int)(state->getX1() + 0.5); - y1 = (int)(state->getY1() + 0.5); - x2 = (int)(state->getX2() + 0.5); - y2 = (int)(state->getY2() + 0.5); + x1 = (int)floor(state->getX1()); + y1 = (int)floor(state->getY1()); + x2 = (int)ceil(state->getX2()); + y2 = (int)ceil(state->getY2()); width = x2 - x1; height = y2 - y1; tx = ty = 0; - // portrait or landscape + // rotation and portrait/landscape mode + if (rotate0 >= 0) { + rotate = (360 - rotate0) % 360; + landscape = gFalse; + } else { + rotate = (360 - state->getRotate()) % 360; + if (rotate == 0 || rotate == 180) { if (width > height && width > imgWidth) { - rotate = 90; + rotate += 90; + landscape = gTrue; + } else { + landscape = gFalse; + } + } else { // rotate == 90 || rotate == 270 + if (height > width && height > imgWidth) { + rotate = 270 - rotate; + landscape = gTrue; + } else { + landscape = gFalse; + } + } + } writePSFmt("%%%%PageOrientation: %s\n", - state->getCTM()[0] ? "Landscape" : "Portrait"); + landscape ? "Landscape" : "Portrait"); writePS("pdfStartPage\n"); + if (rotate == 0) { + imgWidth2 = imgWidth; + imgHeight2 = imgHeight; + } else if (rotate == 90) { writePS("90 rotate\n"); ty = -imgWidth; imgWidth2 = imgHeight; imgHeight2 = imgWidth; - } else { - rotate = 0; - writePSFmt("%%%%PageOrientation: %s\n", - state->getCTM()[0] ? "Portrait" : "Landscape"); - writePS("pdfStartPage\n"); + } else if (rotate == 180) { + writePS("180 rotate\n"); imgWidth2 = imgWidth; imgHeight2 = imgHeight; + tx = -imgWidth; + ty = -imgHeight; + } else { // rotate == 270 + writePS("270 rotate\n"); + tx = -imgHeight; + imgWidth2 = imgHeight; + imgHeight2 = imgWidth; } // shrink or expand - if ((globalParams->getPSShrinkLarger() && + if (xScale0 > 0 && yScale0 > 0) { + xScale = xScale0; + yScale = yScale0; + } else if ((globalParams->getPSShrinkLarger() && (width > imgWidth2 || height > imgHeight2)) || (globalParams->getPSExpandSmaller() && (width < imgWidth2 && height < imgHeight2))) { @@ -2190,18 +2543,26 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { } else { xScale = yScale = 1; } - // deal with odd bounding boxes + // deal with odd bounding boxes or clipping + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + tx -= xScale * clipLLX0; + ty -= yScale * clipLLY0; + } else { tx -= xScale * x1; ty -= yScale * y1; + } // center if (globalParams->getPSCenter()) { + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2; + ty += (imgHeight2 - yScale * (clipURY0 - clipLLY0)) / 2; + } else { tx += (imgWidth2 - xScale * width) / 2; ty += (imgHeight2 - yScale * height) / 2; } - tx += imgLLX + tx0; - ty += imgLLY + ty0; - xScale *= xScale0; - yScale *= yScale0; + } + tx += rotate == 0 ? imgLLX + tx0 : imgLLY + ty0; + ty += rotate == 0 ? imgLLY + ty0 : -(imgLLX + tx0); if (tx != 0 || ty != 0) { writePSFmt("%g %g translate\n", tx, ty); } @@ -2211,6 +2572,8 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { writePSFmt("%g %g %g %g re W\n", clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0); + } else { + writePSFmt("%d %d %d %d re W\n", x1, y1, x2 - x1, y2 - y1); } writePS("%%EndPageSetup\n"); @@ -2220,8 +2583,25 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { case psModeEPS: writePS("pdfStartPage\n"); tx = ty = 0; + rotate = (360 - state->getRotate()) % 360; + if (rotate == 0) { + } else if (rotate == 90) { + writePS("90 rotate\n"); + tx = -epsX1; + ty = -epsY2; + } else if (rotate == 180) { + writePS("180 rotate\n"); + tx = -(epsX1 + epsX2); + ty = -(epsY1 + epsY2); + } else { // rotate == 270 + writePS("270 rotate\n"); + tx = -epsX2; + ty = -epsY1; + } + if (tx != 0 || ty != 0) { + writePSFmt("%g %g translate\n", tx, ty); + } xScale = yScale = 1; - rotate = 0; break; case psModeForm: @@ -2233,14 +2613,11 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { rotate = 0; break; } - - if (underlayCbk) { - (*underlayCbk)(this, underlayCbkData); - } } void PSOutputDev::endPage() { if (overlayCbk) { + restoreState(NULL); (*overlayCbk)(this, overlayCbkData); } @@ -2253,10 +2630,10 @@ void PSOutputDev::endPage() { } else { if (!manualCtrl) { writePS("showpage\n"); + } writePS("%%PageTrailer\n"); writePageTrailer(); } - } } void PSOutputDev::saveState(GfxState */*state*/) { @@ -2281,8 +2658,11 @@ void PSOutputDev::updateLineDash(GfxState *state) { state->getLineDash(&dash, &length, &start); writePS("["); - for (i = 0; i < length; ++i) - writePSFmt("%g%s", dash[i], (i == length-1) ? "" : " "); + for (i = 0; i < length; ++i) { + writePSFmt("%g%s", + dash[i] == 0 ? 1 : dash[i], + (i == length-1) ? "" : " "); + } writePSFmt("] %g d\n", start); } @@ -2306,52 +2686,99 @@ void PSOutputDev::updateLineWidth(GfxState *state) { writePSFmt("%g w\n", state->getLineWidth()); } +void PSOutputDev::updateFillColorSpace(GfxState *state) { + switch (level) { + case psLevel1: + case psLevel1Sep: + break; + case psLevel2: + case psLevel3: + if (state->getFillColorSpace()->getMode() != csPattern) { + dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse); + writePS(" cs\n"); + } + break; + case psLevel2Sep: + case psLevel3Sep: + break; + } +} + +void PSOutputDev::updateStrokeColorSpace(GfxState *state) { + switch (level) { + case psLevel1: + case psLevel1Sep: + break; + case psLevel2: + case psLevel3: + if (state->getStrokeColorSpace()->getMode() != csPattern) { + dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse); + writePS(" CS\n"); + } + break; + case psLevel2Sep: + case psLevel3Sep: + break; + } +} + void PSOutputDev::updateFillColor(GfxState *state) { GfxColor color; - double gray; - GfxRGB rgb; + GfxColor *colorPtr; + GfxGray gray; GfxCMYK cmyk; GfxSeparationColorSpace *sepCS; + double c, m, y, k; + int i; switch (level) { case psLevel1: state->getFillGray(&gray); - writePSFmt("%g g\n", gray); + writePSFmt("%g g\n", colToDbl(gray)); break; case psLevel1Sep: state->getFillCMYK(&cmyk); - writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); - addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("%g %g %g %g k\n", c, m, y, k); + addProcessColor(c, m, y, k); break; case psLevel2: case psLevel3: - if (state->getFillColorSpace()->getMode() == csDeviceCMYK) { - state->getFillCMYK(&cmyk); - writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); - } else { - state->getFillRGB(&rgb); - if (rgb.r == rgb.g && rgb.g == rgb.b) { - writePSFmt("%g g\n", rgb.r); - } else { - writePSFmt("%g %g %g rg\n", rgb.r, rgb.g, rgb.b); + if (state->getFillColorSpace()->getMode() != csPattern) { + colorPtr = state->getFillColor(); + writePS("["); + for (i = 0; i < state->getFillColorSpace()->getNComps(); ++i) { + if (i > 0) { + writePS(" "); + } + writePSFmt("%g", colToDbl(colorPtr->c[i])); } + writePS("] sc\n"); } break; case psLevel2Sep: case psLevel3Sep: if (state->getFillColorSpace()->getMode() == csSeparation) { sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace(); - color.c[0] = 1; + color.c[0] = gfxColorComp1; sepCS->getCMYK(&color, &cmyk); writePSFmt("%g %g %g %g %g (%s) ck\n", - state->getFillColor()->c[0], - cmyk.c, cmyk.m, cmyk.y, cmyk.k, + colToDbl(state->getFillColor()->c[0]), + colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), sepCS->getName()->getCString()); addCustomColor(sepCS); } else { state->getFillCMYK(&cmyk); - writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); - addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("%g %g %g %g k\n", c, m, y, k); + addProcessColor(c, m, y, k); } break; } @@ -2360,50 +2787,61 @@ void PSOutputDev::updateFillColor(GfxState *state) { void PSOutputDev::updateStrokeColor(GfxState *state) { GfxColor color; - double gray; - GfxRGB rgb; + GfxColor *colorPtr; + GfxGray gray; GfxCMYK cmyk; GfxSeparationColorSpace *sepCS; + double c, m, y, k; + int i; switch (level) { case psLevel1: state->getStrokeGray(&gray); - writePSFmt("%g G\n", gray); + writePSFmt("%g G\n", colToDbl(gray)); break; case psLevel1Sep: state->getStrokeCMYK(&cmyk); - writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); - addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("%g %g %g %g K\n", c, m, y, k); + addProcessColor(c, m, y, k); break; case psLevel2: case psLevel3: - if (state->getStrokeColorSpace()->getMode() == csDeviceCMYK) { - state->getStrokeCMYK(&cmyk); - writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); - } else { - state->getStrokeRGB(&rgb); - if (rgb.r == rgb.g && rgb.g == rgb.b) { - writePSFmt("%g G\n", rgb.r); - } else { - writePSFmt("%g %g %g RG\n", rgb.r, rgb.g, rgb.b); + if (state->getStrokeColorSpace()->getMode() != csPattern) { + colorPtr = state->getStrokeColor(); + writePS("["); + for (i = 0; i < state->getStrokeColorSpace()->getNComps(); ++i) { + if (i > 0) { + writePS(" "); } + writePSFmt("%g", colToDbl(colorPtr->c[i])); + } + writePS("] SC\n"); } break; case psLevel2Sep: case psLevel3Sep: if (state->getStrokeColorSpace()->getMode() == csSeparation) { sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace(); - color.c[0] = 1; + color.c[0] = gfxColorComp1; sepCS->getCMYK(&color, &cmyk); writePSFmt("%g %g %g %g %g (%s) CK\n", - state->getStrokeColor()->c[0], - cmyk.c, cmyk.m, cmyk.y, cmyk.k, + colToDbl(state->getStrokeColor()->c[0]), + colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), sepCS->getName()->getCString()); addCustomColor(sepCS); } else { state->getStrokeCMYK(&cmyk); - writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); - addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("%g %g %g %g K\n", c, m, y, k); + addProcessColor(c, m, y, k); } break; } @@ -2435,19 +2873,33 @@ void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) { return; } } - color.c[0] = 1; + color.c[0] = gfxColorComp1; sepCS->getCMYK(&color, &cmyk); - cc = new PSOutCustomColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k, + cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), sepCS->getName()->copy()); cc->next = customColors; customColors = cc; } +void PSOutputDev::updateFillOverprint(GfxState *state) { + if (level >= psLevel2) { + writePSFmt("%s op\n", state->getFillOverprint() ? "true" : "false"); + } +} + +void PSOutputDev::updateStrokeOverprint(GfxState *state) { + if (level >= psLevel2) { + writePSFmt("%s OP\n", state->getStrokeOverprint() ? "true" : "false"); + } +} + void PSOutputDev::updateFont(GfxState *state) { if (state->getFont()) { writePSFmt("/F%d_%d %g Tf\n", state->getFont()->getID()->num, state->getFont()->getID()->gen, - state->getFontSize()); + fabs(state->getFontSize()) < 0.00001 ? 0.00001 + : state->getFontSize()); } } @@ -2455,8 +2907,13 @@ void PSOutputDev::updateTextMat(GfxState *state) { double *mat; mat = state->getTextMat(); + if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) { + // avoid a singular (or close-to-singular) matrix + writePSFmt("[0.00001 0 0 0.00001 %g %g] Tm\n", mat[4], mat[5]); + } else { writePSFmt("[%g %g %g %g %g %g] Tm\n", mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + } } void PSOutputDev::updateCharSpace(GfxState *state) { @@ -2485,7 +2942,8 @@ void PSOutputDev::updateWordSpace(GfxState *state) { void PSOutputDev::updateHorizScaling(GfxState *state) { double h; - if ((h = state->getHorizScaling()) < 0.01) { + h = state->getHorizScaling(); + if (fabs(h) < 0.01) { h = 0.01; } writePSFmt("%g Tz\n", h); @@ -2524,6 +2982,274 @@ void PSOutputDev::eoFill(GfxState *state) { writePS("f*\n"); } +void PSOutputDev::tilingPatternFill(GfxState */*state*/, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep) { + PDFRectangle box; + Gfx *gfx; + + // define a Type 3 font + writePS("8 dict begin\n"); + writePS("/FontType 3 def\n"); + writePS("/FontMatrix [1 0 0 1 0 0] def\n"); + writePSFmt("/FontBBox [%g %g %g %g] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + writePS("/Encoding 256 array def\n"); + writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); + writePS(" Encoding 120 /x put\n"); + writePS("/BuildGlyph {\n"); + writePS(" exch /CharProcs get exch\n"); + writePS(" 2 copy known not { pop /.notdef } if\n"); + writePS(" get exec\n"); + writePS("} bind def\n"); + writePS("/BuildChar {\n"); + writePS(" 1 index /Encoding get exch get\n"); + writePS(" 1 index /BuildGlyph get exec\n"); + writePS("} bind def\n"); + writePS("/CharProcs 1 dict def\n"); + writePS("CharProcs begin\n"); + box.x1 = bbox[0]; + box.y1 = bbox[1]; + box.x2 = bbox[2]; + box.y2 = bbox[3]; + gfx = new Gfx(xref, this, resDict, &box, NULL); + writePS("/x {\n"); + if (paintType == 2) { + writePSFmt("%g 0 %g %g %g %g setcachedevice\n", + xStep, bbox[0], bbox[1], bbox[2], bbox[3]); + } else { + writePSFmt("%g 0 setcharwidth\n", xStep); + } + inType3Char = gTrue; + ++numTilingPatterns; + gfx->display(str); + --numTilingPatterns; + inType3Char = gFalse; + writePS("} def\n"); + delete gfx; + writePS("end\n"); + writePS("currentdict end\n"); + writePSFmt("/xpdfTile%d exch definefont pop\n", numTilingPatterns); + + // draw the tiles + writePSFmt("/xpdfTile%d findfont setfont\n", numTilingPatterns); + writePSFmt("gsave [%g %g %g %g %g %g] concat\n", + mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + writePSFmt("%d 1 %d { %g exch %g mul m %d 1 %d { pop (x) show } for } for\n", + y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1); + writePS("grestore\n"); +} + +void PSOutputDev::functionShadedFill(GfxState */*state*/, + GfxFunctionShading *shading) { + double x0, y0, x1, y1; + double *mat; + int i; + + shading->getDomain(&x0, &y0, &x1, &y1); + mat = shading->getMatrix(); + writePSFmt("/mat [%g %g %g %g %g %g] def\n", + mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + writePSFmt("/n %d def\n", shading->getColorSpace()->getNComps()); + if (shading->getNFuncs() == 1) { + writePS("/func "); + cvtFunction(shading->getFunc(0)); + writePS("def\n"); + } else { + writePS("/func {\n"); + for (i = 0; i < shading->getNFuncs(); ++i) { + if (i < shading->getNFuncs() - 1) { + writePS("2 copy\n"); + } + cvtFunction(shading->getFunc(i)); + writePS("exec\n"); + if (i < shading->getNFuncs() - 1) { + writePS("3 1 roll\n"); + } + } + writePS("} def\n"); + } + writePSFmt("%g %g %g %g 0 funcSH\n", x0, y0, x1, y1); +} + +void PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) { + double xMin, yMin, xMax, yMax; + double x0, y0, x1, y1, dx, dy, mul; + double tMin, tMax, t, t0, t1; + int i; + + // get the clip region bbox + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + + // compute min and max t values, based on the four corners of the + // clip region bbox + shading->getCoords(&x0, &y0, &x1, &y1); + dx = x1 - x0; + dy = y1 - y0; + mul = 1 / (dx * dx + dy * dy); + tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; + t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; + if (t < tMin) { + tMin = t; + } else if (t > tMax) { + tMax = t; + } + t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul; + if (t < tMin) { + tMin = t; + } else if (t > tMax) { + tMax = t; + } + t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul; + if (t < tMin) { + tMin = t; + } else if (t > tMax) { + tMax = t; + } + if (tMin < 0 && !shading->getExtend0()) { + tMin = 0; + } + if (tMax > 1 && !shading->getExtend1()) { + tMax = 1; + } + + // get the function domain + t0 = shading->getDomain0(); + t1 = shading->getDomain1(); + + // generate the PS code + writePSFmt("/t0 %g def\n", t0); + writePSFmt("/t1 %g def\n", t1); + writePSFmt("/dt %g def\n", t1 - t0); + writePSFmt("/x0 %g def\n", x0); + writePSFmt("/y0 %g def\n", y0); + writePSFmt("/dx %g def\n", x1 - x0); + writePSFmt("/x1 %g def\n", x1); + writePSFmt("/y1 %g def\n", y1); + writePSFmt("/dy %g def\n", y1 - y0); + writePSFmt("/xMin %g def\n", xMin); + writePSFmt("/yMin %g def\n", yMin); + writePSFmt("/xMax %g def\n", xMax); + writePSFmt("/yMax %g def\n", yMax); + writePSFmt("/n %d def\n", shading->getColorSpace()->getNComps()); + if (shading->getNFuncs() == 1) { + writePS("/func "); + cvtFunction(shading->getFunc(0)); + writePS("def\n"); + } else { + writePS("/func {\n"); + for (i = 0; i < shading->getNFuncs(); ++i) { + if (i < shading->getNFuncs() - 1) { + writePS("dup\n"); + } + cvtFunction(shading->getFunc(i)); + writePS("exec\n"); + if (i < shading->getNFuncs() - 1) { + writePS("exch\n"); + } + } + writePS("} def\n"); + } + writePSFmt("%g %g 0 axialSH\n", tMin, tMax); +} + +void PSOutputDev::radialShadedFill(GfxState *state, + GfxRadialShading *shading) { + double x0, y0, r0, x1, y1, r1, t0, t1, sMin, sMax; + double xMin, yMin, xMax, yMax; + double d0, d1; + int i; + + // get the shading info + shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); + t0 = shading->getDomain0(); + t1 = shading->getDomain1(); + + // compute the (possibly extended) s range + sMin = 0; + sMax = 1; + if (shading->getExtend0()) { + if (r0 < r1) { + // extend the smaller end + sMin = -r0 / (r1 - r0); + } else { + // extend the larger end + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + d0 = (x0 - xMin) * (x0 - xMin); + d1 = (x0 - xMax) * (x0 - xMax); + sMin = d0 > d1 ? d0 : d1; + d0 = (y0 - yMin) * (y0 - yMin); + d1 = (y0 - yMax) * (y0 - yMax); + sMin += d0 > d1 ? d0 : d1; + sMin = (sqrt(sMin) - r0) / (r1 - r0); + if (sMin > 0) { + sMin = 0; + } else if (sMin < -20) { + // sanity check + sMin = -20; + } + } + } + if (shading->getExtend1()) { + if (r1 < r0) { + // extend the smaller end + sMax = -r0 / (r1 - r0); + } else if (r1 > r0) { + // extend the larger end + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + d0 = (x1 - xMin) * (x1 - xMin); + d1 = (x1 - xMax) * (x1 - xMax); + sMax = d0 > d1 ? d0 : d1; + d0 = (y1 - yMin) * (y1 - yMin); + d1 = (y1 - yMax) * (y1 - yMax); + sMax += d0 > d1 ? d0 : d1; + sMax = (sqrt(sMax) - r0) / (r1 - r0); + if (sMax < 1) { + sMax = 1; + } else if (sMax > 20) { + // sanity check + sMax = 20; + } + } + } + + // generate the PS code + writePSFmt("/x0 %g def\n", x0); + writePSFmt("/x1 %g def\n", x1); + writePSFmt("/dx %g def\n", x1 - x0); + writePSFmt("/y0 %g def\n", y0); + writePSFmt("/y1 %g def\n", y1); + writePSFmt("/dy %g def\n", y1 - y0); + writePSFmt("/r0 %g def\n", r0); + writePSFmt("/r1 %g def\n", r1); + writePSFmt("/dr %g def\n", r1 - r0); + writePSFmt("/t0 %g def\n", t0); + writePSFmt("/t1 %g def\n", t1); + writePSFmt("/dt %g def\n", t1 - t0); + writePSFmt("/n %d def\n", shading->getColorSpace()->getNComps()); + if (shading->getNFuncs() == 1) { + writePS("/func "); + cvtFunction(shading->getFunc(0)); + writePS("def\n"); + } else { + writePS("/func {\n"); + for (i = 0; i < shading->getNFuncs(); ++i) { + if (i < shading->getNFuncs() - 1) { + writePS("dup\n"); + } + cvtFunction(shading->getFunc(i)); + writePS("exec\n"); + if (i < shading->getNFuncs() - 1) { + writePS("exch\n"); + } + } + writePS("} def\n"); + } + writePSFmt("%g %g 0 radialSH\n", sMin, sMax); +} + void PSOutputDev::clip(GfxState *state) { doPath(state->getPath()); writePS("W\n"); @@ -2712,13 +3438,14 @@ void PSOutputDev::drawImageMask(GfxState */*state*/, Object *ref, Stream *str, if (level == psLevel1 || level == psLevel1Sep) { doImageL1(ref, NULL, invert, inlineImg, str, width, height, len); } else { - doImageL2(ref, NULL, invert, inlineImg, str, width, height, len); + doImageL2(ref, NULL, invert, inlineImg, str, width, height, len, + NULL, NULL, 0, 0, gFalse); } } void PSOutputDev::drawImage(GfxState */*state*/, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, - int */*maskColors*/, GBool inlineImg) { + int *maskColors, GBool inlineImg) { int len; len = height * ((width * colorMap->getNumPixelComps() * @@ -2735,7 +3462,37 @@ void PSOutputDev::drawImage(GfxState */*state*/, Object *ref, Stream *str, case psLevel2Sep: case psLevel3: case psLevel3Sep: - doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len); + doImageL2(ref, colorMap, gFalse, inlineImg, str, + width, height, len, maskColors, NULL, 0, 0, gFalse); + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::drawMaskedImage(GfxState */*state*/, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GBool maskInvert) { + int len; + + len = height * ((width * colorMap->getNumPixelComps() * + colorMap->getBits() + 7) / 8); + switch (level) { + case psLevel1: + doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len); + break; + case psLevel1Sep: + //~ handle indexed, separation, ... color spaces + doImageL1Sep(colorMap, gFalse, gFalse, str, width, height, len); + break; + case psLevel2: + case psLevel2Sep: + case psLevel3: + case psLevel3Sep: + doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len, + NULL, maskStr, maskWidth, maskHeight, maskInvert); break; } t3Cacheable = gFalse; @@ -2746,7 +3503,7 @@ void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap, Stream *str, int width, int height, int len) { ImageStream *imgStr; Guchar pixBuf[gfxColorMaxComps]; - double gray; + GfxGray gray; int col, x, y, c, i; if (inType3Char && !colorMap) { @@ -2818,7 +3575,7 @@ void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap, for (x = 0; x < width; ++x) { imgStr->getPixel(pixBuf); colorMap->getGray(pixBuf, &gray); - writePSFmt("%02x", (int)(gray * 255 + 0.5)); + writePSFmt("%02x", colToByte(gray)); if (++i == 32) { writePSChar('\n'); i = 0; @@ -2881,11 +3638,12 @@ void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap, for (x = 0; x < width; ++x) { imgStr->getPixel(pixBuf); colorMap->getCMYK(pixBuf, &cmyk); - lineBuf[4*x+0] = (int)(255 * cmyk.c + 0.5); - lineBuf[4*x+1] = (int)(255 * cmyk.m + 0.5); - lineBuf[4*x+2] = (int)(255 * cmyk.y + 0.5); - lineBuf[4*x+3] = (int)(255 * cmyk.k + 0.5); - addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + lineBuf[4*x+0] = colToByte(cmyk.c); + lineBuf[4*x+1] = colToByte(cmyk.m); + lineBuf[4*x+2] = colToByte(cmyk.y); + lineBuf[4*x+3] = colToByte(cmyk.k); + addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k)); } // write one line of each color component @@ -2910,7 +3668,11 @@ void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap, void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, - Stream *str, int width, int height, int len) { + Stream *str, int width, int height, int len, + int *maskColors, Stream *maskStr, + int maskWidth, int maskHeight, GBool maskInvert) { + ImageStream *imgStr; + Guchar *line, *pix; GString *s; int n, numComps; GBool useRLE, useASCII, useASCIIHex, useCompressed; @@ -2918,11 +3680,86 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, GfxColor color; GfxCMYK cmyk; int c; - int col, i; + int col, i, x, x0, y, y0, maskXor; + + // color key masking + if (maskColors && colorMap && !inlineImg) { + // can't read the stream twice for inline images -- but masking + // isn't allowed with inline images anyway + writePS("[\n"); + numComps = colorMap->getNumPixelComps(); + imgStr = new ImageStream(str, width, numComps, colorMap->getBits()); + imgStr->reset(); + for (y = 0, y0 = 0; y < height; ++y) { + if (!(line = imgStr->getLine())) { + break; + } + for (x = 0, x0 = 0, pix = line; x < width; ++x, pix += numComps) { + for (i = 0; i < numComps; ++i) { + if (pix[i] < maskColors[2*i] || + pix[i] > maskColors[2*i+1]) { + break; + } + } + if (i == numComps) { + if (y0 < y) { + writePSFmt("0 %d %d %d\n", height - y, width, y - y0); + } + if (x0 < x) { + writePSFmt("%d %d %d 1\n", x0, height - y - 1, x - x0); + } + x0 = x + 1; + y0 = y + 1; + } + } + if (x0 > 0 && x0 < width) { + writePSFmt("%d %d %d 1\n", x0, height - y - 1, width - x0); + } + } + if (y0 < height) { + writePSFmt("0 0 %d %d\n", width, height - y0); + } + delete imgStr; + str->close(); + writePSFmt("] %d %d pdfImClip\n", width, height); + + // explicit masking + } else if (maskStr) { + writePS("[\n"); + imgStr = new ImageStream(maskStr, maskWidth, 1, 1); + imgStr->reset(); + maskXor = maskInvert ? 1 : 0; + for (y = 0, y0 = 0; y < maskHeight; ++y) { + if (!(line = imgStr->getLine())) { + break; + } + for (x = 0, x0 = 0, pix = line; x < maskWidth; ++x, ++pix) { + if (*pix ^ maskXor) { + if (y0 < y) { + writePSFmt("0 %d %d %d\n", maskHeight - y, maskWidth, y - y0); + } + if (x0 < x) { + writePSFmt("%d %d %d 1\n", x0, maskHeight - y - 1, x - x0); + } + x0 = x + 1; + y0 = y + 1; + } + } + if (x0 > 0 && x0 < maskWidth) { + writePSFmt("%d %d %d 1\n", x0, maskHeight - y - 1, maskWidth - x0); + } + } + if (y0 < maskHeight) { + writePSFmt("0 0 %d %d\n", maskWidth, maskHeight - y0); + } + delete imgStr; + maskStr->close(); + writePSFmt("] %d %d pdfImClip\n", maskWidth, maskHeight); + } // color space if (colorMap) { - dumpColorSpaceL2(colorMap->getColorSpace()); + dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue); writePS(" setcolorspace\n"); } @@ -3001,8 +3838,9 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, // decode if (colorMap) { writePS(" /Decode ["); - if (colorMap->getColorSpace()->getMode() == csSeparation) { - //~ this is a kludge -- see comment in dumpColorSpaceL2 + if ((level == psLevel2Sep || level == psLevel3Sep) && + colorMap->getColorSpace()->getMode() == csSeparation) { + // this matches up with the code in the pdfImSep operator n = (1 << colorMap->getBits()) - 1; writePSFmt("%g %g", colorMap->getDecodeLow(0) * n, colorMap->getDecodeHigh(0) * n); @@ -3013,8 +3851,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, if (i > 0) { writePS(" "); } - writePSFmt("0 1", colorMap->getDecodeLow(i), - colorMap->getDecodeHigh(i)); + writePS("0 1"); } } else { numComps = colorMap->getNumPixelComps(); @@ -3048,7 +3885,6 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, writePS(" /DataSource currentfile\n"); s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, " "); - if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || inlineImg || !s) { useRLE = gTrue; @@ -3123,11 +3959,12 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, #endif if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && colorMap->getColorSpace()->getMode() == csSeparation) { - color.c[0] = 1; + color.c[0] = gfxColorComp1; sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); sepCS->getCMYK(&color, &cmyk); writePSFmt("%g %g %g %g (%s) pdfImSep\n", - cmyk.c, cmyk.m, cmyk.y, cmyk.k, + colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), sepCS->getName()->getCString()); } else { writePSFmt("%s\n", colorMap ? "pdfIm" : "pdfImM"); @@ -3154,14 +3991,20 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, delete str; } } + + if ((maskColors && colorMap && !inlineImg) || maskStr) { + writePS("pdfImClipEnd\n"); + } } -void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { +void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace, + GBool genXform, GBool updateColors) { GfxCalGrayColorSpace *calGrayCS; GfxCalRGBColorSpace *calRGBCS; GfxLabColorSpace *labCS; GfxIndexedColorSpace *indexedCS; GfxSeparationColorSpace *separationCS; + GfxDeviceNColorSpace *deviceNCS; GfxColorSpace *baseCS; Guchar *lookup, *p; double x[gfxColorMaxComps], y[gfxColorMaxComps]; @@ -3176,7 +4019,12 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { case csDeviceGray: writePS("/DeviceGray"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { processColors |= psProcessBlack; + } break; case csCalGray: @@ -3193,12 +4041,22 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { calGrayCS->getBlackX(), calGrayCS->getBlackY(), calGrayCS->getBlackZ()); writePS(">>]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { processColors |= psProcessBlack; + } break; case csDeviceRGB: writePS("/DeviceRGB"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { processColors |= psProcessCMYK; + } break; case csCalRGB: @@ -3220,12 +4078,22 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { calRGBCS->getBlackX(), calRGBCS->getBlackY(), calRGBCS->getBlackZ()); writePS(">>]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { processColors |= psProcessCMYK; + } break; case csDeviceCMYK: writePS("/DeviceCMYK"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { processColors |= psProcessCMYK; + } break; case csLab: @@ -3251,20 +4119,26 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { writePSFmt(" /BlackPoint [%g %g %g]\n", labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ()); writePS(">>]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { processColors |= psProcessCMYK; + } break; case csICCBased: // there is no transform function to the alternate color space, so // we can use it directly - dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt()); + dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(), + genXform, updateColors); break; case csIndexed: indexedCS = (GfxIndexedColorSpace *)colorSpace; baseCS = indexedCS->getBase(); writePS("[/Indexed "); - dumpColorSpaceL2(baseCS); + dumpColorSpaceL2(baseCS, gFalse, gFalse); n = indexedCS->getIndexHigh(); numComps = baseCS->getNComps(); lookup = indexedCS->getLookup(); @@ -3289,9 +4163,12 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { } writePSFmt("%02x", byte); } - color.c[0] = j; + if (updateColors) { + color.c[0] = dblToCol(j); indexedCS->getCMYK(&color, &cmyk); - addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k)); + } } writePS("\n"); } @@ -3302,52 +4179,52 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { for (k = 0; k < numComps; ++k) { writePSFmt("%02x", lookup[j * numComps + k]); } - color.c[0] = j; + if (updateColors) { + color.c[0] = dblToCol(j); indexedCS->getCMYK(&color, &cmyk); - addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k)); + } } writePS("\n"); } } writePS(">]"); + if (genXform) { + writePS(" {}"); + } break; case csSeparation: - //~ this is a kludge -- the correct thing would to ouput a - //~ separation color space, with the specified alternate color - //~ space and tint transform separationCS = (GfxSeparationColorSpace *)colorSpace; - writePS("[/Indexed "); - dumpColorSpaceL2(separationCS->getAlt()); - writePS(" 255 <\n"); - numComps = separationCS->getAlt()->getNComps(); - for (i = 0; i <= 255; i += 8) { + writePS("[/Separation /"); + writePSName(separationCS->getName()->getCString()); writePS(" "); - for (j = i; j < i+8 && j <= 255; ++j) { - x[0] = (double)j / 255.0; - separationCS->getFunc()->transform(x, y); - for (k = 0; k < numComps; ++k) { - writePSFmt("%02x", (int)(255 * y[k] + 0.5)); - } - } + dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse); writePS("\n"); + cvtFunction(separationCS->getFunc()); + writePS("]"); + if (genXform) { + writePS(" {}"); } - writePS(">]"); -#if 0 //~ this shouldn't be here since the PS file doesn't actually refer - //~ to this colorant (it's converted to CMYK instead) + if (updateColors) { addCustomColor(separationCS); -#endif + } break; case csDeviceN: // DeviceN color spaces are a Level 3 PostScript feature. - dumpColorSpaceL2(((GfxDeviceNColorSpace *)colorSpace)->getAlt()); + deviceNCS = (GfxDeviceNColorSpace *)colorSpace; + dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors); + if (genXform) { + writePS(" "); + cvtFunction(deviceNCS->getTintTransformFunc()); + } break; case csPattern: //~ unimplemented break; - } } @@ -3810,6 +4687,161 @@ void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) { str->close(); } +//~ can nextFunc be reset to 0 -- maybe at the start of each page? +//~ or maybe at the start of each color space / pattern? +void PSOutputDev::cvtFunction(Function *func) { + SampledFunction *func0; + ExponentialFunction *func2; + StitchingFunction *func3; + PostScriptFunction *func4; + int thisFunc, m, n, nSamples, i, j, k; + + switch (func->getType()) { + + case -1: // identity + writePS("{}\n"); + break; + + case 0: // sampled + func0 = (SampledFunction *)func; + thisFunc = nextFunc++; + m = func0->getInputSize(); + n = func0->getOutputSize(); + nSamples = n; + for (i = 0; i < m; ++i) { + nSamples *= func0->getSampleSize(i); + } + writePSFmt("/xpdfSamples%d [\n", thisFunc); + for (i = 0; i < nSamples; ++i) { + writePSFmt("%g\n", func0->getSamples()[i]); + } + writePS("] def\n"); + writePSFmt("{ %d array %d array %d 2 roll\n", 2*m, m, m+2); + // [e01] [efrac] x0 x1 ... xm-1 + for (i = m-1; i >= 0; --i) { + // [e01] [efrac] x0 x1 ... xi + writePSFmt("%g sub %g mul %g add\n", + func0->getDomainMin(i), + (func0->getEncodeMax(i) - func0->getEncodeMin(i)) / + (func0->getDomainMax(i) - func0->getDomainMin(i)), + func0->getEncodeMin(i)); + // [e01] [efrac] x0 x1 ... xi-1 xi' + writePSFmt("dup 0 lt { pop 0 } { dup %d gt { pop %d } if } ifelse\n", + func0->getSampleSize(i) - 1, func0->getSampleSize(i) - 1); + // [e01] [efrac] x0 x1 ... xi-1 xi' + writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n"); + // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi') + writePSFmt("%d index %d 3 2 roll put\n", i+3, i); + // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') + writePSFmt("%d index %d 3 2 roll put\n", i+3, 2*i+1); + // [e01] [efrac] x0 x1 ... xi-1 floor(xi') + writePSFmt("%d index %d 3 2 roll put\n", i+2, 2*i); + // [e01] [efrac] x0 x1 ... xi-1 + } + // [e01] [efrac] + for (i = 0; i < n; ++i) { + // [e01] [efrac] y(0) ... y(i-1) + for (j = 0; j < (1<> k) & 1)); + for (k = m - 2; k >= 0; --k) { + writePSFmt("%d mul %d index %d get add\n", + func0->getSampleSize(k), + i + j + 3, + 2 * k + ((j >> k) & 1)); + } + if (n > 1) { + writePSFmt("%d mul %d add ", n, i); + } + writePS("get\n"); + } + // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1) + for (j = 0; j < m; ++j) { + // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1) + for (k = 0; k < (1 << (m - j)); k += 2) { + // [e01] [efrac] y(0) ... y(i-1) <2^(m-j)-k s values> + writePSFmt("%d index %d get dup\n", i + k/2 + (1 << (m-j)) - k, j); + writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n"); + writePSFmt("%d 1 roll\n", k/2 + (1 << m-j) - k - 1); + } + // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1) + } + // [e01] [efrac] y(0) ... y(i-1) s + writePSFmt("%g mul %g add\n", + func0->getDecodeMax(i) - func0->getDecodeMin(i), + func0->getDecodeMin(i)); + writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", + func0->getRangeMin(i), func0->getRangeMin(i), + func0->getRangeMax(i), func0->getRangeMax(i)); + // [e01] [efrac] y(0) ... y(i-1) y(i) + } + // [e01] [efrac] y(0) ... y(n-1) + writePSFmt("%d %d roll pop pop }\n", n+2, n); + break; + + case 2: // exponential + func2 = (ExponentialFunction *)func; + n = func2->getOutputSize(); + writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", + func2->getDomainMin(0), func2->getDomainMin(0), + func2->getDomainMax(0), func2->getDomainMax(0)); + // x + for (i = 0; i < n; ++i) { + // x y(0) .. y(i-1) + writePSFmt("%d index %g exp %g mul %g add\n", + i, func2->getE(), func2->getC1()[i] - func2->getC0()[i], + func2->getC0()[i]); + if (func2->getHasRange()) { + writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", + func2->getRangeMin(i), func2->getRangeMin(i), + func2->getRangeMax(i), func2->getRangeMax(i)); + } + } + // x y(0) .. y(n-1) + writePSFmt("%d %d roll pop }\n", n+1, n); + break; + + case 3: // stitching + func3 = (StitchingFunction *)func; + thisFunc = nextFunc++; + for (i = 0; i < func3->getNumFuncs(); ++i) { + cvtFunction(func3->getFunc(i)); + writePSFmt("/xpdfFunc%d_%d exch def\n", thisFunc, i); + } + writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", + func3->getDomainMin(0), func3->getDomainMin(0), + func3->getDomainMax(0), func3->getDomainMax(0)); + for (i = 0; i < func3->getNumFuncs() - 1; ++i) { + writePSFmt("dup %g lt { %g sub %g mul %g add xpdfFunc%d_%d } {\n", + func3->getBounds()[i+1], + func3->getBounds()[i], + (func3->getEncode()[2*i+1] - func3->getEncode()[2*i]) / + (func3->getBounds()[i+1] - func3->getBounds()[i]), + func3->getEncode()[2*i], + thisFunc, i); + } + writePSFmt("%g sub %g mul %g add xpdfFunc%d_%d\n", + func3->getBounds()[i], + (func3->getEncode()[2*i+1] - func3->getEncode()[2*i]) / + (func3->getBounds()[i+1] - func3->getBounds()[i]), + func3->getEncode()[2*i], + thisFunc, i); + for (i = 0; i < func3->getNumFuncs() - 1; ++i) { + writePS("} ifelse\n"); + } + writePS("}\n"); + break; + + case 4: // PostScript + func4 = (PostScriptFunction *)func; + writePS(func4->getCodeString()->getCString()); + writePS("\n"); + break; + } +} + void PSOutputDev::writePSChar(char c) { if (t3String) { t3String->append(c); @@ -3842,23 +4874,28 @@ void PSOutputDev::writePSFmt(const char *fmt, ...) { void PSOutputDev::writePSString(GString *s) { Guchar *p; - int n; + int n, line; char buf[8]; writePSChar('('); + line = 1; for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) { + if (line >= 64) { + writePSChar('\\'); + writePSChar('\n'); + line = 0; + } if (*p == '(' || *p == ')' || *p == '\\') { writePSChar('\\'); writePSChar((char)*p); + line += 2; } else if (*p < 0x20 || *p >= 0x80) { sprintf(buf, "\\%03o", *p); - if (t3String) { - t3String->append(buf); - } else { - (*outputFunc)(outputStream, buf, strlen(buf)); - } + writePS(buf); + line += 4; } else { writePSChar((char)*p); + ++line; } } writePSChar(')'); diff --git a/xpdf/xpdf/PSOutputDev.h b/xpdf/xpdf/PSOutputDev.h index 99b4583e9..d2f3b5518 100644 --- a/xpdf/xpdf/PSOutputDev.h +++ b/xpdf/xpdf/PSOutputDev.h @@ -21,6 +21,7 @@ #include "GlobalParams.h" #include "OutputDev.h" +class Function; class GfxPath; class GfxFont; class GfxColorSpace; @@ -81,6 +82,17 @@ public: // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() { return gFalse; } + // Does this device use tilingPatternFill()? If this returns false, + // tiling pattern fills will be reduced to a series of other drawing + // operations. + virtual GBool useTilingPatternFill() { return gTrue; } + + // Does this device use functionShadedFill(), axialShadedFill(), and + // radialShadedFill()? If this returns false, these shaded fills + // will be reduced to a series of other drawing operations. + virtual GBool useShadedFills() + { return level == psLevel2 || level == psLevel3; } + // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() { return gFalse; } @@ -89,7 +101,8 @@ public: // Write the document-level header. void writeHeader(int firstPage, int lastPage, - PDFRectangle *mediaBox, PDFRectangle *cropBox); + PDFRectangle *mediaBox, PDFRectangle *cropBox, + int pageRotate); // Write the Xpdf procset. void writeXpdfProcset(); @@ -97,9 +110,6 @@ public: // Write the document-level setup. void writeDocSetup(Catalog *catalog, int firstPage, int lastPage); - // Write the setup for the current page. - void writePageSetup(); - // Write the trailer for the current page. void writePageTrailer(); @@ -127,8 +137,12 @@ public: virtual void updateLineCap(GfxState *state); virtual void updateMiterLimit(GfxState *state); virtual void updateLineWidth(GfxState *state); + virtual void updateFillColorSpace(GfxState *state); + virtual void updateStrokeColorSpace(GfxState *state); virtual void updateFillColor(GfxState *state); virtual void updateStrokeColor(GfxState *state); + virtual void updateFillOverprint(GfxState *state); + virtual void updateStrokeOverprint(GfxState *state); //----- update text state virtual void updateFont(GfxState *state); @@ -145,6 +159,15 @@ public: virtual void stroke(GfxState *state); virtual void fill(GfxState *state); virtual void eoFill(GfxState *state); + virtual void tilingPatternFill(GfxState *state, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep); + virtual void functionShadedFill(GfxState *state, + GfxFunctionShading *shading); + virtual void axialShadedFill(GfxState *state, GfxAxialShading *shading); + virtual void radialShadedFill(GfxState *state, GfxRadialShading *shading); //----- path clipping virtual void clip(GfxState *state); @@ -161,6 +184,11 @@ public: virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); #if OPI_SUPPORT //----- OPI functions @@ -208,7 +236,8 @@ private: void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName); GString *setupExternalTrueTypeFont(GfxFont *font); void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName); - void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName); + void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName, + GBool needsVerticalMetrics); GString *setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, int faceIndex=0); void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict); void setupImages(Dict *resDict); @@ -224,8 +253,11 @@ private: Stream *str, int width, int height, int len); void doImageL2(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, - Stream *str, int width, int height, int len); - void dumpColorSpaceL2(GfxColorSpace *colorSpace); + Stream *str, int width, int height, int len, + int *maskColors, Stream *maskStr, + int maskWidth, int maskHeight, GBool maskInvert); + void dumpColorSpaceL2(GfxColorSpace *colorSpace, + GBool genXform, GBool updateColors); #if OPI_SUPPORT void opiBegin20(GfxState *state, Dict *dict); void opiBegin13(GfxState *state, Dict *dict); @@ -233,6 +265,7 @@ private: double *x1, double *y1); GBool getFileSpec(Object *fileSpec, Object *fileName); #endif + void cvtFunction(Function *func); void writePSChar(char c); void writePS(const char *s); void writePSFmt(const char *fmt, ...); @@ -277,6 +310,8 @@ private: GList *xobjStack; // stack of XObject dicts currently being // processed int numSaves; // current number of gsaves + int numTilingPatterns; // current number of nested tiling patterns + int nextFunc; // next unique number to use for a function double tx0, ty0; // global translation double xScale0, yScale0; // global scaling @@ -286,6 +321,8 @@ private: double tx, ty; // global translation for current page double xScale, yScale; // global scaling for current page int rotate; // rotation angle for current page + double epsX1, epsY1, // EPS bounding box (unrotated) + epsX2, epsY2; GString *embFontList; // resource comments for embedded fonts diff --git a/xpdf/xpdf/Page.cc b/xpdf/xpdf/Page.cc index c21adae02..227ba0782 100644 --- a/xpdf/xpdf/Page.cc +++ b/xpdf/xpdf/Page.cc @@ -22,6 +22,7 @@ #include "OutputDev.h" #ifndef PDF_PARSER_ONLY #include "Gfx.h" +#include "GfxState.h" #include "Annot.h" #endif #include "Error.h" @@ -33,7 +34,6 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { Object obj1; - double w, h; // get old/default values if (attrs) { @@ -66,18 +66,6 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { cropBox = mediaBox; } - // if the MediaBox is excessively larger than the CropBox, - // just use the CropBox - limitToCropBox = gFalse; - if (haveCropBox) { - w = 0.25 * (cropBox.x2 - cropBox.x1); - h = 0.25 * (cropBox.y2 - cropBox.y1); - if ((cropBox.x1 - mediaBox.x1) + (mediaBox.x2 - cropBox.x2) > w || - (cropBox.y1 - mediaBox.y1) + (mediaBox.y2 - cropBox.y2) > h) { - limitToCropBox = gTrue; - } - } - // other boxes bleedBox = cropBox; readBox(dict, "BleedBox", &bleedBox); @@ -128,6 +116,7 @@ PageAttrs::~PageAttrs() { GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) { PDFRectangle tmp; + double t; Object obj1, obj2; GBool ok; @@ -163,6 +152,12 @@ GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) { } obj2.free(); if (ok) { + if (tmp.x1 > tmp.x2) { + t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t; + } + if (tmp.y1 > tmp.y2) { + t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t; + } *box = tmp; } } else { @@ -322,22 +317,23 @@ Page::~Page() { } void Page::display(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool crop, + int rotate, GBool useMediaBox, GBool crop, Links *links, Catalog *catalog, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { - displaySlice(out, hDPI, vDPI, rotate, crop, -1, -1, -1, -1, links, catalog, + displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, + -1, -1, -1, -1, links, catalog, abortCheckCbk, abortCheckCbkData); } void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool crop, + int rotate, GBool useMediaBox, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, Links *links, Catalog *catalog, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { #ifndef PDF_PARSER_ONLY - PDFRectangle *mediaBox, *cropBox; + PDFRectangle *mediaBox, *cropBox, *baseBox; PDFRectangle box; Gfx *gfx; Object obj; @@ -353,69 +349,71 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, rotate += 360; } - mediaBox = getBox(); + mediaBox = getMediaBox(); + cropBox = getCropBox(); if (sliceW >= 0 && sliceH >= 0) { + baseBox = useMediaBox ? mediaBox : cropBox; kx = 72.0 / hDPI; ky = 72.0 / vDPI; if (rotate == 90) { if (out->upsideDown()) { - box.x1 = mediaBox->x1 + ky * sliceY; - box.x2 = mediaBox->x1 + ky * (sliceY + sliceH); + box.x1 = baseBox->x1 + ky * sliceY; + box.x2 = baseBox->x1 + ky * (sliceY + sliceH); } else { - box.x1 = mediaBox->x2 - ky * (sliceY + sliceH); - box.x2 = mediaBox->x2 - ky * sliceY; + box.x1 = baseBox->x2 - ky * (sliceY + sliceH); + box.x2 = baseBox->x2 - ky * sliceY; } - box.y1 = mediaBox->y1 + kx * sliceX; - box.y2 = mediaBox->y1 + kx * (sliceX + sliceW); + box.y1 = baseBox->y1 + kx * sliceX; + box.y2 = baseBox->y1 + kx * (sliceX + sliceW); } else if (rotate == 180) { - box.x1 = mediaBox->x2 - kx * (sliceX + sliceW); - box.x2 = mediaBox->x2 - kx * sliceX; + box.x1 = baseBox->x2 - kx * (sliceX + sliceW); + box.x2 = baseBox->x2 - kx * sliceX; if (out->upsideDown()) { - box.y1 = mediaBox->y1 + ky * sliceY; - box.y2 = mediaBox->y1 + ky * (sliceY + sliceH); + box.y1 = baseBox->y1 + ky * sliceY; + box.y2 = baseBox->y1 + ky * (sliceY + sliceH); } else { - box.y1 = mediaBox->y2 - ky * (sliceY + sliceH); - box.y2 = mediaBox->y2 - ky * sliceY; + box.y1 = baseBox->y2 - ky * (sliceY + sliceH); + box.y2 = baseBox->y2 - ky * sliceY; } } else if (rotate == 270) { if (out->upsideDown()) { - box.x1 = mediaBox->x2 - ky * (sliceY + sliceH); - box.x2 = mediaBox->x2 - ky * sliceY; + box.x1 = baseBox->x2 - ky * (sliceY + sliceH); + box.x2 = baseBox->x2 - ky * sliceY; } else { - box.x1 = mediaBox->x1 + ky * sliceY; - box.x2 = mediaBox->x1 + ky * (sliceY + sliceH); + box.x1 = baseBox->x1 + ky * sliceY; + box.x2 = baseBox->x1 + ky * (sliceY + sliceH); } - box.y1 = mediaBox->y2 - kx * (sliceX + sliceW); - box.y2 = mediaBox->y2 - kx * sliceX; + box.y1 = baseBox->y2 - kx * (sliceX + sliceW); + box.y2 = baseBox->y2 - kx * sliceX; } else { - box.x1 = mediaBox->x1 + kx * sliceX; - box.x2 = mediaBox->x1 + kx * (sliceX + sliceW); + box.x1 = baseBox->x1 + kx * sliceX; + box.x2 = baseBox->x1 + kx * (sliceX + sliceW); if (out->upsideDown()) { - box.y1 = mediaBox->y2 - ky * (sliceY + sliceH); - box.y2 = mediaBox->y2 - ky * sliceY; + box.y1 = baseBox->y2 - ky * (sliceY + sliceH); + box.y2 = baseBox->y2 - ky * sliceY; } else { - box.y1 = mediaBox->y1 + ky * sliceY; - box.y2 = mediaBox->y1 + ky * (sliceY + sliceH); + box.y1 = baseBox->y1 + ky * sliceY; + box.y2 = baseBox->y1 + ky * (sliceY + sliceH); } } - } else { + } else if (useMediaBox) { box = *mediaBox; + } else { + box = *cropBox; + crop = gFalse; } - cropBox = getCropBox(); if (globalParams->getPrintCommands()) { printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", - box.x1, box.y1, box.x2, box.y2); - if (isCropped()) { + mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2); printf("***** CropBox = ll:%g,%g ur:%g,%g\n", cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); - } printf("***** Rotate = %d\n", attrs->getRotate()); } gfx = new Gfx(xref, out, num, attrs->getResourceDict(), - hDPI, vDPI, &box, crop && isCropped(), cropBox, rotate, - abortCheckCbk, abortCheckCbkData); + hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL, + rotate, abortCheckCbk, abortCheckCbkData); contents.fetch(xref, &obj); if (!obj.isNull()) { gfx->saveState(); @@ -436,7 +434,7 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, } // draw non-link annotations - annotList = new Annots(xref, annots.fetch(xref, &obj)); + annotList = new Annots(xref, catalog, annots.fetch(xref, &obj)); obj.free(); if (annotList->getNumAnnots() > 0) { if (globalParams->getPrintCommands()) { @@ -452,3 +450,21 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, delete gfx; #endif } + +void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI, + int rotate, GBool upsideDown) { + GfxState *state; + int i; + + rotate += getRotate(); + if (rotate >= 360) { + rotate -= 360; + } else if (rotate < 0) { + rotate += 360; + } + state = new GfxState(hDPI, vDPI, getMediaBox(), rotate, upsideDown); + for (i = 0; i < 6; ++i) { + ctm[i] = state->getCTM()[i]; + } + delete state; +} diff --git a/xpdf/xpdf/Page.h b/xpdf/xpdf/Page.h index 5a527f1b9..8dcb8ef1a 100644 --- a/xpdf/xpdf/Page.h +++ b/xpdf/xpdf/Page.h @@ -51,7 +51,6 @@ public: ~PageAttrs(); // Accessors. - PDFRectangle *getBox() { return limitToCropBox ? &cropBox : &mediaBox; } PDFRectangle *getMediaBox() { return &mediaBox; } PDFRectangle *getCropBox() { return &cropBox; } GBool isCropped() { return haveCropBox; } @@ -83,7 +82,6 @@ private: PDFRectangle mediaBox; PDFRectangle cropBox; GBool haveCropBox; - GBool limitToCropBox; PDFRectangle bleedBox; PDFRectangle trimBox; PDFRectangle artBox; @@ -182,12 +180,17 @@ public: GBool isOk() { return ok; } // Get page parameters. - PDFRectangle *getBox() { return attrs->getBox(); } PDFRectangle *getMediaBox() { return attrs->getMediaBox(); } PDFRectangle *getCropBox() { return attrs->getCropBox(); } GBool isCropped() { return attrs->isCropped(); } - double getWidth() { return attrs->getBox()->x2 - attrs->getBox()->x1; } - double getHeight() { return attrs->getBox()->y2 - attrs->getBox()->y1; } + double getMediaWidth() + { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; } + double getMediaHeight() + { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; } + double getCropWidth() + { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; } + double getCropHeight() + { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; } PDFRectangle *getBleedBox() { return attrs->getBleedBox(); } PDFRectangle *getTrimBox() { return attrs->getTrimBox(); } PDFRectangle *getArtBox() { return attrs->getArtBox(); } @@ -213,19 +216,23 @@ public: // Display a page. void display(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool crop, + int rotate, GBool useMediaBox, GBool crop, Links *links, Catalog *catalog, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); // Display part of a page. void displaySlice(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool crop, + int rotate, GBool useMediaBox, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, Links *links, Catalog *catalog, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); + // Get the page's default CTM. + void getDefaultCTM(double *ctm, double hDPI, double vDPI, + int rotate, GBool upsideDown); + private: XRef *xref; // the xref table for this PDF file diff --git a/xpdf/xpdf/Parser.cc b/xpdf/xpdf/Parser.cc index 08b93aba2..892b72a92 100644 --- a/xpdf/xpdf/Parser.cc +++ b/xpdf/xpdf/Parser.cc @@ -19,9 +19,7 @@ #include "Parser.h" #include "XRef.h" #include "Error.h" -#ifndef NO_DECRYPTION #include "Decrypt.h" -#endif Parser::Parser(XRef *xrefA, Lexer *lexerA) { xref = xrefA; @@ -37,23 +35,17 @@ Parser::~Parser() { delete lexer; } -#ifndef NO_DECRYPTION Object *Parser::getObj(Object *obj, Guchar *fileKey, int keyLength, int objNum, int objGen) { -#else -Object *Parser::getObj(Object *obj) { -#endif const char *key; Stream *str; Object obj2; int num; -#ifndef NO_DECRYPTION Decrypt *decrypt; GString *s; char *p; int i; -#endif // refill buffer after inline image data if (inlineImg == 2) { @@ -69,11 +61,7 @@ Object *Parser::getObj(Object *obj) { shift(); obj->initArray(xref); while (!buf1.isCmd("]") && !buf1.isEOF()) -#ifndef NO_DECRYPTION obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen)); -#else - obj->arrayAdd(getObj(&obj2)); -#endif if (buf1.isEOF()) error(getPos(), "End of file inside array"); shift(); @@ -93,11 +81,7 @@ Object *Parser::getObj(Object *obj) { gfree((void*)key); break; } -#ifndef NO_DECRYPTION obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); -#else - obj->dictAdd(key, getObj(&obj2)); -#endif } } if (buf1.isEOF()) @@ -105,12 +89,10 @@ Object *Parser::getObj(Object *obj) { if (buf2.isCmd("stream")) { if ((str = makeStream(obj))) { obj->initStream(str); -#ifndef NO_DECRYPTION if (fileKey) { str->getBaseStream()->doDecryption(fileKey, keyLength, objNum, objGen); } -#endif } else { obj->free(); obj->initError(); @@ -131,7 +113,6 @@ Object *Parser::getObj(Object *obj) { obj->initInt(num); } -#ifndef NO_DECRYPTION // string } else if (buf1.isString() && fileKey) { buf1.copy(obj); @@ -144,7 +125,6 @@ Object *Parser::getObj(Object *obj) { } delete decrypt; shift(); -#endif // simple object } else { @@ -157,6 +137,7 @@ Object *Parser::getObj(Object *obj) { Stream *Parser::makeStream(Object *dict) { Object obj; + BaseStream *baseStr; Stream *str; Guint pos, endPos, length; @@ -185,13 +166,7 @@ Stream *Parser::makeStream(Object *dict) { if (!lexer->getStream()) { return NULL; } - - // make base stream - str = lexer->getStream()->getBaseStream()->makeSubStream(pos, gTrue, - length, dict); - - // get filters - str = str->addFilters(dict); + baseStr = lexer->getStream()->getBaseStream(); // skip over stream data lexer->setPos(pos + length); @@ -203,9 +178,17 @@ Stream *Parser::makeStream(Object *dict) { shift(); } else { error(getPos(), "Missing 'endstream'"); - str->ignoreLength(); + // kludge for broken PDF files: just add 5k to the length, and + // hope its enough + length += 5000; } + // make base stream + str = baseStr->makeSubStream(pos, gTrue, length, dict); + + // get filters + str = str->addFilters(dict); + return str; } diff --git a/xpdf/xpdf/Parser.h b/xpdf/xpdf/Parser.h index 3bc3ab274..b583baf63 100644 --- a/xpdf/xpdf/Parser.h +++ b/xpdf/xpdf/Parser.h @@ -31,13 +31,9 @@ public: ~Parser(); // Get the next object from the input stream. -#ifndef NO_DECRYPTION Object *getObj(Object *obj, Guchar *fileKey = NULL, int keyLength = 0, int objNum = 0, int objGen = 0); -#else - Object *getObj(Object *obj); -#endif // Get stream. Stream *getStream() { return lexer->getStream(); } diff --git a/xpdf/xpdf/SplashOutputDev.cc b/xpdf/xpdf/SplashOutputDev.cc index 9ccf5b883..35050044a 100644 --- a/xpdf/xpdf/SplashOutputDev.cc +++ b/xpdf/xpdf/SplashOutputDev.cc @@ -18,7 +18,6 @@ #include "GlobalParams.h" #include "Error.h" #include "Object.h" -#include "GfxState.h" #include "GfxFont.h" #include "Link.h" #include "CharCodeToUnicode.h" @@ -38,6 +37,385 @@ #include "Splash.h" #include "SplashOutputDev.h" +//------------------------------------------------------------------------ +// Blend functions +//------------------------------------------------------------------------ + +static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + // note: floor(x / 255) = x >> 8 (for 16-bit x) + blend[i] = (dest[i] * src[i]) >> 8; + } +} + +static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + // note: floor(x / 255) = x >> 8 (for 16-bit x) + blend[i] = dest[i] + src[i] - ((dest[i] * src[i]) >> 8); + } +} + +static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + //~ not sure if this is right + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + // note: floor(x / 255) = x >> 8 (for 16-bit x) + blend[i] = dest[i] < 0x80 ? ((dest[i] * src[i]) >> 8) + : dest[i] + src[i] - ((dest[i] * src[i]) >> 8); + } +} + +static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < src[i] ? dest[i] : src[i]; + } +} + +static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] > src[i] ? dest[i] : src[i]; + } +} + +static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int i, x; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + x = dest[i] + src[i]; + blend[i] = x <= 255 ? x : 255; + } +} + +static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i, x; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + x = dest[i] - (255 - src[i]); + blend[i] = x >= 0 ? x : 0; + } +} + +static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + //~ not sure if this is right + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + // note: floor(x / 255) = x >> 8 (for 16-bit x) + blend[i] = src[i] < 0x80 + ? ((dest[i] * (src[i] * 2)) >> 8) + : 0xff - (((0xff - dest[i]) * (0x1ff - src[i] * 2)) >> 8); + } +} + +static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i, x; + + //~ not sure if this is right + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + if (src[i] < 0x80) { + x = dest[i] - (0x80 - src[i]); + blend[i] = x >= 0 ? x : 0; + } else { + x = dest[i] + (src[i] - 0x80); + blend[i] = x <= 255 ? x : 255; + } + } +} + +static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i]; + } +} + +static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + //~ not sure what this is supposed to do + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i]; + } +} + +static void cvtRGBToHSV(Guchar r, Guchar g, Guchar b, int *h, int *s, int *v) { + int cmax, cmid, cmin, x; + + if (r >= g) { + if (g >= b) { x = 0; cmax = r; cmid = g; cmin = b; } + else if (b >= r) { x = 4; cmax = b; cmid = r; cmin = g; } + else { x = 5; cmax = r; cmid = b; cmin = g; } + } else { + if (r >= b) { x = 1; cmax = g; cmid = r; cmin = b; } + else if (g >= b) { x = 2; cmax = g; cmid = b; cmin = r; } + else { x = 3; cmax = b; cmid = g; cmin = r; } + } + if (cmax == cmin) { + *h = *s = 0; + } else { + *h = x * 60; + if (x & 1) { + *h += ((cmax - cmid) * 60) / (cmax - cmin); + } else { + *h += ((cmid - cmin) * 60) / (cmax - cmin); + } + *s = (255 * (cmax - cmin)) / cmax; + } + *v = cmax; +} + +static void cvtHSVToRGB(int h, int s, int v, Guchar *r, Guchar *g, Guchar *b) { + int x, f, cmax, cmid, cmin; + + if (s == 0) { + *r = *g = *b = v; + } else { + x = h / 60; + f = h % 60; + cmax = v; + if (x & 1) { + cmid = (v * 255 - ((s * f) / 60)) >> 8; + } else { + cmid = (v * (255 - ((s * (60 - f)) / 60))) >> 8; + } + // note: floor(x / 255) = x >> 8 (for 16-bit x) + cmin = (v * (255 - s)) >> 8; + switch (x) { + case 0: *r = cmax; *g = cmid; *b = cmin; break; + case 1: *g = cmax; *r = cmid; *b = cmin; break; + case 2: *g = cmax; *b = cmid; *r = cmin; break; + case 3: *b = cmax; *g = cmid; *r = cmin; break; + case 4: *b = cmax; *r = cmid; *g = cmin; break; + case 5: *r = cmax; *b = cmid; *g = cmin; break; + } + } +} + +static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hs, sd, vd, &blend[0], &blend[1], &blend[2]); + break; + case splashModeBGR8: + cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); + cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); + cvtHSVToRGB(hs, sd, vd, &blend[2], &blend[1], &blend[0]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hs, sd, vd, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[0] = 0xff - g; + blend[0] = 0xff - b; + blend[3] = 0; + break; +#endif + default: + //~ unimplemented + break; + } +} + +static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hd, ss, vd, &blend[0], &blend[1], &blend[2]); + break; + case splashModeBGR8: + cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); + cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); + cvtHSVToRGB(hd, ss, vd, &blend[2], &blend[1], &blend[0]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hd, ss, vd, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[0] = 0xff - g; + blend[0] = 0xff - b; + blend[3] = 0; + break; +#endif + default: + //~ unimplemented + break; + } +} + +static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hs, ss, vd, &blend[0], &blend[1], &blend[2]); + break; + case splashModeBGR8: + cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); + cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); + cvtHSVToRGB(hs, ss, vd, &blend[2], &blend[1], &blend[0]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hs, ss, vd, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[0] = 0xff - g; + blend[0] = 0xff - b; + blend[3] = 0; + break; +#endif + default: + //~ unimplemented + break; + } +} + +static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hd, sd, vs, &blend[0], &blend[1], &blend[2]); + break; + case splashModeBGR8: + cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); + cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); + cvtHSVToRGB(hd, sd, vs, &blend[2], &blend[1], &blend[0]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hd, sd, vs, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[0] = 0xff - g; + blend[0] = 0xff - b; + blend[3] = 0; + break; +#endif + default: + //~ unimplemented + break; + } +} + +// NB: This must match the GfxBlendMode enum defined in GfxState.h. +SplashBlendFunc splashOutBlendFuncs[] = { + NULL, + &splashOutBlendMultiply, + &splashOutBlendScreen, + &splashOutBlendOverlay, + &splashOutBlendDarken, + &splashOutBlendLighten, + &splashOutBlendColorDodge, + &splashOutBlendColorBurn, + &splashOutBlendHardLight, + &splashOutBlendSoftLight, + &splashOutBlendDifference, + &splashOutBlendExclusion, + &splashOutBlendHue, + &splashOutBlendSaturation, + &splashOutBlendColor, + &splashOutBlendLuminosity +}; + //------------------------------------------------------------------------ // Font substitutions //------------------------------------------------------------------------ @@ -67,10 +445,6 @@ static SplashOutFontSubst splashOutSubstFonts[16] = { {"Symbol", 0.576} }; -//------------------------------------------------------------------------ - -#define soutRound(x) ((int)(x + 0.5)) - //------------------------------------------------------------------------ // SplashOutFontFileID //------------------------------------------------------------------------ @@ -159,8 +533,8 @@ T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A, } else { cacheSets = 1; } - cacheData = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize); - cacheTags = (T3FontCacheTag *)gmalloc(cacheSets * cacheAssoc * + cacheData = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize); + cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc, sizeof(T3FontCacheTag)); for (i = 0; i < cacheSets * cacheAssoc; ++i) { cacheTags[i].mru = i & (cacheAssoc - 1); @@ -194,15 +568,21 @@ struct T3GlyphStack { //------------------------------------------------------------------------ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, + int bitmapRowPadA, GBool reverseVideoA, - SplashColor paperColorA) { + SplashColorPtr paperColorA, + GBool bitmapTopDownA, + GBool allowAntialiasA) { colorMode = colorModeA; + bitmapRowPad = bitmapRowPadA; + bitmapTopDown = bitmapTopDownA; + allowAntialias = allowAntialiasA; reverseVideo = reverseVideoA; - paperColor = paperColorA; + splashColorCopy(paperColor, paperColorA); xref = NULL; - bitmap = new SplashBitmap(1, 1, colorMode); + bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, bitmapTopDown); splash = new Splash(bitmap); splash->clear(paperColor); @@ -214,9 +594,6 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, font = NULL; needFontUpdate = gFalse; textClipPath = NULL; - - underlayCbk = NULL; - underlayCbkData = NULL; } SplashOutputDev::~SplashOutputDev() { @@ -250,7 +627,9 @@ void SplashOutputDev::startDoc(XRef *xrefA) { #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H globalParams->getEnableFreeType(), #endif - globalParams->getAntialias()); + allowAntialias && + globalParams->getAntialias() && + colorMode != splashModeMono1); for (i = 0; i < nT3Fonts; ++i) { delete t3FontCache[i]; } @@ -270,14 +649,39 @@ void SplashOutputDev::startPage(int /*pageNum*/, GfxState *state) { if (bitmap) { delete bitmap; } - bitmap = new SplashBitmap(w, h, colorMode); + bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, bitmapTopDown); } splash = new Splash(bitmap); switch (colorMode) { - case splashModeMono1: color.mono1 = 0; break; - case splashModeMono8: color.mono8 = 0; break; - case splashModeRGB8: color.rgb8 = splashMakeRGB8(0, 0, 0); break; - case splashModeBGR8Packed: color.bgr8 = splashMakeBGR8(0, 0, 0); break; + case splashModeMono1: + case splashModeMono8: + color[0] = 0; + break; + case splashModeRGB8: + case splashModeBGR8: + color[0] = color[1] = color[2] = 0; + break; + case splashModeAMono8: + color[0] = 0xff; + color[1] = 0; + break; + case splashModeARGB8: + color[0] = 255; + color[1] = color[2] = color[3] = 0; + break; + case splashModeBGRA8: + color[0] = color[1] = color[2] = 0; + color[3] = 255; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + color[0] = color[1] = color[2] = color[3] = 0; + break; + case splashModeACMYK8: + color[0] = 255; + color[1] = color[2] = color[3] = color[4] = 0; + break; +#endif } splash->setStrokePattern(new SplashSolidColor(color)); splash->setFillPattern(new SplashSolidColor(color)); @@ -287,10 +691,6 @@ void SplashOutputDev::startPage(int /*pageNum*/, GfxState *state) { splash->setMiterLimit(10); splash->setFlatness(1); splash->clear(paperColor); - - if (underlayCbk) { - (*underlayCbk)(underlayCbkData); - } } void SplashOutputDev::endPage() { @@ -299,8 +699,12 @@ void SplashOutputDev::endPage() { void SplashOutputDev::drawLink(Link *link, Catalog */*catalog*/) { double x1, y1, x2, y2; LinkBorderStyle *borderStyle; + double r, g, b; GfxRGB rgb; - double gray; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif double *dash; int dashLength; SplashCoord dashList[20]; @@ -310,12 +714,23 @@ void SplashOutputDev::drawLink(Link *link, Catalog */*catalog*/) { link->getRect(&x1, &y1, &x2, &y2); borderStyle = link->getBorderStyle(); if (borderStyle->getWidth() > 0) { - borderStyle->getColor(&rgb.r, &rgb.g, &rgb.b); - gray = 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b; - if (gray > 1) { - gray = 1; + borderStyle->getColor(&r, &g, &b); + rgb.r = dblToCol(r); + rgb.g = dblToCol(g); + rgb.b = dblToCol(b); + gray = dblToCol(0.299 * r + 0.587 * g + 0.114 * b); + if (gray > gfxColorComp1) { + gray = gfxColorComp1; } +#if SPLASH_CMYK + cmyk.c = gfxColorComp1 - rgb.r; + cmyk.m = gfxColorComp1 - rgb.g; + cmyk.y = gfxColorComp1 - rgb.b; + cmyk.k = 0; + splash->setStrokePattern(getColor(gray, &rgb, &cmyk)); +#else splash->setStrokePattern(getColor(gray, &rgb)); +#endif splash->setLineWidth((SplashCoord)borderStyle->getWidth()); borderStyle->getDash(&dash, &dashLength); if (borderStyle->getType() == linkBorderDashed && dashLength > 0) { @@ -422,33 +837,54 @@ void SplashOutputDev::updateLineWidth(GfxState *state) { } void SplashOutputDev::updateFillColor(GfxState *state) { - double gray; + GfxGray gray; GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif state->getFillGray(&gray); state->getFillRGB(&rgb); +#if SPLASH_CMYK + state->getFillCMYK(&cmyk); + splash->setFillPattern(getColor(gray, &rgb, &cmyk)); +#else splash->setFillPattern(getColor(gray, &rgb)); +#endif } void SplashOutputDev::updateStrokeColor(GfxState *state) { - double gray; + GfxGray gray; GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif state->getStrokeGray(&gray); state->getStrokeRGB(&rgb); +#if SPLASH_CMYK + state->getStrokeCMYK(&cmyk); + splash->setStrokePattern(getColor(gray, &rgb, &cmyk)); +#else splash->setStrokePattern(getColor(gray, &rgb)); +#endif } -SplashPattern *SplashOutputDev::getColor(double gray, GfxRGB *rgb) { +#if SPLASH_CMYK +SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb, + GfxCMYK *cmyk) { +#else +SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) { +#endif SplashPattern *pattern; SplashColor color0, color1; - double r, g, b; + GfxColorComp r, g, b; if (reverseVideo) { - gray = 1 - gray; - r = 1 - rgb->r; - g = 1 - rgb->g; - b = 1 - rgb->b; + gray = gfxColorComp1 - gray; + r = gfxColorComp1 - rgb->r; + g = gfxColorComp1 - rgb->g; + b = gfxColorComp1 - rgb->b; } else { r = rgb->r; g = rgb->g; @@ -458,33 +894,81 @@ SplashPattern *SplashOutputDev::getColor(double gray, GfxRGB *rgb) { pattern = NULL; // make gcc happy switch (colorMode) { case splashModeMono1: - color0.mono1 = 0; - color1.mono1 = 1; + color0[0] = 0; + color1[0] = 1; pattern = new SplashHalftone(color0, color1, splash->getScreen()->copy(), - (SplashCoord)gray); + (SplashCoord)colToDbl(gray)); break; case splashModeMono8: - color1.mono8 = soutRound(255 * gray); + color1[0] = colToByte(gray); + pattern = new SplashSolidColor(color1); + break; + case splashModeAMono8: + color1[0] = 255; + color1[1] = colToByte(gray); pattern = new SplashSolidColor(color1); break; case splashModeRGB8: - color1.rgb8 = splashMakeRGB8(soutRound(255 * r), - soutRound(255 * g), - soutRound(255 * b)); + color1[0] = colToByte(r); + color1[1] = colToByte(g); + color1[2] = colToByte(b); + pattern = new SplashSolidColor(color1); + break; + case splashModeBGR8: + color1[2] = colToByte(r); + color1[1] = colToByte(g); + color1[0] = colToByte(b); + pattern = new SplashSolidColor(color1); + break; + case splashModeARGB8: + color1[0] = 255; + color1[1] = colToByte(r); + color1[2] = colToByte(g); + color1[3] = colToByte(b); + pattern = new SplashSolidColor(color1); + break; + case splashModeBGRA8: + color1[3] = 255; + color1[2] = colToByte(r); + color1[1] = colToByte(g); + color1[0] = colToByte(b); pattern = new SplashSolidColor(color1); break; - case splashModeBGR8Packed: - color1.bgr8 = splashMakeBGR8(soutRound(255 * r), - soutRound(255 * g), - soutRound(255 * b)); +#if SPLASH_CMYK + case splashModeCMYK8: + color1[0] = colToByte(cmyk->c); + color1[1] = colToByte(cmyk->m); + color1[2] = colToByte(cmyk->y); + color1[3] = colToByte(cmyk->k); pattern = new SplashSolidColor(color1); break; + case splashModeACMYK8: + color1[0] = 255; + color1[1] = colToByte(cmyk->c); + color1[2] = colToByte(cmyk->m); + color1[3] = colToByte(cmyk->y); + color1[4] = colToByte(cmyk->k); + pattern = new SplashSolidColor(color1); + break; +#endif } return pattern; } +void SplashOutputDev::updateBlendMode(GfxState *state) { + splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]); +} + +void SplashOutputDev::updateFillOpacity(GfxState *state) { + splash->setFillAlpha((SplashCoord)state->getFillOpacity()); +} + +void SplashOutputDev::updateStrokeOpacity(GfxState *state) { + splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity()); +} + void SplashOutputDev::updateFont(GfxState *state) { GfxFont *gfxFont; GfxFontType fontType; @@ -497,7 +981,6 @@ void SplashOutputDev::updateFont(GfxState *state) { GString *fileName, *substName; char *tmpBuf; int tmpBufLen; -// FILE *tmpFile; Gushort *codeToGID; DisplayFontParam *dfp; CharCodeToUnicode *ctu; @@ -505,7 +988,7 @@ void SplashOutputDev::updateFont(GfxState *state) { SplashCoord mat[4]; const char *name; Unicode uBuf[8]; - int /*c, */substIdx, n, code, cmap; + int substIdx, n, code, cmap; int faceIndex = 0; needFontUpdate = gFalse; @@ -662,7 +1145,7 @@ void SplashOutputDev::updateFont(GfxState *state) { if (cmap < ff->getNumCmaps()) { // map CID -> Unicode -> GID n = ctu->getLength(); - codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort)); + codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); for (code = 0; code < n; ++code) { if (ctu->mapToUnicode(code, uBuf, 8) > 0) { codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]); @@ -682,7 +1165,7 @@ void SplashOutputDev::updateFont(GfxState *state) { } else { if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); - codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort)); + codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), n * sizeof(Gushort)); } else { @@ -743,6 +1226,11 @@ void SplashOutputDev::updateFont(GfxState *state) { // create the scaled font mat[0] = m11; mat[1] = -m12; mat[2] = m21; mat[3] = -m22; + if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.01) { + // avoid a singular (or close-to-singular) matrix + mat[0] = 0.01; mat[1] = 0; + mat[2] = 0; mat[3] = 0.01; + } font = fontEngine->getFont(fontFile, mat); return; @@ -832,7 +1320,8 @@ SplashPath *SplashOutputDev::convertPath(GfxState *state, GfxPath *path) { void SplashOutputDev::drawChar(GfxState *state, double x, double y, double /*dx*/, double /*dy*/, double originX, double originY, - CharCode code, Unicode */*u*/, int /*uLen*/) { + CharCode code, int /*nBytes*/, + Unicode */*u*/, int /*uLen*/) { double x1, y1; SplashPath *path; int render; @@ -1011,7 +1500,7 @@ void SplashOutputDev::endType3Char(GfxState *state) { double *ctm; if (t3GlyphStack->cacheTag) { - memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr().mono8, + memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(), t3GlyphStack->cache->glyphSize); delete bitmap; delete splash; @@ -1110,17 +1599,19 @@ void SplashOutputDev::type3D1(GfxState *state, double /*wx*/, double /*wy*/, // create the temporary bitmap if (colorMode == splashModeMono1) { - bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, splashModeMono1); + bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, + splashModeMono1); splash = new Splash(bitmap); - color.mono1 = 0; + color[0] = 0; splash->clear(color); - color.mono1 = 1; + color[0] = 1; } else { - bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, splashModeMono8); + bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, + splashModeMono8); splash = new Splash(bitmap); - color.mono8 = 0x00; + color[0] = 0x00; splash->clear(color); - color.mono8 = 0xff; + color[0] = 0xff; } splash->setFillPattern(new SplashSolidColor(color)); splash->setStrokePattern(new SplashSolidColor(color)); @@ -1154,24 +1645,25 @@ void SplashOutputDev::endTextObject(GfxState */*state*/) { struct SplashOutImageMaskData { ImageStream *imgStr; - int nPixels, idx; GBool invert; + int width, height, y; }; -GBool SplashOutputDev::imageMaskSrc(void *data, SplashMono1 *pixel) { +GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) { SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data; - Guchar pix; + Guchar *p; + SplashColorPtr q; + int x; - if (imgMaskData->idx >= imgMaskData->nPixels) { + if (imgMaskData->y == imgMaskData->height) { return gFalse; } - //~ use getLine - imgMaskData->imgStr->getPixel(&pix); - if (!imgMaskData->invert) { - pix ^= 1; + for (x = 0, p = imgMaskData->imgStr->getLine(), q = line; + x < imgMaskData->width; + ++x) { + *q++ = *p++ ^ imgMaskData->invert; } - *pixel = pix; - ++imgMaskData->idx; + ++imgMaskData->y; return gTrue; } @@ -1181,7 +1673,6 @@ void SplashOutputDev::drawImageMask(GfxState *state, Object */*ref*/, Stream *st double *ctm; SplashCoord mat[6]; SplashOutImageMaskData imgMaskData; - Guchar pix; ctm = state->getCTM(); mat[0] = ctm[0]; @@ -1193,74 +1684,265 @@ void SplashOutputDev::drawImageMask(GfxState *state, Object */*ref*/, Stream *st imgMaskData.imgStr = new ImageStream(str, width, 1, 1); imgMaskData.imgStr->reset(); - imgMaskData.nPixels = width * height; - imgMaskData.idx = 0; - imgMaskData.invert = invert; + imgMaskData.invert = invert ? 0 : 1; + imgMaskData.width = width; + imgMaskData.height = height; + imgMaskData.y = 0; splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat); if (inlineImg) { - while (imageMaskSrc(&imgMaskData, &pix)) ; + while (imgMaskData.y < height) { + imgMaskData.imgStr->getLine(); + ++imgMaskData.y; + } } delete imgMaskData.imgStr; + str->close(); } struct SplashOutImageData { ImageStream *imgStr; GfxImageColorMap *colorMap; + SplashColorPtr lookup; int *maskColors; - SplashOutputDev *out; - int nPixels, idx; + SplashColorMode colorMode; + int width, height, y; }; -GBool SplashOutputDev::imageSrc(void *data, SplashColor *pixel, - Guchar *alpha) { +GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr line) { SplashOutImageData *imgData = (SplashOutImageData *)data; - Guchar pix[gfxColorMaxComps]; + Guchar *p; + SplashColorPtr q, col; GfxRGB rgb; - double gray; - int i; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + int nComps, x; - if (imgData->idx >= imgData->nPixels) { + if (imgData->y == imgData->height) { return gFalse; } - //~ use getLine - imgData->imgStr->getPixel(pix); - switch (imgData->out->colorMode) { + nComps = imgData->colorMap->getNumPixelComps(); + + if (imgData->lookup) { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, ++p) { + *q++ = imgData->lookup[*p]; + } + break; + case splashModeRGB8: + case splashModeBGR8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, ++p) { + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, ++p) { + col = &imgData->lookup[4 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = col[3]; + } + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } else { + switch (imgData->colorMode) { case splashModeMono1: case splashModeMono8: - imgData->colorMap->getGray(pix, &gray); - pixel->mono8 = soutRound(255 * gray); + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getGray(p, &gray); + *q++ = colToByte(gray); + } break; case splashModeRGB8: - imgData->colorMap->getRGB(pix, &rgb); - pixel->rgb8 = splashMakeRGB8(soutRound(255 * rgb.r), - soutRound(255 * rgb.g), - soutRound(255 * rgb.b)); + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.r); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.b); + } break; - case splashModeBGR8Packed: - imgData->colorMap->getRGB(pix, &rgb); - pixel->bgr8 = splashMakeBGR8(soutRound(255 * rgb.r), - soutRound(255 * rgb.g), - soutRound(255 * rgb.b)); + case splashModeBGR8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.b); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.r); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getCMYK(p, &cmyk); + *q++ = colToByte(cmyk.c); + *q++ = colToByte(cmyk.m); + *q++ = colToByte(cmyk.y); + *q++ = colToByte(cmyk.k); + } break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } + + ++imgData->y; + return gTrue; +} + +GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr line) { + SplashOutImageData *imgData = (SplashOutImageData *)data; + Guchar *p; + SplashColorPtr q, col; + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar alpha; + int nComps, x, i; + + if (imgData->y == imgData->height) { + return gFalse; } - if (imgData->maskColors) { - *alpha = 0; - for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) { - if (pix[i] < imgData->maskColors[2*i] || - pix[i] > imgData->maskColors[2*i+1]) { - *alpha = 1; + nComps = imgData->colorMap->getNumPixelComps(); + + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + alpha = 0; + for (i = 0; i < nComps; ++i) { + if (p[i] < imgData->maskColors[2*i] || + p[i] > imgData->maskColors[2*i+1]) { + alpha = 0xff; break; } } + if (imgData->lookup) { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + *q++ = alpha; + *q++ = imgData->lookup[*p]; + break; + case splashModeRGB8: + *q++ = alpha; + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + break; + case splashModeBGR8: + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + *q++ = alpha; + col = &imgData->lookup[4 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = col[3]; + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } } else { - *alpha = 1; + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData->colorMap->getGray(p, &gray); + *q++ = alpha; + *q++ = colToByte(gray); + break; + case splashModeRGB8: + imgData->colorMap->getRGB(p, &rgb); + *q++ = alpha; + *q++ = colToByte(rgb.r); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.b); + break; + case splashModeBGR8: + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.b); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.r); + *q++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData->colorMap->getCMYK(p, &cmyk); + *q++ = alpha; + *q++ = colToByte(cmyk.c); + *q++ = colToByte(cmyk.m); + *q++ = colToByte(cmyk.y); + *q++ = colToByte(cmyk.k); + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } } - ++imgData->idx; + ++imgData->y; return gTrue; } @@ -1271,8 +1953,15 @@ void SplashOutputDev::drawImage(GfxState *state, Object */*ref*/, Stream *str, double *ctm; SplashCoord mat[6]; SplashOutImageData imgData; - SplashColor pix; - Guchar alpha; + SplashColorMode srcMode; + SplashImageSource src; + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar pix; + int n, i; ctm = state->getCTM(); mat[0] = ctm[0]; @@ -1288,19 +1977,532 @@ void SplashOutputDev::drawImage(GfxState *state, Object */*ref*/, Stream *str, imgData.imgStr->reset(); imgData.colorMap = colorMap; imgData.maskColors = maskColors; - imgData.out = this; - imgData.nPixels = width * height; - imgData.idx = 0; - - splash->drawImage(&imageSrc, &imgData, - (colorMode == splashModeMono1) ? splashModeMono8 - : colorMode, - width, height, mat); + imgData.colorMode = colorMode; + imgData.width = width; + imgData.height = height; + imgData.y = 0; + + // special case for one-channel (monochrome/gray/separation) images: + // build a lookup table here + imgData.lookup = NULL; + if (colorMap->getNumPixelComps() == 1) { + n = 1 << colorMap->getBits(); + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getGray(&pix, &gray); + imgData.lookup[i] = colToByte(gray); + } + break; + case splashModeRGB8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.r); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.b); + } + break; + case splashModeBGR8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.b); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.r); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData.lookup = (SplashColorPtr)gmalloc(4 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getCMYK(&pix, &cmyk); + imgData.lookup[4*i] = colToByte(cmyk.c); + imgData.lookup[4*i+1] = colToByte(cmyk.m); + imgData.lookup[4*i+2] = colToByte(cmyk.y); + imgData.lookup[4*i+3] = colToByte(cmyk.k); + } + break; +#endif + default: + //~ unimplemented + break; + } + } + + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + srcMode = maskColors ? splashModeAMono8 : splashModeMono8; + break; + case splashModeRGB8: + srcMode = maskColors ? splashModeARGB8 : splashModeRGB8; + break; + case splashModeBGR8: + srcMode = maskColors ? splashModeBGRA8 : splashModeBGR8; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + srcMode = maskColors ? splashModeACMYK8 : splashModeCMYK8; + break; +#endif + default: + //~ unimplemented + srcMode = splashModeRGB8; + break; + } + src = maskColors ? &alphaImageSrc : &imageSrc; + splash->drawImage(src, &imgData, srcMode, width, height, mat); if (inlineImg) { - while (imageSrc(&imgData, &pix, &alpha)) ; + while (imgData.y < height) { + imgData.imgStr->getLine(); + ++imgData.y; + } + } + + gfree(imgData.lookup); + delete imgData.imgStr; + str->close(); +} + +struct SplashOutMaskedImageData { + ImageStream *imgStr; + GfxImageColorMap *colorMap; + SplashBitmap *mask; + SplashColorPtr lookup; + SplashColorMode colorMode; + int width, height, y; +}; + +GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr line) { + SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data; + Guchar *p; + SplashColor maskColor; + SplashColorPtr q, col; + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar alpha; + int nComps, x; + + if (imgData->y == imgData->height) { + return gFalse; + } + + nComps = imgData->colorMap->getNumPixelComps(); + + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + imgData->mask->getPixel(x, imgData->y, maskColor); + alpha = maskColor[0] ? 0xff : 0x00; + if (imgData->lookup) { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + *q++ = alpha; + *q++ = imgData->lookup[*p]; + break; + case splashModeRGB8: + *q++ = alpha; + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + break; + case splashModeBGR8: + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + *q++ = alpha; + col = &imgData->lookup[4 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = col[3]; + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } else { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData->colorMap->getGray(p, &gray); + *q++ = alpha; + *q++ = colToByte(gray); + break; + case splashModeRGB8: + imgData->colorMap->getRGB(p, &rgb); + *q++ = alpha; + *q++ = colToByte(rgb.r); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.b); + break; + case splashModeBGR8: + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.b); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.r); + *q++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData->colorMap->getCMYK(p, &cmyk); + *q++ = alpha; + *q++ = colToByte(cmyk.c); + *q++ = colToByte(cmyk.m); + *q++ = colToByte(cmyk.y); + *q++ = colToByte(cmyk.k); + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } + } + + ++imgData->y; + return gTrue; +} + +void SplashOutputDev::drawMaskedImage(GfxState *state, Object */*ref*/, + Stream *str, int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, + int maskHeight, GBool maskInvert) { + double *ctm; + SplashCoord mat[6]; + SplashOutMaskedImageData imgData; + SplashOutImageMaskData imgMaskData; + SplashColorMode srcMode; + SplashBitmap *maskBitmap; + Splash *maskSplash; + SplashColor maskColor; + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar pix; + int n, i; + + //----- scale the mask image to the same size as the source image + + mat[0] = (SplashCoord)width; + mat[1] = 0; + mat[2] = 0; + mat[3] = (SplashCoord)height; + mat[4] = 0; + mat[5] = 0; + imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, 1, 1); + imgMaskData.imgStr->reset(); + imgMaskData.invert = maskInvert ? 0 : 1; + imgMaskData.width = maskWidth; + imgMaskData.height = maskHeight; + imgMaskData.y = 0; + maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1); + maskSplash = new Splash(maskBitmap); + maskColor[0] = 0; + maskSplash->clear(maskColor); + maskColor[0] = 1; + maskSplash->setFillPattern(new SplashSolidColor(maskColor)); + maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData, + maskWidth, maskHeight, mat); + delete imgMaskData.imgStr; + maskStr->close(); + delete maskSplash; + + //----- draw the source image + + ctm = state->getCTM(); + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + + imgData.imgStr = new ImageStream(str, width, + colorMap->getNumPixelComps(), + colorMap->getBits()); + imgData.imgStr->reset(); + imgData.colorMap = colorMap; + imgData.mask = maskBitmap; + imgData.colorMode = colorMode; + imgData.width = width; + imgData.height = height; + imgData.y = 0; + + // special case for one-channel (monochrome/gray/separation) images: + // build a lookup table here + imgData.lookup = NULL; + if (colorMap->getNumPixelComps() == 1) { + n = 1 << colorMap->getBits(); + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getGray(&pix, &gray); + imgData.lookup[i] = colToByte(gray); + } + break; + case splashModeRGB8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.r); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.b); + } + break; + case splashModeBGR8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.b); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.r); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData.lookup = (SplashColorPtr)gmalloc(4 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getCMYK(&pix, &cmyk); + imgData.lookup[4*i] = colToByte(cmyk.c); + imgData.lookup[4*i+1] = colToByte(cmyk.m); + imgData.lookup[4*i+2] = colToByte(cmyk.y); + imgData.lookup[4*i+3] = colToByte(cmyk.k); + } + break; +#endif + default: + //~ unimplemented + break; + } + } + + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + srcMode = splashModeAMono8; + break; + case splashModeRGB8: + srcMode = splashModeARGB8; + break; + case splashModeBGR8: + srcMode = splashModeBGRA8; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + srcMode = splashModeACMYK8; + break; +#endif + default: + //~ unimplemented + srcMode = splashModeARGB8; + break; + } + splash->drawImage(&maskedImageSrc, &imgData, srcMode, width, height, mat); + + delete maskBitmap; + gfree(imgData.lookup); + delete imgData.imgStr; + str->close(); +} + +void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object */*ref*/, + Stream *str, int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap) { + double *ctm; + SplashCoord mat[6]; + SplashOutImageData imgData; + SplashOutImageData imgMaskData; + SplashColorMode srcMode; + SplashBitmap *maskBitmap; + Splash *maskSplash; + SplashColor maskColor; + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar pix; + int n, i; + + ctm = state->getCTM(); + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + + //----- set up the soft mask + + imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, + maskColorMap->getNumPixelComps(), + maskColorMap->getBits()); + imgMaskData.imgStr->reset(); + imgMaskData.colorMap = maskColorMap; + imgMaskData.maskColors = NULL; + imgMaskData.colorMode = splashModeMono8; + imgMaskData.width = maskWidth; + imgMaskData.height = maskHeight; + imgMaskData.y = 0; + n = 1 << maskColorMap->getBits(); + imgMaskData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + maskColorMap->getGray(&pix, &gray); + imgMaskData.lookup[i] = colToByte(gray); + } + maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), + 1, splashModeMono8); + maskSplash = new Splash(maskBitmap); + maskColor[0] = 0; + maskSplash->clear(maskColor); + maskSplash->drawImage(&imageSrc, &imgMaskData, + splashModeMono8, maskWidth, maskHeight, mat); + delete imgMaskData.imgStr; + maskStr->close(); + gfree(imgMaskData.lookup); + delete maskSplash; + splash->setSoftMask(maskBitmap); + + //----- draw the source image + + imgData.imgStr = new ImageStream(str, width, + colorMap->getNumPixelComps(), + colorMap->getBits()); + imgData.imgStr->reset(); + imgData.colorMap = colorMap; + imgData.maskColors = NULL; + imgData.colorMode = colorMode; + imgData.width = width; + imgData.height = height; + imgData.y = 0; + + // special case for one-channel (monochrome/gray/separation) images: + // build a lookup table here + imgData.lookup = NULL; + if (colorMap->getNumPixelComps() == 1) { + n = 1 << colorMap->getBits(); + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getGray(&pix, &gray); + imgData.lookup[i] = colToByte(gray); + } + break; + case splashModeRGB8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.r); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.b); + } + break; + case splashModeBGR8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.b); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.r); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData.lookup = (SplashColorPtr)gmalloc(4 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getCMYK(&pix, &cmyk); + imgData.lookup[4*i] = colToByte(cmyk.c); + imgData.lookup[4*i+1] = colToByte(cmyk.m); + imgData.lookup[4*i+2] = colToByte(cmyk.y); + imgData.lookup[4*i+3] = colToByte(cmyk.k); + } + break; +#endif + default: + //~ unimplemented + break; + } } + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + srcMode = splashModeMono8; + break; + case splashModeRGB8: + srcMode = splashModeRGB8; + break; + case splashModeBGR8: + srcMode = splashModeBGR8; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + srcMode = splashModeCMYK8; + break; +#endif + default: + //~ unimplemented + srcMode = splashModeRGB8; + break; + } + splash->drawImage(&imageSrc, &imgData, srcMode, width, height, mat); + + splash->setSoftMask(NULL); + gfree(imgData.lookup); delete imgData.imgStr; + str->close(); +} + +void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA) { + splashColorCopy(paperColor, paperColorA); } int SplashOutputDev::getBitmapWidth() { @@ -1311,30 +2513,46 @@ int SplashOutputDev::getBitmapHeight() { return bitmap->getHeight(); } -void SplashOutputDev::xorRectangle(int x0, int y0, int x1, int y1, - SplashPattern *pattern) { - SplashPath *path; +SplashBitmap *SplashOutputDev::takeBitmap() { + SplashBitmap *ret; - path = new SplashPath(); - path->moveTo((SplashCoord)x0, (SplashCoord)y0); - path->lineTo((SplashCoord)x1, (SplashCoord)y0); - path->lineTo((SplashCoord)x1, (SplashCoord)y1); - path->lineTo((SplashCoord)x0, (SplashCoord)y1); - path->close(); - splash->setFillPattern(pattern); - splash->xorFill(path, gTrue); - delete path; + ret = bitmap; + bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, bitmapTopDown); + return ret; +} + +void SplashOutputDev::getModRegion(int *xMin, int *yMin, + int *xMax, int *yMax) { + splash->getModRegion(xMin, yMin, xMax, yMax); +} + +void SplashOutputDev::clearModRegion() { + splash->clearModRegion(); } void SplashOutputDev::setFillColor(int r, int g, int b) { GfxRGB rgb; - double gray; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif - rgb.r = r / 255.0; - rgb.g = g / 255.0; - rgb.b = b / 255.0; - gray = 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g; + rgb.r = byteToCol(r); + rgb.g = byteToCol(g); + rgb.b = byteToCol(b); + gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5); + if (gray > gfxColorComp1) { + gray = gfxColorComp1; + } +#if SPLASH_CMYK + cmyk.c = gfxColorComp1 - rgb.r; + cmyk.m = gfxColorComp1 - rgb.g; + cmyk.y = gfxColorComp1 - rgb.b; + cmyk.k = 0; + splash->setFillPattern(getColor(gray, &rgb, &cmyk)); +#else splash->setFillPattern(getColor(gray, &rgb)); +#endif } SplashFont *SplashOutputDev::getFont(GString *name, double *mat) { @@ -1343,7 +2561,10 @@ SplashFont *SplashOutputDev::getFont(GString *name, double *mat) { SplashOutFontFileID *id; SplashFontFile *fontFile; SplashFont *fontObj; - int i; + FoFiTrueType *ff; + Gushort *codeToGID; + Unicode u; + int cmap, i; for (i = 0; i < 16; ++i) { if (!name->cmp(splashOutSubstFonts[i].name)) { @@ -1364,12 +2585,40 @@ SplashFont *SplashOutputDev::getFont(GString *name, double *mat) { // load the font file } else { dfp = globalParams->getDisplayFont(name); - if (dfp->kind != displayFontT1) { + if (dfp && dfp->kind == displayFontT1) { + SplashFontSrc *fontsrc = new SplashFontSrc; + fontsrc->setFile(dfp->t1.fileName, gFalse); + fontFile = fontEngine->loadType1Font(id, fontsrc, winAnsiEncoding); + } else if (dfp && dfp->kind == displayFontTT) { + if (!(ff = FoFiTrueType::load(dfp->tt.fileName->getCString()))) { + return NULL; + } + for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { + if ((ff->getCmapPlatform(cmap) == 3 && + ff->getCmapEncoding(cmap) == 1) || + ff->getCmapPlatform(cmap) == 0) { + break; + } + } + if (cmap == ff->getNumCmaps()) { + delete ff; + return NULL; + } + codeToGID = (Gushort *)gmallocn(256, sizeof(Gushort)); + for (i = 0; i < 256; ++i) { + codeToGID[i] = 0; + if (winAnsiEncoding[i] && + (u = globalParams->mapNameToUnicode(winAnsiEncoding[i]))) { + codeToGID[i] = ff->mapCodeToGID(cmap, u); + } + } + delete ff; + SplashFontSrc *fontsrc = new SplashFontSrc; + fontsrc->setFile(dfp->tt.fileName, gFalse); + fontFile = fontEngine->loadTrueTypeFont(id, fontsrc, codeToGID, 256); + } else { return NULL; } - SplashFontSrc *fontsrc = new SplashFontSrc; - fontsrc->setFile(dfp->t1.fileName, gFalse); - fontFile = fontEngine->loadType1Font(id, fontsrc, winAnsiEncoding); } // create the scaled font diff --git a/xpdf/xpdf/SplashOutputDev.h b/xpdf/xpdf/SplashOutputDev.h index 5051a9c7a..2cd66ab3c 100644 --- a/xpdf/xpdf/SplashOutputDev.h +++ b/xpdf/xpdf/SplashOutputDev.h @@ -17,11 +17,10 @@ #include "gtypes.h" #include "SplashTypes.h" -#include "xpdf_config.h" +#include "config.h" #include "OutputDev.h" +#include "GfxState.h" -class GfxState; -class GfxPath; class Gfx8BitFont; class SplashBitmap; class Splash; @@ -32,7 +31,6 @@ class SplashFont; class T3FontCache; struct T3FontCacheTag; struct T3GlyphStack; -struct GfxRGB; //------------------------------------------------------------------------ @@ -47,8 +45,10 @@ class SplashOutputDev: public OutputDev { public: // Constructor. - SplashOutputDev(SplashColorMode colorModeA, GBool reverseVideoA, - SplashColor paperColorA); + SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, + GBool reverseVideoA, SplashColorPtr paperColorA, + GBool bitmapTopDownA = gTrue, + GBool allowAntialiasA = gTrue); // Destructor. virtual ~SplashOutputDev(); @@ -93,6 +93,9 @@ public: virtual void updateLineWidth(GfxState *state); virtual void updateFillColor(GfxState *state); virtual void updateStrokeColor(GfxState *state); + virtual void updateBlendMode(GfxState *state); + virtual void updateFillOpacity(GfxState *state); + virtual void updateStrokeOpacity(GfxState *state); //----- update text state virtual void updateFont(GfxState *state); @@ -110,7 +113,7 @@ public: virtual void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, - CharCode code, Unicode *u, int uLen); + CharCode code, int nBytes, Unicode *u, int uLen); virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen); @@ -124,6 +127,17 @@ public: virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap); //----- Type 3 font operators virtual void type3D0(GfxState *state, double wx, double wy); @@ -135,20 +149,28 @@ public: // Called to indicate that a new PDF document has been loaded. void startDoc(XRef *xrefA); + void setPaperColor(SplashColorPtr paperColorA); + GBool isReverseVideo() { return reverseVideo; } + void setReverseVideo(GBool reverseVideoA) { reverseVideo = reverseVideoA; } // Get the bitmap and its size. SplashBitmap *getBitmap() { return bitmap; } int getBitmapWidth(); int getBitmapHeight(); + // Returns the last rasterized bitmap, transferring ownership to the + // caller. + SplashBitmap *takeBitmap(); + // Get the Splash object. Splash *getSplash() { return splash; } - // XOR a rectangular region in the bitmap with . - // is passed to Splash::setFillPattern, so it should not be used - // after calling this function. - void xorRectangle(int x0, int y0, int x1, int y1, SplashPattern *pattern); + // Get the modified region. + void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax); + + // Clear the modified region. + void clearModRegion(); // Set the Splash fill color. void setFillColor(int r, int g, int b); @@ -156,20 +178,28 @@ public: // Get a font object for a Base-14 font, using the Latin-1 encoding. SplashFont *getFont(GString *name, double *mat); - void setUnderlayCbk(void (*cbk)(void *data), void *data) - { underlayCbk = cbk; underlayCbkData = data; } + SplashFont *getCurrentFont() { return font; } private: - SplashPattern *getColor(double gray, GfxRGB *rgb); +#if SPLASH_CMYK + SplashPattern *getColor(GfxGray gray, GfxRGB *rgb, GfxCMYK *cmyk); +#else + SplashPattern *getColor(GfxGray gray, GfxRGB *rgb); +#endif SplashPath *convertPath(GfxState *state, GfxPath *path); void drawType3Glyph(T3FontCache *t3Font, T3FontCacheTag *tag, Guchar *data, double x, double y); - static GBool imageMaskSrc(void *data, SplashMono1 *pixel); - static GBool imageSrc(void *data, SplashColor *pixel, Guchar *alpha); + static GBool imageMaskSrc(void *data, SplashColorPtr line); + static GBool imageSrc(void *data, SplashColorPtr line); + static GBool alphaImageSrc(void *data, SplashColorPtr line); + static GBool maskedImageSrc(void *data, SplashColorPtr line); SplashColorMode colorMode; + int bitmapRowPad; + GBool bitmapTopDown; + GBool allowAntialias; GBool reverseVideo; // reverse video mode SplashColor paperColor; // paper color @@ -187,9 +217,6 @@ private: SplashFont *font; // current font GBool needFontUpdate; // set when the font needs to be updated SplashPath *textClipPath; // clipping path built with text object - - void (*underlayCbk)(void *data); - void *underlayCbkData; }; #endif diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc index e0ee890c6..c4c6abfed 100644 --- a/xpdf/xpdf/Stream.cc +++ b/xpdf/xpdf/Stream.cc @@ -25,9 +25,9 @@ #include "xpdf_config.h" #include "Error.h" #include "Object.h" -#ifndef NO_DECRYPTION +#include "Lexer.h" #include "Decrypt.h" -#endif +#include "GfxState.h" #include "Stream.h" #include "JBIG2Stream.h" #include "JPXStream.h" @@ -273,25 +273,19 @@ Stream *Stream::makeFilter(const char *name, Stream *str, Object *params) { BaseStream::BaseStream(Object *dictA) { dict = *dictA; -#ifndef NO_DECRYPTION decrypt = NULL; -#endif } BaseStream::~BaseStream() { dict.free(); -#ifndef NO_DECRYPTION if (decrypt) delete decrypt; -#endif } -#ifndef NO_DECRYPTION void BaseStream::doDecryption(Guchar *fileKey, int keyLength, int objNum, int objGen) { decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); } -#endif //------------------------------------------------------------------------ // FilterStream @@ -330,7 +324,7 @@ ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) { } else { imgLineSize = nVals; } - imgLine = (Guchar *)gmalloc(imgLineSize * sizeof(Guchar)); + imgLine = (Guchar *)gmallocn(imgLineSize, sizeof(Guchar)); imgIdx = nVals; } @@ -446,12 +440,12 @@ int StreamPredictor::getChar() { GBool StreamPredictor::getNextLine() { int curPred; - Guchar upLeftBuf[4]; + Guchar upLeftBuf[gfxColorMaxComps * 2 + 1]; int left, up, upLeft, p, pa, pb, pc; int c; Gulong inBuf, outBuf, bitMask; int inBits, outBits; - int i, j, k; + int i, j, k, kk; // get PNG optimum predictor number if (predictor >= 10) { @@ -464,13 +458,19 @@ GBool StreamPredictor::getNextLine() { } // read the raw line, apply PNG (byte) predictor - upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; + memset(upLeftBuf, 0, pixBytes + 1); for (i = pixBytes; i < rowBytes; ++i) { - upLeftBuf[3] = upLeftBuf[2]; - upLeftBuf[2] = upLeftBuf[1]; - upLeftBuf[1] = upLeftBuf[0]; + for (j = pixBytes; j > 0; --j) { + upLeftBuf[j] = upLeftBuf[j-1]; + } upLeftBuf[0] = predLine[i]; if ((c = str->getRawChar()) == EOF) { + if (i > pixBytes) { + // this ought to return false, but some (broken) PDF files + // contain truncated image data, and Adobe apparently reads the + // last partial line + break; + } return gFalse; } switch (curPred) { @@ -523,30 +523,31 @@ GBool StreamPredictor::getNextLine() { predLine[i] += predLine[i - nComps]; } } else { - upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; + memset(upLeftBuf, 0, nComps + 1); bitMask = (1 << nBits) - 1; inBuf = outBuf = 0; inBits = outBits = 0; j = k = pixBytes; - for (i = 0; i < nVals; ++i) { + for (i = 0; i < width; ++i) { + for (kk = 0; kk < nComps; ++kk) { if (inBits < nBits) { inBuf = (inBuf << 8) | (predLine[j++] & 0xff); inBits += 8; } - upLeftBuf[3] = upLeftBuf[2]; - upLeftBuf[2] = upLeftBuf[1]; - upLeftBuf[1] = upLeftBuf[0]; - upLeftBuf[0] = (upLeftBuf[nComps] + + upLeftBuf[kk] = (upLeftBuf[kk] + (inBuf >> (inBits - nBits))) & bitMask; - outBuf = (outBuf << nBits) | upLeftBuf[0]; inBits -= nBits; + outBuf = (outBuf << nBits) | upLeftBuf[kk]; outBits += nBits; - if (outBits > 8) { + if (outBits >= 8) { predLine[k++] = (Guchar)(outBuf >> (outBits - 8)); + outBits -= 8; + } } } if (outBits > 0) { - predLine[k++] = (Guchar)(outBuf << (8 - outBits)); + predLine[k++] = (Guchar)((outBuf << (8 - outBits)) + + (inBuf & ((1 << (8 - outBits)) - 1))); } } } @@ -597,10 +598,8 @@ void FileStream::reset() { saved = gTrue; bufPtr = bufEnd = buf; bufPos = start; -#ifndef NO_DECRYPTION if (decrypt) decrypt->reset(); -#endif } void FileStream::close() { @@ -618,9 +617,7 @@ void FileStream::close() { GBool FileStream::fillBuf() { int n; -#ifndef NO_DECRYPTION char *p; -#endif bufPos += bufEnd - buf; bufPtr = bufEnd = buf; @@ -637,13 +634,11 @@ GBool FileStream::fillBuf() { if (bufPtr >= bufEnd) { return gFalse; } -#ifndef NO_DECRYPTION if (decrypt) { for (p = buf; p < bufEnd; ++p) { *p = (char)decrypt->decryptByte((Guchar)*p); } } -#endif return gTrue; } @@ -732,11 +727,9 @@ Stream *MemStream::makeSubStream(Guint startA, GBool limited, void MemStream::reset() { bufPtr = buf + start; -#ifndef NO_DECRYPTION if (decrypt) { decrypt->reset(); } -#endif } void MemStream::close() { @@ -760,10 +753,10 @@ void MemStream::setPos(Guint pos, int dir) { void MemStream::moveStart(int delta) { start += delta; + length -= delta; bufPtr = buf + start; } -#ifndef NO_DECRYPTION void MemStream::doDecryption(Guchar *fileKey, int keyLength, int objNum, int objGen) { char *newBuf; @@ -782,7 +775,6 @@ void MemStream::doDecryption(Guchar *fileKey, int keyLength, needFree = gTrue; } } -#endif //------------------------------------------------------------------------ // EmbedStream @@ -953,7 +945,7 @@ int ASCII85Stream::lookChar() { index = 0; do { c[0] = str->getChar(); - } while (c[0] == '\n' || c[0] == '\r'); + } while (Lexer::isSpace(c[0])); if (c[0] == '~' || c[0] == EOF) { eof = gTrue; n = 0; @@ -965,7 +957,7 @@ int ASCII85Stream::lookChar() { for (k = 1; k < 5; ++k) { do { c[k] = str->getChar(); - } while (c[k] == '\n' || c[k] == '\r'); + } while (Lexer::isSpace(c[k])); if (c[k] == '~' || c[k] == EOF) break; } @@ -1178,7 +1170,11 @@ GString *LZWStream::getPSFilter(int psLevel, const char *indent) { if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } - s->append(indent)->append("/LZWDecode filter\n"); + s->append(indent)->append("<< "); + if (!early) { + s->append("/EarlyChange 0 "); + } + s->append(">> /LZWDecode filter\n"); return s; } @@ -1261,11 +1257,14 @@ CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, endOfLine = endOfLineA; byteAlign = byteAlignA; columns = columnsA; + if (columns < 1) { + columns = 1; + } rows = rowsA; endOfBlock = endOfBlockA; black = blackA; - refLine = (short *)gmalloc((columns + 3) * sizeof(short)); - codingLine = (short *)gmalloc((columns + 2) * sizeof(short)); + refLine = (short *)gmallocn(columns + 4, sizeof(short)); + codingLine = (short *)gmallocn(columns + 3, sizeof(short)); eof = gFalse; row = 0; @@ -1387,10 +1386,12 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertL1: + if (a0 == 0 || refLine[b1] - 1 > a0New) { a0New = codingLine[++a0] = refLine[b1] - 1; --b1; while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) b1 += 2; + } break; case twoDimVertR2: a0New = codingLine[++a0] = refLine[b1] + 2; @@ -1401,10 +1402,12 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertL2: + if (a0 == 0 || refLine[b1] - 2 > a0New) { a0New = codingLine[++a0] = refLine[b1] - 2; --b1; while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) b1 += 2; + } break; case twoDimVertR3: a0New = codingLine[++a0] = refLine[b1] + 3; @@ -1415,10 +1418,12 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertL3: + if (a0 == 0 || refLine[b1] - 3 > a0New) { a0New = codingLine[++a0] = refLine[b1] - 3; --b1; while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) b1 += 2; + } break; case EOF: eof = gTrue; @@ -1788,6 +1793,7 @@ GBool CCITTFaxStream::isBinary(GBool /*last*/) { } #if 0 + //------------------------------------------------------------------------ // DCTStream //------------------------------------------------------------------------ @@ -1878,7 +1884,6 @@ DCTStream::~DCTStream() { } void DCTStream::reset() { - int minHSample, minVSample; int i, j; str->reset(); @@ -1900,24 +1905,21 @@ void DCTStream::reset() { } // compute MCU size - mcuWidth = minHSample = compInfo[0].hSample; - mcuHeight = minVSample = compInfo[0].vSample; + if (numComps == 1) { + compInfo[0].hSample = compInfo[0].vSample = 1; + } + mcuWidth = compInfo[0].hSample; + mcuHeight = compInfo[0].vSample; for (i = 1; i < numComps; ++i) { - if (compInfo[i].hSample < minHSample) - minHSample = compInfo[i].hSample; - if (compInfo[i].vSample < minVSample) - minVSample = compInfo[i].vSample; - if (compInfo[i].hSample > mcuWidth) + if (compInfo[i].hSample > mcuWidth) { mcuWidth = compInfo[i].hSample; - if (compInfo[i].vSample > mcuHeight) + } + if (compInfo[i].vSample > mcuHeight) { mcuHeight = compInfo[i].vSample; } - for (i = 0; i < numComps; ++i) { - compInfo[i].hSample /= minHSample; - compInfo[i].vSample /= minVSample; } - mcuWidth = (mcuWidth / minHSample) * 8; - mcuHeight = (mcuHeight / minVSample) * 8; + mcuWidth *= 8; + mcuHeight *= 8; // figure out color transform if (!gotAdobeMarker && numComps == 3) { @@ -1937,7 +1939,7 @@ void DCTStream::reset() { bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight; for (i = 0; i < numComps; ++i) { - frameBuf[i] = (int *)gmalloc(bufWidth * bufHeight * sizeof(int)); + frameBuf[i] = (int *)gmallocn(bufWidth * bufHeight, sizeof(int)); memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int)); } @@ -1962,7 +1964,7 @@ void DCTStream::reset() { bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; for (i = 0; i < numComps; ++i) { for (j = 0; j < mcuHeight; ++j) { - rowBuf[i][j] = (Guchar *)gmalloc(bufWidth * sizeof(Guchar)); + rowBuf[i][j] = (Guchar *)gmallocn(bufWidth, sizeof(Guchar)); } } @@ -2455,7 +2457,7 @@ GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, void DCTStream::decodeImage() { int dataIn[64]; Guchar dataOut[64]; - Guchar *quantTable; + Gushort *quantTable; int pY, pCb, pCr, pR, pG, pB; int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; int h, v, horiz, vert, hSub, vSub; @@ -2594,7 +2596,7 @@ void DCTStream::decodeImage() { // 988-991. // The stage numbers mentioned in the comments refer to Figure 1 in this // paper. -void DCTStream::transformDataUnit(Guchar *quantTable, +void DCTStream::transformDataUnit(Gushort *quantTable, int dataIn[64], Guchar dataOut[64]) { int v0, v1, v2, v3, v4, v5, v6, v7, t; int *p; @@ -2822,12 +2824,13 @@ GBool DCTStream::readHeader() { while (!doScan) { c = readMarker(); switch (c) { - case 0xc0: // SOF0 + case 0xc0: // SOF0 (sequential) + case 0xc1: // SOF1 (extended sequential) if (!readBaselineSOF()) { return gFalse; } break; - case 0xc2: // SOF2 + case 0xc2: // SOF2 (progressive) if (!readProgressiveSOF()) { return gFalse; } @@ -2988,23 +2991,33 @@ GBool DCTStream::readScanInfo() { } GBool DCTStream::readQuantTables() { - int length; - int i; - int index; + int length, prec, i, index; length = read16() - 2; while (length > 0) { index = str->getChar(); - if ((index & 0xf0) || index >= 4) { + prec = (index >> 4) & 0x0f; + index &= 0x0f; + if (prec > 1 || index >= 4) { error(getPos(), "Bad DCT quantization table"); return gFalse; } - if (index == numQuantTables) + if (index == numQuantTables) { numQuantTables = index + 1; - for (i = 0; i < 64; ++i) + } + for (i = 0; i < 64; ++i) { + if (prec) { + quantTables[index][dctZigZag[i]] = read16(); + } else { quantTables[index][dctZigZag[i]] = str->getChar(); + } + } + if (prec) { + length -= 129; + } else { length -= 65; } + } return gTrue; } @@ -3144,7 +3157,7 @@ int DCTStream::readMarker() { do { do { c = str->getChar(); - } while (c != 0xff); + } while (c != 0xff && c != EOF); do { c = str->getChar(); } while (c == 0xff); @@ -3175,9 +3188,10 @@ GString *DCTStream::getPSFilter(int psLevel, const char *indent) { return s; } -GBool DCTStream::isBinary(GBool /*last*/) { +GBool DCTStream::isBinary(GBool last) { return str->isBinary(gTrue); } + #endif //------------------------------------------------------------------------ @@ -3217,6 +3231,8 @@ FlateDecode FlateStream::lengthDecode[flateMaxLitCodes-257] = { {5, 163}, {5, 195}, {5, 227}, + {0, 258}, + {0, 258}, {0, 258} }; @@ -3253,6 +3269,564 @@ FlateDecode FlateStream::distDecode[flateMaxDistCodes] = { {13, 24577} }; +static FlateCode flateFixedLitCodeTabCodes[512] = { + {7, 0x0100}, + {8, 0x0050}, + {8, 0x0010}, + {8, 0x0118}, + {7, 0x0110}, + {8, 0x0070}, + {8, 0x0030}, + {9, 0x00c0}, + {7, 0x0108}, + {8, 0x0060}, + {8, 0x0020}, + {9, 0x00a0}, + {8, 0x0000}, + {8, 0x0080}, + {8, 0x0040}, + {9, 0x00e0}, + {7, 0x0104}, + {8, 0x0058}, + {8, 0x0018}, + {9, 0x0090}, + {7, 0x0114}, + {8, 0x0078}, + {8, 0x0038}, + {9, 0x00d0}, + {7, 0x010c}, + {8, 0x0068}, + {8, 0x0028}, + {9, 0x00b0}, + {8, 0x0008}, + {8, 0x0088}, + {8, 0x0048}, + {9, 0x00f0}, + {7, 0x0102}, + {8, 0x0054}, + {8, 0x0014}, + {8, 0x011c}, + {7, 0x0112}, + {8, 0x0074}, + {8, 0x0034}, + {9, 0x00c8}, + {7, 0x010a}, + {8, 0x0064}, + {8, 0x0024}, + {9, 0x00a8}, + {8, 0x0004}, + {8, 0x0084}, + {8, 0x0044}, + {9, 0x00e8}, + {7, 0x0106}, + {8, 0x005c}, + {8, 0x001c}, + {9, 0x0098}, + {7, 0x0116}, + {8, 0x007c}, + {8, 0x003c}, + {9, 0x00d8}, + {7, 0x010e}, + {8, 0x006c}, + {8, 0x002c}, + {9, 0x00b8}, + {8, 0x000c}, + {8, 0x008c}, + {8, 0x004c}, + {9, 0x00f8}, + {7, 0x0101}, + {8, 0x0052}, + {8, 0x0012}, + {8, 0x011a}, + {7, 0x0111}, + {8, 0x0072}, + {8, 0x0032}, + {9, 0x00c4}, + {7, 0x0109}, + {8, 0x0062}, + {8, 0x0022}, + {9, 0x00a4}, + {8, 0x0002}, + {8, 0x0082}, + {8, 0x0042}, + {9, 0x00e4}, + {7, 0x0105}, + {8, 0x005a}, + {8, 0x001a}, + {9, 0x0094}, + {7, 0x0115}, + {8, 0x007a}, + {8, 0x003a}, + {9, 0x00d4}, + {7, 0x010d}, + {8, 0x006a}, + {8, 0x002a}, + {9, 0x00b4}, + {8, 0x000a}, + {8, 0x008a}, + {8, 0x004a}, + {9, 0x00f4}, + {7, 0x0103}, + {8, 0x0056}, + {8, 0x0016}, + {8, 0x011e}, + {7, 0x0113}, + {8, 0x0076}, + {8, 0x0036}, + {9, 0x00cc}, + {7, 0x010b}, + {8, 0x0066}, + {8, 0x0026}, + {9, 0x00ac}, + {8, 0x0006}, + {8, 0x0086}, + {8, 0x0046}, + {9, 0x00ec}, + {7, 0x0107}, + {8, 0x005e}, + {8, 0x001e}, + {9, 0x009c}, + {7, 0x0117}, + {8, 0x007e}, + {8, 0x003e}, + {9, 0x00dc}, + {7, 0x010f}, + {8, 0x006e}, + {8, 0x002e}, + {9, 0x00bc}, + {8, 0x000e}, + {8, 0x008e}, + {8, 0x004e}, + {9, 0x00fc}, + {7, 0x0100}, + {8, 0x0051}, + {8, 0x0011}, + {8, 0x0119}, + {7, 0x0110}, + {8, 0x0071}, + {8, 0x0031}, + {9, 0x00c2}, + {7, 0x0108}, + {8, 0x0061}, + {8, 0x0021}, + {9, 0x00a2}, + {8, 0x0001}, + {8, 0x0081}, + {8, 0x0041}, + {9, 0x00e2}, + {7, 0x0104}, + {8, 0x0059}, + {8, 0x0019}, + {9, 0x0092}, + {7, 0x0114}, + {8, 0x0079}, + {8, 0x0039}, + {9, 0x00d2}, + {7, 0x010c}, + {8, 0x0069}, + {8, 0x0029}, + {9, 0x00b2}, + {8, 0x0009}, + {8, 0x0089}, + {8, 0x0049}, + {9, 0x00f2}, + {7, 0x0102}, + {8, 0x0055}, + {8, 0x0015}, + {8, 0x011d}, + {7, 0x0112}, + {8, 0x0075}, + {8, 0x0035}, + {9, 0x00ca}, + {7, 0x010a}, + {8, 0x0065}, + {8, 0x0025}, + {9, 0x00aa}, + {8, 0x0005}, + {8, 0x0085}, + {8, 0x0045}, + {9, 0x00ea}, + {7, 0x0106}, + {8, 0x005d}, + {8, 0x001d}, + {9, 0x009a}, + {7, 0x0116}, + {8, 0x007d}, + {8, 0x003d}, + {9, 0x00da}, + {7, 0x010e}, + {8, 0x006d}, + {8, 0x002d}, + {9, 0x00ba}, + {8, 0x000d}, + {8, 0x008d}, + {8, 0x004d}, + {9, 0x00fa}, + {7, 0x0101}, + {8, 0x0053}, + {8, 0x0013}, + {8, 0x011b}, + {7, 0x0111}, + {8, 0x0073}, + {8, 0x0033}, + {9, 0x00c6}, + {7, 0x0109}, + {8, 0x0063}, + {8, 0x0023}, + {9, 0x00a6}, + {8, 0x0003}, + {8, 0x0083}, + {8, 0x0043}, + {9, 0x00e6}, + {7, 0x0105}, + {8, 0x005b}, + {8, 0x001b}, + {9, 0x0096}, + {7, 0x0115}, + {8, 0x007b}, + {8, 0x003b}, + {9, 0x00d6}, + {7, 0x010d}, + {8, 0x006b}, + {8, 0x002b}, + {9, 0x00b6}, + {8, 0x000b}, + {8, 0x008b}, + {8, 0x004b}, + {9, 0x00f6}, + {7, 0x0103}, + {8, 0x0057}, + {8, 0x0017}, + {8, 0x011f}, + {7, 0x0113}, + {8, 0x0077}, + {8, 0x0037}, + {9, 0x00ce}, + {7, 0x010b}, + {8, 0x0067}, + {8, 0x0027}, + {9, 0x00ae}, + {8, 0x0007}, + {8, 0x0087}, + {8, 0x0047}, + {9, 0x00ee}, + {7, 0x0107}, + {8, 0x005f}, + {8, 0x001f}, + {9, 0x009e}, + {7, 0x0117}, + {8, 0x007f}, + {8, 0x003f}, + {9, 0x00de}, + {7, 0x010f}, + {8, 0x006f}, + {8, 0x002f}, + {9, 0x00be}, + {8, 0x000f}, + {8, 0x008f}, + {8, 0x004f}, + {9, 0x00fe}, + {7, 0x0100}, + {8, 0x0050}, + {8, 0x0010}, + {8, 0x0118}, + {7, 0x0110}, + {8, 0x0070}, + {8, 0x0030}, + {9, 0x00c1}, + {7, 0x0108}, + {8, 0x0060}, + {8, 0x0020}, + {9, 0x00a1}, + {8, 0x0000}, + {8, 0x0080}, + {8, 0x0040}, + {9, 0x00e1}, + {7, 0x0104}, + {8, 0x0058}, + {8, 0x0018}, + {9, 0x0091}, + {7, 0x0114}, + {8, 0x0078}, + {8, 0x0038}, + {9, 0x00d1}, + {7, 0x010c}, + {8, 0x0068}, + {8, 0x0028}, + {9, 0x00b1}, + {8, 0x0008}, + {8, 0x0088}, + {8, 0x0048}, + {9, 0x00f1}, + {7, 0x0102}, + {8, 0x0054}, + {8, 0x0014}, + {8, 0x011c}, + {7, 0x0112}, + {8, 0x0074}, + {8, 0x0034}, + {9, 0x00c9}, + {7, 0x010a}, + {8, 0x0064}, + {8, 0x0024}, + {9, 0x00a9}, + {8, 0x0004}, + {8, 0x0084}, + {8, 0x0044}, + {9, 0x00e9}, + {7, 0x0106}, + {8, 0x005c}, + {8, 0x001c}, + {9, 0x0099}, + {7, 0x0116}, + {8, 0x007c}, + {8, 0x003c}, + {9, 0x00d9}, + {7, 0x010e}, + {8, 0x006c}, + {8, 0x002c}, + {9, 0x00b9}, + {8, 0x000c}, + {8, 0x008c}, + {8, 0x004c}, + {9, 0x00f9}, + {7, 0x0101}, + {8, 0x0052}, + {8, 0x0012}, + {8, 0x011a}, + {7, 0x0111}, + {8, 0x0072}, + {8, 0x0032}, + {9, 0x00c5}, + {7, 0x0109}, + {8, 0x0062}, + {8, 0x0022}, + {9, 0x00a5}, + {8, 0x0002}, + {8, 0x0082}, + {8, 0x0042}, + {9, 0x00e5}, + {7, 0x0105}, + {8, 0x005a}, + {8, 0x001a}, + {9, 0x0095}, + {7, 0x0115}, + {8, 0x007a}, + {8, 0x003a}, + {9, 0x00d5}, + {7, 0x010d}, + {8, 0x006a}, + {8, 0x002a}, + {9, 0x00b5}, + {8, 0x000a}, + {8, 0x008a}, + {8, 0x004a}, + {9, 0x00f5}, + {7, 0x0103}, + {8, 0x0056}, + {8, 0x0016}, + {8, 0x011e}, + {7, 0x0113}, + {8, 0x0076}, + {8, 0x0036}, + {9, 0x00cd}, + {7, 0x010b}, + {8, 0x0066}, + {8, 0x0026}, + {9, 0x00ad}, + {8, 0x0006}, + {8, 0x0086}, + {8, 0x0046}, + {9, 0x00ed}, + {7, 0x0107}, + {8, 0x005e}, + {8, 0x001e}, + {9, 0x009d}, + {7, 0x0117}, + {8, 0x007e}, + {8, 0x003e}, + {9, 0x00dd}, + {7, 0x010f}, + {8, 0x006e}, + {8, 0x002e}, + {9, 0x00bd}, + {8, 0x000e}, + {8, 0x008e}, + {8, 0x004e}, + {9, 0x00fd}, + {7, 0x0100}, + {8, 0x0051}, + {8, 0x0011}, + {8, 0x0119}, + {7, 0x0110}, + {8, 0x0071}, + {8, 0x0031}, + {9, 0x00c3}, + {7, 0x0108}, + {8, 0x0061}, + {8, 0x0021}, + {9, 0x00a3}, + {8, 0x0001}, + {8, 0x0081}, + {8, 0x0041}, + {9, 0x00e3}, + {7, 0x0104}, + {8, 0x0059}, + {8, 0x0019}, + {9, 0x0093}, + {7, 0x0114}, + {8, 0x0079}, + {8, 0x0039}, + {9, 0x00d3}, + {7, 0x010c}, + {8, 0x0069}, + {8, 0x0029}, + {9, 0x00b3}, + {8, 0x0009}, + {8, 0x0089}, + {8, 0x0049}, + {9, 0x00f3}, + {7, 0x0102}, + {8, 0x0055}, + {8, 0x0015}, + {8, 0x011d}, + {7, 0x0112}, + {8, 0x0075}, + {8, 0x0035}, + {9, 0x00cb}, + {7, 0x010a}, + {8, 0x0065}, + {8, 0x0025}, + {9, 0x00ab}, + {8, 0x0005}, + {8, 0x0085}, + {8, 0x0045}, + {9, 0x00eb}, + {7, 0x0106}, + {8, 0x005d}, + {8, 0x001d}, + {9, 0x009b}, + {7, 0x0116}, + {8, 0x007d}, + {8, 0x003d}, + {9, 0x00db}, + {7, 0x010e}, + {8, 0x006d}, + {8, 0x002d}, + {9, 0x00bb}, + {8, 0x000d}, + {8, 0x008d}, + {8, 0x004d}, + {9, 0x00fb}, + {7, 0x0101}, + {8, 0x0053}, + {8, 0x0013}, + {8, 0x011b}, + {7, 0x0111}, + {8, 0x0073}, + {8, 0x0033}, + {9, 0x00c7}, + {7, 0x0109}, + {8, 0x0063}, + {8, 0x0023}, + {9, 0x00a7}, + {8, 0x0003}, + {8, 0x0083}, + {8, 0x0043}, + {9, 0x00e7}, + {7, 0x0105}, + {8, 0x005b}, + {8, 0x001b}, + {9, 0x0097}, + {7, 0x0115}, + {8, 0x007b}, + {8, 0x003b}, + {9, 0x00d7}, + {7, 0x010d}, + {8, 0x006b}, + {8, 0x002b}, + {9, 0x00b7}, + {8, 0x000b}, + {8, 0x008b}, + {8, 0x004b}, + {9, 0x00f7}, + {7, 0x0103}, + {8, 0x0057}, + {8, 0x0017}, + {8, 0x011f}, + {7, 0x0113}, + {8, 0x0077}, + {8, 0x0037}, + {9, 0x00cf}, + {7, 0x010b}, + {8, 0x0067}, + {8, 0x0027}, + {9, 0x00af}, + {8, 0x0007}, + {8, 0x0087}, + {8, 0x0047}, + {9, 0x00ef}, + {7, 0x0107}, + {8, 0x005f}, + {8, 0x001f}, + {9, 0x009f}, + {7, 0x0117}, + {8, 0x007f}, + {8, 0x003f}, + {9, 0x00df}, + {7, 0x010f}, + {8, 0x006f}, + {8, 0x002f}, + {9, 0x00bf}, + {8, 0x000f}, + {8, 0x008f}, + {8, 0x004f}, + {9, 0x00ff} +}; + +FlateHuffmanTab FlateStream::fixedLitCodeTab = { + flateFixedLitCodeTabCodes, 9 +}; + +static FlateCode flateFixedDistCodeTabCodes[32] = { + {5, 0x0000}, + {5, 0x0010}, + {5, 0x0008}, + {5, 0x0018}, + {5, 0x0004}, + {5, 0x0014}, + {5, 0x000c}, + {5, 0x001c}, + {5, 0x0002}, + {5, 0x0012}, + {5, 0x000a}, + {5, 0x001a}, + {5, 0x0006}, + {5, 0x0016}, + {5, 0x000e}, + {0, 0x0000}, + {5, 0x0001}, + {5, 0x0011}, + {5, 0x0009}, + {5, 0x0019}, + {5, 0x0005}, + {5, 0x0015}, + {5, 0x000d}, + {5, 0x001d}, + {5, 0x0003}, + {5, 0x0013}, + {5, 0x000b}, + {5, 0x001b}, + {5, 0x0007}, + {5, 0x0017}, + {5, 0x000f}, + {0, 0x0000} +}; + +FlateHuffmanTab FlateStream::fixedDistCodeTab = { + flateFixedDistCodeTabCodes, 5 +}; + FlateStream::FlateStream(Stream *strA, int predictor, int columns, int colors, int bits): FilterStream(strA) { @@ -3266,8 +3840,12 @@ FlateStream::FlateStream(Stream *strA, int predictor, int columns, } FlateStream::~FlateStream() { + if (litCodeTab.codes != fixedLitCodeTab.codes) { gfree(litCodeTab.codes); + } + if (distCodeTab.codes != fixedDistCodeTab.codes) { gfree(distCodeTab.codes); + } if (pred) { delete pred; } @@ -3444,9 +4022,13 @@ GBool FlateStream::startBlock() { int check; // free the code tables from the previous block + if (litCodeTab.codes != fixedLitCodeTab.codes) { gfree(litCodeTab.codes); + } litCodeTab.codes = NULL; + if (distCodeTab.codes != fixedDistCodeTab.codes) { gfree(distCodeTab.codes); + } distCodeTab.codes = NULL; // read block header @@ -3502,28 +4084,10 @@ err: } void FlateStream::loadFixedCodes() { - int i; - - // build the literal code table - for (i = 0; i <= 143; ++i) { - codeLengths[i] = 8; - } - for (i = 144; i <= 255; ++i) { - codeLengths[i] = 9; - } - for (i = 256; i <= 279; ++i) { - codeLengths[i] = 7; - } - for (i = 280; i <= 287; ++i) { - codeLengths[i] = 8; - } - compHuffmanCodes(codeLengths, flateMaxLitCodes, &litCodeTab); - - // build the distance code table - for (i = 0; i < flateMaxDistCodes; ++i) { - codeLengths[i] = 5; - } - compHuffmanCodes(codeLengths, flateMaxDistCodes, &distCodeTab); + litCodeTab.codes = fixedLitCodeTab.codes; + litCodeTab.maxLen = fixedLitCodeTab.maxLen; + distCodeTab.codes = fixedDistCodeTab.codes; + distCodeTab.maxLen = fixedDistCodeTab.maxLen; } GBool FlateStream::readDynamicCodes() { @@ -3641,7 +4205,7 @@ void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) { // allocate the table tabSize = 1 << tab->maxLen; - tab->codes = (FlateCode *)gmalloc(tabSize * sizeof(FlateCode)); + tab->codes = (FlateCode *)gmallocn(tabSize, sizeof(FlateCode)); // clear the table for (i = 0; i < tabSize; ++i) { diff --git a/xpdf/xpdf/Stream.h b/xpdf/xpdf/Stream.h index bc1e077c8..00f4c79a6 100644 --- a/xpdf/xpdf/Stream.h +++ b/xpdf/xpdf/Stream.h @@ -19,9 +19,7 @@ #include "gtypes.h" #include "Object.h" -#ifndef NO_DECRYPTION class Decrypt; -#endif class BaseStream; //------------------------------------------------------------------------ @@ -40,6 +38,13 @@ enum StreamKind { strWeird // internal-use stream types }; +enum StreamColorSpaceMode { + streamCSNone, + streamCSDeviceGray, + streamCSDeviceRGB, + streamCSDeviceCMYK +}; + //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ @@ -102,15 +107,14 @@ public: // Is this an encoding filter? virtual GBool isEncoder() { return gFalse; } + // Get image parameters which are defined by the stream contents. + virtual void getImageParams(int */*bitsPerComponent*/, + StreamColorSpaceMode */*csMode*/) {} + // Add filters to this stream according to the parameters in . // Returns the new stream. Stream *addFilters(Object *dict); - // Tell this stream to ignore any length limitation -- this only - // applies to BaseStream subclasses, and is used as a hack to work - // around broken PDF files with incorrect stream lengths. - virtual void ignoreLength() {} - private: Stream *makeFilter(const char *name, Stream *str, Object *params); @@ -140,17 +144,13 @@ public: virtual Guint getStart() = 0; virtual void moveStart(int delta) = 0; -#ifndef NO_DECRYPTION // Set decryption for this stream. virtual void doDecryption(Guchar *fileKey, int keyLength, int objNum, int objGen); -#endif -#ifndef NO_DECRYPTION protected: Decrypt *decrypt; -#endif private: @@ -173,7 +173,6 @@ public: virtual void setPos(Guint pos, int dir = 0); virtual BaseStream *getBaseStream() { return str->getBaseStream(); } virtual Dict *getDict() { return str->getDict(); } - virtual void ignoreLength() { str->ignoreLength(); } protected: @@ -275,7 +274,6 @@ public: { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual int getPos() { return bufPos + (bufPtr - buf); } virtual void setPos(Guint pos, int dir = 0); - virtual void ignoreLength() { limited = gFalse; } virtual Guint getStart() { return start; } virtual void moveStart(int delta); @@ -317,10 +315,8 @@ public: virtual void setPos(Guint pos, int dir = 0); virtual Guint getStart() { return start; } virtual void moveStart(int delta); -#ifndef NO_DECRYPTION virtual void doDecryption(Guchar *fileKey, int keyLength, int objNum, int objGen); -#endif private: @@ -594,7 +590,7 @@ private: GBool gotJFIFMarker; // set if APP0 JFIF marker was present GBool gotAdobeMarker; // set if APP14 Adobe marker was present int restartInterval; // restart interval, in MCUs - Guchar quantTables[4][64]; // quantization tables + Gushort quantTables[4][64]; // quantization tables int numQuantTables; // number of quantization tables DCTHuffTable dcHuffTables[4]; // DC Huffman tables DCTHuffTable acHuffTables[4]; // AC Huffman tables @@ -619,7 +615,7 @@ private: DCTHuffTable *acHuffTable, int *prevDC, int data[64]); void decodeImage(); - void transformDataUnit(Guchar *quantTable, + void transformDataUnit(Gushort *quantTable, int dataIn[64], Guchar dataOut[64]); int readHuffSym(DCTHuffTable *table); int readAmp(int size); @@ -704,6 +700,10 @@ private: lengthDecode[flateMaxLitCodes-257]; static FlateDecode // distance decoding info distDecode[flateMaxDistCodes]; + static FlateHuffmanTab // fixed literal code table + fixedLitCodeTab; + static FlateHuffmanTab // fixed distance code table + fixedDistCodeTab; void readSome(); GBool startBlock(); diff --git a/xpdf/xpdf/TextOutputDev.cc b/xpdf/xpdf/TextOutputDev.cc index 7be4298e4..c74228fa6 100644 --- a/xpdf/xpdf/TextOutputDev.cc +++ b/xpdf/xpdf/TextOutputDev.cc @@ -221,9 +221,9 @@ TextWord::TextWord(GfxState *state, int rotA, double x0, double y0, } else { state->getFillRGB(&rgb); } - colorR = rgb.r; - colorG = rgb.g; - colorB = rgb.b; + colorR = colToDbl(rgb.r); + colorG = colToDbl(rgb.g); + colorB = colToDbl(rgb.b); #endif } @@ -236,8 +236,8 @@ void TextWord::addChar(GfxState */*state*/, double x, double y, double dx, double dy, Unicode u) { if (len == size) { size += 16; - text = (Unicode *)grealloc(text, size * sizeof(Unicode)); - edge = (double *)grealloc(edge, (size + 1) * sizeof(double)); + text = (Unicode *)greallocn(text, size, sizeof(Unicode)); + edge = (double *)greallocn(edge, size + 1, sizeof(double)); } text[len] = u; switch (rot) { @@ -290,8 +290,8 @@ void TextWord::merge(TextWord *word) { } if (len + word->len > size) { size = len + word->len; - text = (Unicode *)grealloc(text, size * sizeof(Unicode)); - edge = (double *)grealloc(edge, (size + 1) * sizeof(double)); + text = (Unicode *)greallocn(text, size, sizeof(Unicode)); + edge = (double *)greallocn(edge, size + 1, sizeof(double)); } for (i = 0; i < word->len; ++i) { text[len + i] = word->text[i]; @@ -426,14 +426,14 @@ void TextPool::addWord(TextWord *word) { if (minBaseIdx > maxBaseIdx) { minBaseIdx = wordBaseIdx - 128; maxBaseIdx = wordBaseIdx + 128; - pool = (TextWord **)gmalloc((maxBaseIdx - minBaseIdx + 1) * + pool = (TextWord **)gmallocn(maxBaseIdx - minBaseIdx + 1, sizeof(TextWord *)); for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) { pool[baseIdx - minBaseIdx] = NULL; } } else if (wordBaseIdx < minBaseIdx) { newMinBaseIdx = wordBaseIdx - 128; - newPool = (TextWord **)gmalloc((maxBaseIdx - newMinBaseIdx + 1) * + newPool = (TextWord **)gmallocn(maxBaseIdx - newMinBaseIdx + 1, sizeof(TextWord *)); for (baseIdx = newMinBaseIdx; baseIdx < minBaseIdx; ++baseIdx) { newPool[baseIdx - newMinBaseIdx] = NULL; @@ -445,7 +445,7 @@ void TextPool::addWord(TextWord *word) { minBaseIdx = newMinBaseIdx; } else if (wordBaseIdx > maxBaseIdx) { newMaxBaseIdx = wordBaseIdx + 128; - pool = (TextWord **)grealloc(pool, (newMaxBaseIdx - minBaseIdx + 1) * + pool = (TextWord **)greallocn(pool, newMaxBaseIdx - minBaseIdx + 1, sizeof(TextWord *)); for (baseIdx = maxBaseIdx + 1; baseIdx <= newMaxBaseIdx; ++baseIdx) { pool[baseIdx - minBaseIdx] = NULL; @@ -668,8 +668,8 @@ void TextLine::coalesce(UnicodeMap *uMap) { ++len; } } - text = (Unicode *)gmalloc(len * sizeof(Unicode)); - edge = (double *)gmalloc((len + 1) * sizeof(double)); + text = (Unicode *)gmallocn(len, sizeof(Unicode)); + edge = (double *)gmallocn(len + 1, sizeof(double)); i = 0; for (word1 = words; word1; word1 = word1->next) { for (j = 0; j < word1->len; ++j) { @@ -685,7 +685,7 @@ void TextLine::coalesce(UnicodeMap *uMap) { } // compute convertedLen and set up the col array - col = (int *)gmalloc((len + 1) * sizeof(int)); + col = (int *)gmallocn(len + 1, sizeof(int)); convertedLen = 0; for (i = 0; i < len; ++i) { col[i] = convertedLen; @@ -869,22 +869,22 @@ int TextLineFrag::cmpYXPrimaryRot(const void *p1, const void *p2) { cmp = 0; // make gcc happy switch (frag1->line->blk->page->primaryRot) { case 0: - if ((cmp = frag1->yMin - frag2->yMin) == 0) { + if (fabs(cmp = frag1->yMin - frag2->yMin) < 0.01) { cmp = frag1->xMin - frag2->xMin; } break; case 1: - if ((cmp = frag2->xMax - frag1->xMax) == 0) { + if (fabs(cmp = frag2->xMax - frag1->xMax) < 0.01) { cmp = frag1->yMin - frag2->yMin; } break; case 2: - if ((cmp = frag2->yMin - frag1->yMin) == 0) { + if (fabs(cmp = frag2->yMin - frag1->yMin) < 0.01) { cmp = frag2->xMax - frag1->xMax; } break; case 3: - if ((cmp = frag1->xMax - frag2->xMax) == 0) { + if (fabs(cmp = frag1->xMax - frag2->xMax) < 0.01) { cmp = frag2->yMax - frag1->yMax; } break; @@ -1190,7 +1190,7 @@ void TextBlock::coalesce(UnicodeMap *uMap) { } // sort lines into xy order for column assignment - lineArray = (TextLine **)gmalloc(nLines * sizeof(TextLine *)); + lineArray = (TextLine **)gmallocn(nLines, sizeof(TextLine *)); for (line = lines, i = 0; line; line = line->next, ++i) { lineArray[i] = line; } @@ -1538,7 +1538,7 @@ TextWordList::TextWordList(TextPage *text, GBool physLayout) { } } } - wordArray = (TextWord **)gmalloc(nWords * sizeof(TextWord *)); + wordArray = (TextWord **)gmallocn(nWords, sizeof(TextWord *)); i = 0; for (flow = text->flows; flow; flow = flow->next) { for (blk = flow->blocks; blk; blk = blk->next) { @@ -1757,7 +1757,7 @@ void TextPage::updateFont(GfxState *state) { } void TextPage::beginWord(GfxState *state, double x0, double y0) { - double *txtm, *ctm, *fontm; + double *fontm; double m[4], m2[4]; int rot; @@ -1770,12 +1770,7 @@ void TextPage::beginWord(GfxState *state, double x0, double y0) { } // compute the rotation - txtm = state->getTextMat(); - ctm = state->getCTM(); - m[0] = txtm[0] * ctm[0] + txtm[1] * ctm[2]; - m[1] = txtm[0] * ctm[1] + txtm[1] * ctm[3]; - m[2] = txtm[2] * ctm[0] + txtm[3] * ctm[2]; - m[3] = txtm[2] * ctm[1] + txtm[3] * ctm[3]; + state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]); if (state->getFont()->getType() == fontType3) { fontm = state->getFont()->getFontMatrix(); m2[0] = fontm[0] * m[0] + fontm[1] * m[2]; @@ -1798,20 +1793,16 @@ void TextPage::beginWord(GfxState *state, double x0, double y0) { void TextPage::addChar(GfxState *state, double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - double x1, y1, w1, h1, dx2, dy2, base, sp; + CharCode c, int nBytes, Unicode *u, int uLen) { + double x1, y1, w1, h1, dx2, dy2, base, sp, delta; + GBool overlap; int i; - // if the previous char was a space, addChar will have called - // endWord, so we need to start a new word - if (!curWord) { - beginWord(state, x, y); - } - // throw away chars that aren't inside the page bounds state->transform(x, y, &x1, &y1); if (x1 < 0 || x1 > pageWidth || y1 < 0 || y1 > pageHeight) { + charPos += nBytes; return; } @@ -1829,60 +1820,72 @@ void TextPage::addChar(GfxState *state, double x, double y, if (!globalParams->getTextKeepTinyChars() && fabs(w1) < 3 && fabs(h1) < 3) { if (++nTinyChars > 50000) { + charPos += nBytes; return; } } // break words at space character if (uLen == 1 && u[0] == (Unicode)0x20) { + if (curWord) { ++curWord->charLen; - ++charPos; + } + charPos += nBytes; endWord(); return; } // start a new word if: - // (1) this character's baseline doesn't match the current word's - // baseline, or - // (2) there is space between the end of the current word and this - // character, or - // (3) this character overlaps the previous one (duplicated text), or - // (4) the previous character was an overlap (we want each duplicated - // characters to be in a word by itself) - base = sp = 0; // make gcc happy - if (curWord->len > 0) { + // (1) this character doesn't fall in the right place relative to + // the end of the previous word (this places upper and lower + // constraints on the position deltas along both the primary + // and secondary axes), or + // (2) this character overlaps the previous one (duplicated text), or + // (3) the previous character was an overlap (we want each duplicated + // character to be in a word by itself at this stage) + if (curWord && curWord->len > 0) { + base = sp = delta = 0; // make gcc happy switch (curWord->rot) { case 0: base = y1; sp = x1 - curWord->xMax; + delta = x1 - curWord->edge[curWord->len - 1]; break; case 1: base = x1; sp = y1 - curWord->yMax; + delta = y1 - curWord->edge[curWord->len - 1]; break; case 2: base = y1; sp = curWord->xMin - x1; + delta = curWord->edge[curWord->len - 1] - x1; break; case 3: base = x1; sp = curWord->yMin - y1; + delta = curWord->edge[curWord->len - 1] - y1; break; } - if (fabs(base - curWord->base) > 0.5 || - sp > minWordBreakSpace * curWord->fontSize || + overlap = fabs(delta) < dupMaxPriDelta * curWord->fontSize && + fabs(base - curWord->base) < dupMaxSecDelta * curWord->fontSize; + if (overlap || lastCharOverlap || sp < -minDupBreakOverlap * curWord->fontSize || - lastCharOverlap) { - lastCharOverlap = gTrue; + sp > minWordBreakSpace * curWord->fontSize || + fabs(base - curWord->base) > 0.5) { endWord(); - beginWord(state, x, y); - } else { - lastCharOverlap = gFalse; } + lastCharOverlap = overlap; } else { lastCharOverlap = gFalse; } + if (uLen != 0) { + // start a new word if needed + if (!curWord) { + beginWord(state, x, y); + } + // page rotation and/or transform matrices can cause text to be // drawn in reverse order -- in this case, swap the begin/end // coordinates and break text into individual chars @@ -1899,15 +1902,16 @@ void TextPage::addChar(GfxState *state, double x, double y, } // add the characters to the current word - if (uLen != 0) { w1 /= uLen; h1 /= uLen; - } for (i = 0; i < uLen; ++i) { curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]); } - ++curWord->charLen; - ++charPos; + } + if (curWord) { + curWord->charLen += nBytes; + } + charPos += nBytes; } void TextPage::endWord() { @@ -1981,9 +1985,9 @@ void TextPage::coalesce(GBool /*physLayout*/) { pool = pools[rot]; for (baseIdx = pool->minBaseIdx; baseIdx <= pool->maxBaseIdx; ++baseIdx) { for (word0 = pool->getPool(baseIdx); word0; word0 = word0->next) { - printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f '", + printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f rot=%d '", word0->xMin, word0->xMax, word0->yMin, word0->yMax, - word0->base, word0->fontSize); + word0->base, word0->fontSize, rot*90); for (i = 0; i < word0->len; ++i) { fputc(word0->text[i] & 0xff, stdout); } @@ -2365,7 +2369,7 @@ void TextPage::coalesce(GBool /*physLayout*/) { //----- column assignment // sort blocks into xy order for column assignment - blocks = (TextBlock **)gmalloc(nBlocks * sizeof(TextBlock *)); + blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *)); for (blk = blkList, i = 0; blk; blk = blk->next, ++i) { blocks[i] = blk; } @@ -2382,6 +2386,8 @@ void TextPage::coalesce(GBool /*physLayout*/) { case 0: if (blk0->xMin > blk1->xMax) { col2 = blk1->col + blk1->nColumns + 3; + } else if (blk1->xMax == blk1->xMin) { + col2 = blk1->col; } else { col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) / (blk1->xMax - blk1->xMin)) * @@ -2391,6 +2397,8 @@ void TextPage::coalesce(GBool /*physLayout*/) { case 1: if (blk0->yMin > blk1->yMax) { col2 = blk1->col + blk1->nColumns + 3; + } else if (blk1->yMax == blk1->yMin) { + col2 = blk1->col; } else { col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) / (blk1->yMax - blk1->yMin)) * @@ -2400,6 +2408,8 @@ void TextPage::coalesce(GBool /*physLayout*/) { case 2: if (blk0->xMax < blk1->xMin) { col2 = blk1->col + blk1->nColumns + 3; + } else if (blk1->xMin == blk1->xMax) { + col2 = blk1->col; } else { col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) / (blk1->xMin - blk1->xMax)) * @@ -2409,6 +2419,8 @@ void TextPage::coalesce(GBool /*physLayout*/) { case 3: if (blk0->yMax < blk1->yMin) { col2 = blk1->col + blk1->nColumns + 3; + } else if (blk1->yMin == blk1->yMax) { + col2 = blk1->col; } else { col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) / (blk1->yMin - blk1->yMax)) * @@ -2492,7 +2504,7 @@ void TextPage::coalesce(GBool /*physLayout*/) { // build the flows //~ this needs to be adjusted for writing mode (vertical text) //~ this also needs to account for right-to-left column ordering - blkArray = (TextBlock **)gmalloc(nBlocks * sizeof(TextBlock *)); + blkArray = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *)); memcpy(blkArray, blocks, nBlocks * sizeof(TextBlock *)); flows = lastFlow = NULL; firstBlkIdx = 0; @@ -2613,13 +2625,14 @@ void TextPage::coalesce(GBool /*physLayout*/) { GBool TextPage::findText(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, + GBool caseSensitive, GBool backward, double *xMin, double *yMin, double *xMax, double *yMax) { TextBlock *blk; TextLine *line; + Unicode *s2, *txt; Unicode *p; - Unicode u1, u2; - int m, i, j, k; + int txtSize, m, i, j, k; double xStart, yStart, xStop, yStop; double xMin0, yMin0, xMax0, yMax0; double xMin1, yMin1, xMax1, yMax1; @@ -2631,6 +2644,19 @@ GBool TextPage::findText(Unicode *s, int len, return gFalse; } + // convert the search string to uppercase + if (!caseSensitive) { + s2 = (Unicode *)gmallocn(len, sizeof(Unicode)); + for (i = 0; i < len; ++i) { + s2[i] = unicodeToUpper(s[i]); + } + } else { + s2 = s; + } + + txt = NULL; + txtSize = 0; + xStart = yStart = xStop = yStop = 0; if (startAtLast && haveLastFind) { xStart = lastFindXMin; @@ -2651,51 +2677,57 @@ GBool TextPage::findText(Unicode *s, int len, xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy - for (i = 0; i < nBlocks; ++i) { + for (i = backward ? nBlocks - 1 : 0; + backward ? i >= 0 : i < nBlocks; + i += backward ? -1 : 1) { blk = blocks[i]; // check: is the block above the top limit? - if (!startAtTop && blk->yMax < yStart) { + if (!startAtTop && (backward ? blk->yMin > yStart : blk->yMax < yStart)) { continue; } // check: is the block below the bottom limit? - if (!stopAtBottom && blk->yMin > yStop) { + if (!stopAtBottom && (backward ? blk->yMax < yStop : blk->yMin > yStop)) { break; } for (line = blk->lines; line; line = line->next) { // check: is the line above the top limit? - if (!startAtTop && line->yMin < yStart) { + if (!startAtTop && + (backward ? line->yMin > yStart : line->yMin < yStart)) { continue; } // check: is the line below the bottom limit? - if (!stopAtBottom && line->yMin > yStop) { + if (!stopAtBottom && + (backward ? line->yMin < yStop : line->yMin > yStop)) { continue; } - // search each position in this line + // convert the line to uppercase m = line->len; - for (j = 0, p = line->text; j <= m - len; ++j, ++p) { - - // compare the strings - for (k = 0; k < len; ++k) { -#if 1 //~ this lowercases Latin A-Z only -- this will eventually be - //~ extended to handle other character sets - if (p[k] >= 0x41 && p[k] <= 0x5a) { - u1 = p[k] + 0x20; - } else { - u1 = p[k]; + if (!caseSensitive) { + if (m > txtSize) { + txt = (Unicode *)greallocn(txt, m, sizeof(Unicode)); + txtSize = m; + } + for (k = 0; k < m; ++k) { + txt[k] = unicodeToUpper(line->text[k]); } - if (s[k] >= 0x41 && s[k] <= 0x5a) { - u2 = s[k] + 0x20; } else { - u2 = s[k]; + txt = line->text; } -#endif - if (u1 != u2) { + + // search each position in this line + j = backward ? m - len : 0; + p = txt + j; + while (backward ? j >= 0 : j <= m - len) { + + // compare the strings + for (k = 0; k < len; ++k) { + if (p[k] != s2[k]) { break; } } @@ -2728,11 +2760,27 @@ GBool TextPage::findText(Unicode *s, int len, yMax1 = line->edge[j]; break; } + if (backward) { + if ((startAtTop || + yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) && + (stopAtBottom || + yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) { + if (!found || + yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) { + xMin0 = xMin1; + xMax0 = xMax1; + yMin0 = yMin1; + yMax0 = yMax1; + found = gTrue; + } + } + } else { if ((startAtTop || yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) && (stopAtBottom || - yMin1 < yStop || (yMin1 == yStop && xMin1 < yStop))) { - if (!found || yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) { + yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) { + if (!found || + yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) { xMin0 = xMin1; xMax0 = xMax1; yMin0 = yMin1; @@ -2742,9 +2790,22 @@ GBool TextPage::findText(Unicode *s, int len, } } } + if (backward) { + --j; + --p; + } else { + ++j; + ++p; + } + } } } + if (!caseSensitive) { + gfree(s2); + gfree(txt); + } + if (found) { *xMin = xMin0; *xMax = xMax0; @@ -2806,7 +2867,7 @@ GString *TextPage::getText(double xMin, double yMin, // collect the line fragments that are in the rectangle fragsSize = 256; - frags = (TextLineFrag *)gmalloc(fragsSize * sizeof(TextLineFrag)); + frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag)); nFrags = 0; lastRot = -1; oneRot = gTrue; @@ -2908,7 +2969,7 @@ GString *TextPage::getText(double xMin, double yMin, if (nFrags == fragsSize) { fragsSize *= 2; frags = (TextLineFrag *) - grealloc(frags, fragsSize * sizeof(TextLineFrag)); + greallocn(frags, fragsSize, sizeof(TextLineFrag)); } frags[nFrags].init(line, idx0, idx1 - idx0 + 1); ++nFrags; @@ -3126,15 +3187,15 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc, // collect the line fragments for the page and sort them fragsSize = 256; - frags = (TextLineFrag *)gmalloc(fragsSize * sizeof(TextLineFrag)); + frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag)); nFrags = 0; for (i = 0; i < nBlocks; ++i) { blk = blocks[i]; for (line = blk->lines; line; line = line->next) { if (nFrags == fragsSize) { fragsSize *= 2; - frags = (TextLineFrag *)grealloc(frags, - fragsSize * sizeof(TextLineFrag)); + frags = (TextLineFrag *)greallocn(frags, + fragsSize, sizeof(TextLineFrag)); } frags[nFrags].init(line, 0, line->len); frags[nFrags].computeCoords(gTrue); @@ -3143,6 +3204,20 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc, } qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpYXPrimaryRot); +#if 0 // for debugging + printf("*** line fragments ***\n"); + for (i = 0; i < nFrags; ++i) { + frag = &frags[i]; + printf("frag: x=%.2f..%.2f y=%.2f..%.2f base=%.2f '", + frag->xMin, frag->xMax, frag->yMin, frag->yMax, frag->base); + for (n = 0; n < frag->len; ++n) { + fputc(frag->line->text[frag->start + n] & 0xff, stdout); + } + printf("'\n"); + } + printf("\n"); +#endif + // generate output col = 0; for (i = 0; i < nFrags; ++i) { @@ -3221,7 +3296,6 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc, // end of page if (pageBreaks) { (*outputFunc)(outputStream, eop, eopLen); - (*outputFunc)(outputStream, eol, eolLen); } uMap->decRefCnt(); @@ -3498,17 +3572,19 @@ void TextOutputDev::endString(GfxState */*state*/) { void TextOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double /*originX*/, double /*originY*/, - CharCode c, Unicode *u, int uLen) { - text->addChar(state, x, y, dx, dy, c, u, uLen); + CharCode c, int nBytes, Unicode *u, int uLen) { + text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen); } GBool TextOutputDev::findText(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, + GBool caseSensitive, GBool backward, double *xMin, double *yMin, double *xMax, double *yMax) { return text->findText(s, len, startAtTop, stopAtBottom, - startAtLast, stopAtLast, xMin, yMin, xMax, yMax); + startAtLast, stopAtLast, caseSensitive, backward, + xMin, yMin, xMax, yMax); } GString *TextOutputDev::getText(double xMin, double yMin, @@ -3527,3 +3603,11 @@ TextWordList *TextOutputDev::makeWordList() { return text->makeWordList(physLayout); } #endif + +TextPage *TextOutputDev::takeText() { + TextPage *ret; + + ret = text; + text = new TextPage(rawOrder); + return ret; +} diff --git a/xpdf/xpdf/TextOutputDev.h b/xpdf/xpdf/TextOutputDev.h index 5e8b49a09..10fb4c804 100644 --- a/xpdf/xpdf/TextOutputDev.h +++ b/xpdf/xpdf/TextOutputDev.h @@ -25,9 +25,15 @@ class GList; class GfxFont; class GfxState; class UnicodeMap; + +class TextWord; +class TextPool; +class TextLine; +class TextLineFrag; class TextBlock; +class TextFlow; +class TextWordList; class TextPage; -class TextLineFrag; //------------------------------------------------------------------------ @@ -96,6 +102,8 @@ public: { *r = colorR; *g = colorG; *b = colorB; } void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA) { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + double getFontSize() { return fontSize; } + int getRotation() { return rot; } int getCharPos() { return charPos; } int getCharLen() { return charLen; } #endif @@ -369,7 +377,7 @@ public: // Add a character to the current word. void addChar(GfxState *state, double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen); + CharCode c, int nBytes, Unicode *u, int uLen); // End the current word, sorting it into the list of words. void endWord(); @@ -390,6 +398,7 @@ public: GBool findText(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, + GBool caseSensitive, GBool backward, double *xMin, double *yMin, double *xMax, double *yMax); @@ -521,7 +530,7 @@ public: virtual void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, - CharCode c, Unicode *u, int uLen); + CharCode c, int nBytes, Unicode *u, int uLen); //----- special access @@ -535,6 +544,7 @@ public: GBool findText(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, + GBool caseSensitive, GBool backward, double *xMin, double *yMin, double *xMax, double *yMax); @@ -557,6 +567,10 @@ public: TextWordList *makeWordList(); #endif + // Returns the TextPage object for the last rasterized page, + // transferring ownership to the caller. + TextPage *takeText(); + private: TextOutputFunc outputFunc; // output function diff --git a/xpdf/xpdf/UnicodeMap.cc b/xpdf/xpdf/UnicodeMap.cc index 05ee44d19..1aa916110 100644 --- a/xpdf/xpdf/UnicodeMap.cc +++ b/xpdf/xpdf/UnicodeMap.cc @@ -53,7 +53,7 @@ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { map = new UnicodeMap(encodingNameA->copy()); size = 8; - map->ranges = (UnicodeMapRange *)gmalloc(size * sizeof(UnicodeMapRange)); + map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange)); eMapsSize = 0; line = 1; @@ -69,7 +69,7 @@ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { if (map->len == size) { size *= 2; map->ranges = (UnicodeMapRange *) - grealloc(map->ranges, size * sizeof(UnicodeMapRange)); + greallocn(map->ranges, size, sizeof(UnicodeMapRange)); } range = &map->ranges[map->len]; sscanf(tok1, "%x", &range->start); @@ -81,7 +81,7 @@ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { if (map->eMapsLen == eMapsSize) { eMapsSize += 16; map->eMaps = (UnicodeMapExt *) - grealloc(map->eMaps, eMapsSize * sizeof(UnicodeMapExt)); + greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt)); } eMap = &map->eMaps[map->eMapsLen]; sscanf(tok1, "%x", &eMap->u); diff --git a/xpdf/xpdf/UnicodeTypeTable.cc b/xpdf/xpdf/UnicodeTypeTable.cc index 54be55ce5..d658e24cc 100644 --- a/xpdf/xpdf/UnicodeTypeTable.cc +++ b/xpdf/xpdf/UnicodeTypeTable.cc @@ -1,8 +1,8 @@ //======================================================================== // -// UnicodeMapTables.cc +// UnicodeTypeTable.cc // -// Copyright 2003 Glyph & Cog, LLC +// Copyright 2004 Glyph & Cog, LLC // //======================================================================== @@ -15,20 +15,24 @@ struct UnicodeMapTableEntry { char type; }; -static UnicodeMapTableEntry table[256] = { +struct UnicodeCaseTableVector { + Unicode codes[256]; +}; + +static UnicodeMapTableEntry typeTable[256] = { { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNLNNNNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL", 'X' }, { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLNNNNNNNNNNNNNNLLNNNNNNNNNNNNNNLLLLLNNNNNNNNNLNNNNNNNNNNNNNNNNN", 'X' }, - { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLNNNNNNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLNNNNNNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRNRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNN", 'X' }, - { "NNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNRRNNNNNNNNNNNNNNNNNNNRRRRRR", 'X' }, - { "RRRRRRRRRRRRRRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRNRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' }, + { "RRRRNNNNNNNNNRNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNRNNNNNNNRRNNNNNNNRRNNNNNNNNNNRRRRRR", 'X' }, + { "RRRRRRRRRRRRRRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { NULL, 'N' }, { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLNNNNLLLLLLLLLLLLLNNLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNLLLLLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLNNLLLLLLLNNNNN", 'X' }, - { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNN", 'X' }, - { "NNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLNLNNNLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLNNLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLNNNNNNNNNNNNNNNN", 'X' }, + { "NNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLNLNNNLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNNNNLLLLLLLNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNLNNNNNLNNLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, @@ -39,23 +43,24 @@ static UnicodeMapTableEntry table[256] = { { NULL, 'L' }, { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLNLLNNNNNNNNNNNLLLLLLLNLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { "LLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLNLLNNNNNNNNNNNLLLLLLLNLNLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { "NNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLNNNNNLLLLLLNLLLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNNNLLLLLLLLLLLNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLNNNLLLLLLLLLLLLLNNN", 'X' }, - { "NNNNNNNNNNNNNNLRNNNNNNNNNNNNNNNNNNNNNNNNNNLRNLRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, - { "NNLNNNNLNNLLLLLLLLLLNLNNNLLLLLNNNNNNLNLNLNLLLLNLLLNLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { "NNNNNNNNNNNNNNLRNNNNNNNNNNNNNNNNNNNNNNNNNNLRNLRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { "NNLNNNNLNNLLLLLLLLLLNLNNNLLLLLNNNNNNLNLNLNLLLLNLLLNLLLLLLLNNLLLLNNNNNLLLLLNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { NULL, 'N' }, { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { NULL, 'N' }, { NULL, 'N' }, { NULL, 'N' }, + { NULL, 'L' }, { NULL, 'N' }, { NULL, 'N' }, { NULL, 'N' }, @@ -63,12 +68,10 @@ static UnicodeMapTableEntry table[256] = { { NULL, 'N' }, { NULL, 'N' }, { NULL, 'N' }, - { NULL, 'N' }, - { "NNNNNLLLNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNNNNNNNLLLLLNNLLLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLL", 'X' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, + { "NNNNNLLLNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNNNNNNNLLLLLNNLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLL", 'X' }, { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN", 'X' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, @@ -94,6 +97,7 @@ static UnicodeMapTableEntry table[256] = { { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, @@ -269,11 +273,644 @@ static UnicodeMapTableEntry table[256] = { { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLRRRRRRNRRRRRRRRRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' }, { NULL, 'R' }, - { "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNN", 'X' }, + { "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' }, { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' }, { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLL", 'X' } }; +static UnicodeCaseTableVector caseTable00 = {{ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x03bc, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00d7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff +}}; +static UnicodeCaseTableVector caseTable01 = {{ + 0x0101, 0x0101, 0x0103, 0x0103, 0x0105, 0x0105, 0x0107, 0x0107, + 0x0109, 0x0109, 0x010b, 0x010b, 0x010d, 0x010d, 0x010f, 0x010f, + 0x0111, 0x0111, 0x0113, 0x0113, 0x0115, 0x0115, 0x0117, 0x0117, + 0x0119, 0x0119, 0x011b, 0x011b, 0x011d, 0x011d, 0x011f, 0x011f, + 0x0121, 0x0121, 0x0123, 0x0123, 0x0125, 0x0125, 0x0127, 0x0127, + 0x0129, 0x0129, 0x012b, 0x012b, 0x012d, 0x012d, 0x012f, 0x012f, + 0x0130, 0x0131, 0x0133, 0x0133, 0x0135, 0x0135, 0x0137, 0x0137, + 0x0138, 0x013a, 0x013a, 0x013c, 0x013c, 0x013e, 0x013e, 0x0140, + 0x0140, 0x0142, 0x0142, 0x0144, 0x0144, 0x0146, 0x0146, 0x0148, + 0x0148, 0x0149, 0x014b, 0x014b, 0x014d, 0x014d, 0x014f, 0x014f, + 0x0151, 0x0151, 0x0153, 0x0153, 0x0155, 0x0155, 0x0157, 0x0157, + 0x0159, 0x0159, 0x015b, 0x015b, 0x015d, 0x015d, 0x015f, 0x015f, + 0x0161, 0x0161, 0x0163, 0x0163, 0x0165, 0x0165, 0x0167, 0x0167, + 0x0169, 0x0169, 0x016b, 0x016b, 0x016d, 0x016d, 0x016f, 0x016f, + 0x0171, 0x0171, 0x0173, 0x0173, 0x0175, 0x0175, 0x0177, 0x0177, + 0x00ff, 0x017a, 0x017a, 0x017c, 0x017c, 0x017e, 0x017e, 0x0073, + 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, + 0x0188, 0x0256, 0x0257, 0x018c, 0x018c, 0x018d, 0x01dd, 0x0259, + 0x025b, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, + 0x0199, 0x0199, 0x019a, 0x019b, 0x026f, 0x0272, 0x019e, 0x0275, + 0x01a1, 0x01a1, 0x01a3, 0x01a3, 0x01a5, 0x01a5, 0x0280, 0x01a8, + 0x01a8, 0x0283, 0x01aa, 0x01ab, 0x01ad, 0x01ad, 0x0288, 0x01b0, + 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b4, 0x01b6, 0x01b6, 0x0292, + 0x01b9, 0x01b9, 0x01ba, 0x01bb, 0x01bd, 0x01bd, 0x01be, 0x01bf, + 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c6, 0x01c6, 0x01c6, 0x01c9, + 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01cc, 0x01ce, 0x01ce, 0x01d0, + 0x01d0, 0x01d2, 0x01d2, 0x01d4, 0x01d4, 0x01d6, 0x01d6, 0x01d8, + 0x01d8, 0x01da, 0x01da, 0x01dc, 0x01dc, 0x01dd, 0x01df, 0x01df, + 0x01e1, 0x01e1, 0x01e3, 0x01e3, 0x01e5, 0x01e5, 0x01e7, 0x01e7, + 0x01e9, 0x01e9, 0x01eb, 0x01eb, 0x01ed, 0x01ed, 0x01ef, 0x01ef, + 0x01f0, 0x01f3, 0x01f3, 0x01f3, 0x01f5, 0x01f5, 0x0195, 0x01bf, + 0x01f9, 0x01f9, 0x01fb, 0x01fb, 0x01fd, 0x01fd, 0x01ff, 0x01ff +}}; +static UnicodeCaseTableVector caseTable02 = {{ + 0x0201, 0x0201, 0x0203, 0x0203, 0x0205, 0x0205, 0x0207, 0x0207, + 0x0209, 0x0209, 0x020b, 0x020b, 0x020d, 0x020d, 0x020f, 0x020f, + 0x0211, 0x0211, 0x0213, 0x0213, 0x0215, 0x0215, 0x0217, 0x0217, + 0x0219, 0x0219, 0x021b, 0x021b, 0x021d, 0x021d, 0x021f, 0x021f, + 0x019e, 0x0221, 0x0223, 0x0223, 0x0225, 0x0225, 0x0227, 0x0227, + 0x0229, 0x0229, 0x022b, 0x022b, 0x022d, 0x022d, 0x022f, 0x022f, + 0x0231, 0x0231, 0x0233, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237, + 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, + 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, + 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f, + 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, + 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, + 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, + 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, + 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, + 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, + 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, + 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, + 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, + 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, + 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, + 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, + 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7, + 0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, + 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, + 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, + 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, + 0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df, + 0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7, + 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, + 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, + 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff +}}; +static UnicodeCaseTableVector caseTable03 = {{ + 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, + 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, + 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, + 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, + 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, + 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, + 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, + 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, + 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x03b9, 0x0346, 0x0347, + 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, + 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, + 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, + 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, + 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, + 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, + 0x0378, 0x0379, 0x037a, 0x037b, 0x037c, 0x037d, 0x037e, 0x037f, + 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x03ac, 0x0387, + 0x03ad, 0x03ae, 0x03af, 0x038b, 0x03cc, 0x038d, 0x03cd, 0x03ce, + 0x0390, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03a2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03ac, 0x03ad, 0x03ae, 0x03af, + 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03c3, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x03cf, + 0x03b2, 0x03b8, 0x03d2, 0x03d3, 0x03d4, 0x03c6, 0x03c0, 0x03d7, + 0x03d9, 0x03d9, 0x03db, 0x03db, 0x03dd, 0x03dd, 0x03df, 0x03df, + 0x03e1, 0x03e1, 0x03e3, 0x03e3, 0x03e5, 0x03e5, 0x03e7, 0x03e7, + 0x03e9, 0x03e9, 0x03eb, 0x03eb, 0x03ed, 0x03ed, 0x03ef, 0x03ef, + 0x03ba, 0x03c1, 0x03f2, 0x03f3, 0x03b8, 0x03b5, 0x03f6, 0x03f8, + 0x03f8, 0x03f2, 0x03fb, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff +}}; +static UnicodeCaseTableVector caseTable04 = {{ + 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, + 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, + 0x0469, 0x0469, 0x046b, 0x046b, 0x046d, 0x046d, 0x046f, 0x046f, + 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0477, 0x0477, + 0x0479, 0x0479, 0x047b, 0x047b, 0x047d, 0x047d, 0x047f, 0x047f, + 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, + 0x0488, 0x0489, 0x048b, 0x048b, 0x048d, 0x048d, 0x048f, 0x048f, + 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, + 0x0499, 0x0499, 0x049b, 0x049b, 0x049d, 0x049d, 0x049f, 0x049f, + 0x04a1, 0x04a1, 0x04a3, 0x04a3, 0x04a5, 0x04a5, 0x04a7, 0x04a7, + 0x04a9, 0x04a9, 0x04ab, 0x04ab, 0x04ad, 0x04ad, 0x04af, 0x04af, + 0x04b1, 0x04b1, 0x04b3, 0x04b3, 0x04b5, 0x04b5, 0x04b7, 0x04b7, + 0x04b9, 0x04b9, 0x04bb, 0x04bb, 0x04bd, 0x04bd, 0x04bf, 0x04bf, + 0x04c0, 0x04c2, 0x04c2, 0x04c4, 0x04c4, 0x04c6, 0x04c6, 0x04c8, + 0x04c8, 0x04ca, 0x04ca, 0x04cc, 0x04cc, 0x04ce, 0x04ce, 0x04cf, + 0x04d1, 0x04d1, 0x04d3, 0x04d3, 0x04d5, 0x04d5, 0x04d7, 0x04d7, + 0x04d9, 0x04d9, 0x04db, 0x04db, 0x04dd, 0x04dd, 0x04df, 0x04df, + 0x04e1, 0x04e1, 0x04e3, 0x04e3, 0x04e5, 0x04e5, 0x04e7, 0x04e7, + 0x04e9, 0x04e9, 0x04eb, 0x04eb, 0x04ed, 0x04ed, 0x04ef, 0x04ef, + 0x04f1, 0x04f1, 0x04f3, 0x04f3, 0x04f5, 0x04f5, 0x04f6, 0x04f7, + 0x04f9, 0x04f9, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff +}}; +static UnicodeCaseTableVector caseTable05 = {{ + 0x0501, 0x0501, 0x0503, 0x0503, 0x0505, 0x0505, 0x0507, 0x0507, + 0x0509, 0x0509, 0x050b, 0x050b, 0x050d, 0x050d, 0x050f, 0x050f, + 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, + 0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f, + 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, + 0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f, + 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, + 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f, + 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, + 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, + 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, + 0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f, + 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, + 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f, + 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, + 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, + 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, + 0x0588, 0x0589, 0x058a, 0x058b, 0x058c, 0x058d, 0x058e, 0x058f, + 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, + 0x0598, 0x0599, 0x059a, 0x059b, 0x059c, 0x059d, 0x059e, 0x059f, + 0x05a0, 0x05a1, 0x05a2, 0x05a3, 0x05a4, 0x05a5, 0x05a6, 0x05a7, + 0x05a8, 0x05a9, 0x05aa, 0x05ab, 0x05ac, 0x05ad, 0x05ae, 0x05af, + 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7, + 0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf, + 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05c4, 0x05c5, 0x05c6, 0x05c7, + 0x05c8, 0x05c9, 0x05ca, 0x05cb, 0x05cc, 0x05cd, 0x05ce, 0x05cf, + 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, + 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, + 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, + 0x05e8, 0x05e9, 0x05ea, 0x05eb, 0x05ec, 0x05ed, 0x05ee, 0x05ef, + 0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0x05f5, 0x05f6, 0x05f7, + 0x05f8, 0x05f9, 0x05fa, 0x05fb, 0x05fc, 0x05fd, 0x05fe, 0x05ff +}}; +static UnicodeCaseTableVector caseTable1e = {{ + 0x1e01, 0x1e01, 0x1e03, 0x1e03, 0x1e05, 0x1e05, 0x1e07, 0x1e07, + 0x1e09, 0x1e09, 0x1e0b, 0x1e0b, 0x1e0d, 0x1e0d, 0x1e0f, 0x1e0f, + 0x1e11, 0x1e11, 0x1e13, 0x1e13, 0x1e15, 0x1e15, 0x1e17, 0x1e17, + 0x1e19, 0x1e19, 0x1e1b, 0x1e1b, 0x1e1d, 0x1e1d, 0x1e1f, 0x1e1f, + 0x1e21, 0x1e21, 0x1e23, 0x1e23, 0x1e25, 0x1e25, 0x1e27, 0x1e27, + 0x1e29, 0x1e29, 0x1e2b, 0x1e2b, 0x1e2d, 0x1e2d, 0x1e2f, 0x1e2f, + 0x1e31, 0x1e31, 0x1e33, 0x1e33, 0x1e35, 0x1e35, 0x1e37, 0x1e37, + 0x1e39, 0x1e39, 0x1e3b, 0x1e3b, 0x1e3d, 0x1e3d, 0x1e3f, 0x1e3f, + 0x1e41, 0x1e41, 0x1e43, 0x1e43, 0x1e45, 0x1e45, 0x1e47, 0x1e47, + 0x1e49, 0x1e49, 0x1e4b, 0x1e4b, 0x1e4d, 0x1e4d, 0x1e4f, 0x1e4f, + 0x1e51, 0x1e51, 0x1e53, 0x1e53, 0x1e55, 0x1e55, 0x1e57, 0x1e57, + 0x1e59, 0x1e59, 0x1e5b, 0x1e5b, 0x1e5d, 0x1e5d, 0x1e5f, 0x1e5f, + 0x1e61, 0x1e61, 0x1e63, 0x1e63, 0x1e65, 0x1e65, 0x1e67, 0x1e67, + 0x1e69, 0x1e69, 0x1e6b, 0x1e6b, 0x1e6d, 0x1e6d, 0x1e6f, 0x1e6f, + 0x1e71, 0x1e71, 0x1e73, 0x1e73, 0x1e75, 0x1e75, 0x1e77, 0x1e77, + 0x1e79, 0x1e79, 0x1e7b, 0x1e7b, 0x1e7d, 0x1e7d, 0x1e7f, 0x1e7f, + 0x1e81, 0x1e81, 0x1e83, 0x1e83, 0x1e85, 0x1e85, 0x1e87, 0x1e87, + 0x1e89, 0x1e89, 0x1e8b, 0x1e8b, 0x1e8d, 0x1e8d, 0x1e8f, 0x1e8f, + 0x1e91, 0x1e91, 0x1e93, 0x1e93, 0x1e95, 0x1e95, 0x1e96, 0x1e97, + 0x1e98, 0x1e99, 0x1e9a, 0x1e61, 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f, + 0x1ea1, 0x1ea1, 0x1ea3, 0x1ea3, 0x1ea5, 0x1ea5, 0x1ea7, 0x1ea7, + 0x1ea9, 0x1ea9, 0x1eab, 0x1eab, 0x1ead, 0x1ead, 0x1eaf, 0x1eaf, + 0x1eb1, 0x1eb1, 0x1eb3, 0x1eb3, 0x1eb5, 0x1eb5, 0x1eb7, 0x1eb7, + 0x1eb9, 0x1eb9, 0x1ebb, 0x1ebb, 0x1ebd, 0x1ebd, 0x1ebf, 0x1ebf, + 0x1ec1, 0x1ec1, 0x1ec3, 0x1ec3, 0x1ec5, 0x1ec5, 0x1ec7, 0x1ec7, + 0x1ec9, 0x1ec9, 0x1ecb, 0x1ecb, 0x1ecd, 0x1ecd, 0x1ecf, 0x1ecf, + 0x1ed1, 0x1ed1, 0x1ed3, 0x1ed3, 0x1ed5, 0x1ed5, 0x1ed7, 0x1ed7, + 0x1ed9, 0x1ed9, 0x1edb, 0x1edb, 0x1edd, 0x1edd, 0x1edf, 0x1edf, + 0x1ee1, 0x1ee1, 0x1ee3, 0x1ee3, 0x1ee5, 0x1ee5, 0x1ee7, 0x1ee7, + 0x1ee9, 0x1ee9, 0x1eeb, 0x1eeb, 0x1eed, 0x1eed, 0x1eef, 0x1eef, + 0x1ef1, 0x1ef1, 0x1ef3, 0x1ef3, 0x1ef5, 0x1ef5, 0x1ef7, 0x1ef7, + 0x1ef9, 0x1ef9, 0x1efa, 0x1efb, 0x1efc, 0x1efd, 0x1efe, 0x1eff +}}; +static UnicodeCaseTableVector caseTable1f = {{ + 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, + 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, + 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f16, 0x1f17, + 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f1e, 0x1f1f, + 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, + 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, + 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, + 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, + 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f46, 0x1f47, + 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f4e, 0x1f4f, + 0x1f50, 0x1f51, 0x1f52, 0x1f53, 0x1f54, 0x1f55, 0x1f56, 0x1f57, + 0x1f58, 0x1f51, 0x1f5a, 0x1f53, 0x1f5c, 0x1f55, 0x1f5e, 0x1f57, + 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, + 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, + 0x1f70, 0x1f71, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1f76, 0x1f77, + 0x1f78, 0x1f79, 0x1f7a, 0x1f7b, 0x1f7c, 0x1f7d, 0x1f7e, 0x1f7f, + 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, + 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, + 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, + 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, + 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, + 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, + 0x1fb0, 0x1fb1, 0x1fb2, 0x1fb3, 0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7, + 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0x1fbd, 0x03b9, 0x1fbf, + 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, 0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7, + 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0x1fcd, 0x1fce, 0x1fcf, + 0x1fd0, 0x1fd1, 0x1fd2, 0x1fd3, 0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7, + 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf, + 0x1fe0, 0x1fe1, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe5, 0x1fe6, 0x1fe7, + 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1fed, 0x1fee, 0x1fef, + 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3, 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, + 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0x1ffd, 0x1ffe, 0x1fff +}}; +static UnicodeCaseTableVector caseTable21 = {{ + 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, + 0x2108, 0x2109, 0x210a, 0x210b, 0x210c, 0x210d, 0x210e, 0x210f, + 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, + 0x2118, 0x2119, 0x211a, 0x211b, 0x211c, 0x211d, 0x211e, 0x211f, + 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x03c9, 0x2127, + 0x2128, 0x2129, 0x006b, 0x00e5, 0x212c, 0x212d, 0x212e, 0x212f, + 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, + 0x2138, 0x2139, 0x213a, 0x213b, 0x213c, 0x213d, 0x213e, 0x213f, + 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, + 0x2148, 0x2149, 0x214a, 0x214b, 0x214c, 0x214d, 0x214e, 0x214f, + 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, + 0x2158, 0x2159, 0x215a, 0x215b, 0x215c, 0x215d, 0x215e, 0x215f, + 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, + 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, + 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, + 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, + 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, + 0x2188, 0x2189, 0x218a, 0x218b, 0x218c, 0x218d, 0x218e, 0x218f, + 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, + 0x2198, 0x2199, 0x219a, 0x219b, 0x219c, 0x219d, 0x219e, 0x219f, + 0x21a0, 0x21a1, 0x21a2, 0x21a3, 0x21a4, 0x21a5, 0x21a6, 0x21a7, + 0x21a8, 0x21a9, 0x21aa, 0x21ab, 0x21ac, 0x21ad, 0x21ae, 0x21af, + 0x21b0, 0x21b1, 0x21b2, 0x21b3, 0x21b4, 0x21b5, 0x21b6, 0x21b7, + 0x21b8, 0x21b9, 0x21ba, 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf, + 0x21c0, 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7, + 0x21c8, 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf, + 0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x21d5, 0x21d6, 0x21d7, + 0x21d8, 0x21d9, 0x21da, 0x21db, 0x21dc, 0x21dd, 0x21de, 0x21df, + 0x21e0, 0x21e1, 0x21e2, 0x21e3, 0x21e4, 0x21e5, 0x21e6, 0x21e7, + 0x21e8, 0x21e9, 0x21ea, 0x21eb, 0x21ec, 0x21ed, 0x21ee, 0x21ef, + 0x21f0, 0x21f1, 0x21f2, 0x21f3, 0x21f4, 0x21f5, 0x21f6, 0x21f7, + 0x21f8, 0x21f9, 0x21fa, 0x21fb, 0x21fc, 0x21fd, 0x21fe, 0x21ff +}}; +static UnicodeCaseTableVector caseTable24 = {{ + 0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407, + 0x2408, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x240e, 0x240f, + 0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417, + 0x2418, 0x2419, 0x241a, 0x241b, 0x241c, 0x241d, 0x241e, 0x241f, + 0x2420, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427, + 0x2428, 0x2429, 0x242a, 0x242b, 0x242c, 0x242d, 0x242e, 0x242f, + 0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437, + 0x2438, 0x2439, 0x243a, 0x243b, 0x243c, 0x243d, 0x243e, 0x243f, + 0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447, + 0x2448, 0x2449, 0x244a, 0x244b, 0x244c, 0x244d, 0x244e, 0x244f, + 0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457, + 0x2458, 0x2459, 0x245a, 0x245b, 0x245c, 0x245d, 0x245e, 0x245f, + 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, + 0x2468, 0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, + 0x2470, 0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0x2477, + 0x2478, 0x2479, 0x247a, 0x247b, 0x247c, 0x247d, 0x247e, 0x247f, + 0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487, + 0x2488, 0x2489, 0x248a, 0x248b, 0x248c, 0x248d, 0x248e, 0x248f, + 0x2490, 0x2491, 0x2492, 0x2493, 0x2494, 0x2495, 0x2496, 0x2497, + 0x2498, 0x2499, 0x249a, 0x249b, 0x249c, 0x249d, 0x249e, 0x249f, + 0x24a0, 0x24a1, 0x24a2, 0x24a3, 0x24a4, 0x24a5, 0x24a6, 0x24a7, + 0x24a8, 0x24a9, 0x24aa, 0x24ab, 0x24ac, 0x24ad, 0x24ae, 0x24af, + 0x24b0, 0x24b1, 0x24b2, 0x24b3, 0x24b4, 0x24b5, 0x24d0, 0x24d1, + 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9, + 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1, + 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9, + 0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, + 0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, + 0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, + 0x24e8, 0x24e9, 0x24ea, 0x24eb, 0x24ec, 0x24ed, 0x24ee, 0x24ef, + 0x24f0, 0x24f1, 0x24f2, 0x24f3, 0x24f4, 0x24f5, 0x24f6, 0x24f7, + 0x24f8, 0x24f9, 0x24fa, 0x24fb, 0x24fc, 0x24fd, 0x24fe, 0x24ff +}}; +static UnicodeCaseTableVector caseTableff = {{ + 0xff00, 0xff01, 0xff02, 0xff03, 0xff04, 0xff05, 0xff06, 0xff07, + 0xff08, 0xff09, 0xff0a, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f, + 0xff10, 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17, + 0xff18, 0xff19, 0xff1a, 0xff1b, 0xff1c, 0xff1d, 0xff1e, 0xff1f, + 0xff20, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, + 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, + 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, + 0xff58, 0xff59, 0xff5a, 0xff3b, 0xff3c, 0xff3d, 0xff3e, 0xff3f, + 0xff40, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, + 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, + 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, + 0xff58, 0xff59, 0xff5a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f, + 0xff60, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, + 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, + 0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77, + 0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f, + 0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87, + 0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f, + 0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97, + 0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f, + 0xffa0, 0xffa1, 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7, + 0xffa8, 0xffa9, 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf, + 0xffb0, 0xffb1, 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7, + 0xffb8, 0xffb9, 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf, + 0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, + 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf, + 0xffd0, 0xffd1, 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7, + 0xffd8, 0xffd9, 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf, + 0xffe0, 0xffe1, 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7, + 0xffe8, 0xffe9, 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef, + 0xfff0, 0xfff1, 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7, + 0xfff8, 0xfff9, 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff +}}; +static UnicodeCaseTableVector *caseTable[256] = { + &caseTable00, + &caseTable01, + &caseTable02, + &caseTable03, + &caseTable04, + &caseTable05, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &caseTable1e, + &caseTable1f, + NULL, + &caseTable21, + NULL, + NULL, + &caseTable24, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &caseTableff +}; + static inline char getType(Unicode c) { int i; char type; @@ -282,8 +919,8 @@ static inline char getType(Unicode c) { type = 'X'; } else { i = (c >> 8) & 0xff; - if ((type = table[i].type) == 'X') { - type = table[i].vector[c & 0xff]; + if ((type = typeTable[i].type) == 'X') { + type = typeTable[i].vector[c & 0xff]; } } return type; @@ -297,3 +934,16 @@ GBool unicodeTypeR(Unicode c) { return getType(c) == 'R'; } +Unicode unicodeToUpper(Unicode c) { + int i; + + if (c > 0xffff) { + return c; + } + i = (c >> 8) & 0xff; + if (caseTable[i]) { + return caseTable[i]->codes[c & 0xff]; + } + return c; +} + diff --git a/xpdf/xpdf/UnicodeTypeTable.h b/xpdf/xpdf/UnicodeTypeTable.h index e06b39391..7103dbddf 100644 --- a/xpdf/xpdf/UnicodeTypeTable.h +++ b/xpdf/xpdf/UnicodeTypeTable.h @@ -15,4 +15,6 @@ extern GBool unicodeTypeL(Unicode c); extern GBool unicodeTypeR(Unicode c); +extern Unicode unicodeToUpper(Unicode c); + #endif diff --git a/xpdf/xpdf/XRef.cc b/xpdf/xpdf/XRef.cc index 12407103e..928931eb4 100644 --- a/xpdf/xpdf/XRef.cc +++ b/xpdf/xpdf/XRef.cc @@ -12,7 +12,6 @@ #pragma implementation #endif -#include #include #include #include @@ -23,9 +22,6 @@ #include "Lexer.h" #include "Parser.h" #include "Dict.h" -#ifndef NO_DECRYPTION -#include "Decrypt.h" -#endif #include "Error.h" #include "ErrorCodes.h" #include "XRef.h" @@ -35,7 +31,6 @@ #define xrefSearchSize 1024 // read this many bytes at end of file // to look for 'startxref' -#ifndef NO_DECRYPTION //------------------------------------------------------------------------ // Permission bits //------------------------------------------------------------------------ @@ -45,7 +40,6 @@ #define permCopy (1<<4) #define permNotes (1<<5) #define defPermFlags 0xfffc -#endif //------------------------------------------------------------------------ // ObjectStream @@ -111,14 +105,9 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { goto err1; } - if ((unsigned) nObjects >= INT_MAX / sizeof(int)) { - error(-1, "Invalid 'nObjects'"); - goto err1; - } - objs = new Object[nObjects]; - objNums = (int *)gmalloc(nObjects * sizeof(int)); - offsets = (int *)gmalloc(nObjects * sizeof(int)); + objNums = (int *)gmallocn(nObjects, sizeof(int)); + offsets = (int *)gmallocn(nObjects, sizeof(int)); // parse the header: object numbers and offsets objStr.streamReset(); @@ -201,7 +190,7 @@ Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { // XRef //------------------------------------------------------------------------ -XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { +XRef::XRef(BaseStream *strA) { Guint pos; Object obj; @@ -213,6 +202,10 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { streamEndsLen = 0; objStr = NULL; + encrypted = gFalse; + permFlags = defPermFlags; + ownerPasswordOk = gFalse; + // read the trailer str = strA; start = str->getStart(); @@ -257,16 +250,6 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { // now set the trailer dictionary's xref pointer so we can fetch // indirect objects from it trailerDict.getDict()->setXRef(this); - - // check for encryption -#ifndef NO_DECRYPTION - encrypted = gFalse; -#endif - if (checkEncrypted(ownerPassword, userPassword)) { - ok = gFalse; - errCode = errEncrypted; - return; - } } XRef::~XRef() { @@ -394,12 +377,7 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos) { if (newSize < 0) { goto err1; } - if ((unsigned) newSize >= INT_MAX / sizeof(XRefEntry)) { - error(-1, "Invalid 'obj' parameters'"); - goto err1; - } - - entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; @@ -472,6 +450,7 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos) { pos2 = (Guint)obj2.getInt(); readXRef(&pos2); if (!ok) { + obj2.free(); goto err1; } } @@ -504,11 +483,7 @@ GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { goto err1; } if (newSize > size) { - if ((unsigned) newSize >= INT_MAX / sizeof(XRefEntry)) { - error(-1, "Invalid 'size' parameter."); - return gFalse; - } - entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; @@ -598,11 +573,7 @@ GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { if (newSize < 0) { return gFalse; } - if ((unsigned) newSize >= INT_MAX / sizeof(XRefEntry)) { - error(-1, "Invalid 'size' inside xref table."); - return gFalse; - } - entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; @@ -692,7 +663,7 @@ GBool XRef::constructXRef() { obj.initNull(); parser = new Parser(NULL, new Lexer(NULL, - str->makeSubStream(start + pos + 7, gFalse, 0, &obj))); + str->makeSubStream(pos + 7, gFalse, 0, &obj))); parser->getObj(&newTrailerDict); if (newTrailerDict.isDict()) { newTrailerDict.dictLookupNF("Root", &obj); @@ -737,12 +708,8 @@ GBool XRef::constructXRef() { error(-1, "Bad object number"); return gFalse; } - if ((unsigned) newSize >= INT_MAX / sizeof(XRefEntry)) { - error(-1, "Invalid 'obj' parameters."); - return gFalse; - } entries = (XRefEntry *) - grealloc(entries, newSize * sizeof(XRefEntry)); + greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; @@ -764,12 +731,8 @@ GBool XRef::constructXRef() { } else if (!strncmp(p, "endstream", 9)) { if (streamEndsLen == streamEndsSize) { streamEndsSize += 64; - if ((unsigned) streamEndsSize >= INT_MAX / sizeof(int)) { - error(-1, "Invalid 'endstream' parameter."); - return gFalse; - } - streamEnds = (Guint *)grealloc(streamEnds, - streamEndsSize * sizeof(int)); + streamEnds = (Guint *)greallocn(streamEnds, + streamEndsSize, sizeof(int)); } streamEnds[streamEndsLen++] = pos; } @@ -782,143 +745,38 @@ GBool XRef::constructXRef() { return gFalse; } -#ifndef NO_DECRYPTION -GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { - Object encrypt, filterObj, versionObj, revisionObj, lengthObj; - Object ownerKey, userKey, permissions, fileID, fileID1; - GBool encrypted1; - GBool ret; - - keyLength = 0; - encVersion = encRevision = 0; - ret = gFalse; +void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA, + Guchar *fileKeyA, int keyLengthA, int encVersionA) { + int i; - permFlags = defPermFlags; - ownerPasswordOk = gFalse; - trailerDict.dictLookup("Encrypt", &encrypt); - if ((encrypted1 = encrypt.isDict())) { - ret = gTrue; - encrypt.dictLookup("Filter", &filterObj); - if (filterObj.isName("Standard")) { - encrypt.dictLookup("V", &versionObj); - encrypt.dictLookup("R", &revisionObj); - encrypt.dictLookup("Length", &lengthObj); - encrypt.dictLookup("O", &ownerKey); - encrypt.dictLookup("U", &userKey); - encrypt.dictLookup("P", &permissions); - trailerDict.dictLookup("ID", &fileID); - if (versionObj.isInt() && - revisionObj.isInt() && - ownerKey.isString() && ownerKey.getString()->getLength() == 32 && - userKey.isString() && userKey.getString()->getLength() == 32 && - permissions.isInt() && - fileID.isArray()) { - encVersion = versionObj.getInt(); - encRevision = revisionObj.getInt(); - if (lengthObj.isInt()) { - keyLength = lengthObj.getInt() / 8; + encrypted = gTrue; + permFlags = permFlagsA; + ownerPasswordOk = ownerPasswordOkA; + if (keyLengthA <= 16) { + keyLength = keyLengthA; } else { - keyLength = 5; - } - if (keyLength < 1) { - keyLength = 1; - } - if (keyLength > 16) { keyLength = 16; } - permFlags = permissions.getInt(); - if (encVersion >= 1 && encVersion <= 2 && - encRevision >= 2 && encRevision <= 3) { - fileID.arrayGet(0, &fileID1); - if (fileID1.isString()) { - if (Decrypt::makeFileKey(encVersion, encRevision, keyLength, - ownerKey.getString(), userKey.getString(), - permFlags, fileID1.getString(), - ownerPassword, userPassword, fileKey, - &ownerPasswordOk)) { - if (ownerPassword && !ownerPasswordOk) { - error(-1, "Incorrect owner password"); + for (i = 0; i < keyLength; ++i) { + fileKey[i] = fileKeyA[i]; } - ret = gFalse; - } else { - error(-1, "Incorrect password"); - } - } else { - error(-1, "Weird encryption info"); - } - fileID1.free(); - } else { - error(-1, "Unsupported version/revision (%d/%d) of Standard security handler", - encVersion, encRevision); - } - } else { - error(-1, "Weird encryption info"); - } - fileID.free(); - permissions.free(); - userKey.free(); - ownerKey.free(); - lengthObj.free(); - revisionObj.free(); - versionObj.free(); - } else { - error(-1, "Unknown security handler '%s'", - filterObj.isName() ? filterObj.getName() : "???"); - } - filterObj.free(); - } - encrypt.free(); - - // this flag has to be set *after* we read the O/U/P strings - encrypted = encrypted1; - - return ret; -} -#else -GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { - Object obj; - GBool encrypted; - - trailerDict.dictLookup("Encrypt", &obj); - if ((encrypted = !obj.isNull())) { - error(-1, "PDF file is encrypted and this version of the Xpdf tools"); - error(-1, "was built without decryption support."); - } - obj.free(); - return encrypted; + encVersion = encVersionA; } -#endif GBool XRef::okToPrint(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint); -#else - return gTrue; -#endif } GBool XRef::okToChange(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange); -#else - return gTrue; -#endif } GBool XRef::okToCopy(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy); -#else - return gTrue; -#endif } GBool XRef::okToAddNotes(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes); -#else - return gTrue; -#endif } Object *XRef::fetch(int num, int gen, Object *obj) { @@ -948,14 +806,14 @@ Object *XRef::fetch(int num, int gen, Object *obj) { if (!obj1.isInt() || obj1.getInt() != num || !obj2.isInt() || obj2.getInt() != gen || !obj3.isCmd("obj")) { + obj1.free(); + obj2.free(); + obj3.free(); + delete parser; goto err; } -#ifndef NO_DECRYPTION parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, num, gen); -#else - parser->getObj(obj); -#endif obj1.free(); obj2.free(); obj3.free(); diff --git a/xpdf/xpdf/XRef.h b/xpdf/xpdf/XRef.h index bec487a11..f9dede3e7 100644 --- a/xpdf/xpdf/XRef.h +++ b/xpdf/xpdf/XRef.h @@ -43,7 +43,7 @@ class XRef { public: // Constructor. Read xref table from stream. - XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword); + XRef(BaseStream *strA); // Destructor. ~XRef(); @@ -54,12 +54,12 @@ public: // Get the error code (if isOk() returns false). int getErrorCode() { return errCode; } + // Set the encryption parameters. + void setEncryption(int permFlagsA, GBool ownerPasswordOkA, + Guchar *fileKeyA, int keyLengthA, int encVersionA); + // Is the file encrypted? -#ifndef NO_DECRYPTION GBool isEncrypted() { return encrypted; } -#else - GBool isEncrypted() { return gFalse; } -#endif // Check various permissions. GBool okToPrint(GBool ignoreOwnerPW = gFalse); @@ -112,15 +112,12 @@ private: // damaged files int streamEndsLen; // number of valid entries in streamEnds ObjectStream *objStr; // cached object stream -#ifndef NO_DECRYPTION GBool encrypted; // true if file is encrypted - int encVersion; // encryption algorithm - int encRevision; // security handler revision - int keyLength; // length of key, in bytes int permFlags; // permission bits - Guchar fileKey[16]; // file decryption key GBool ownerPasswordOk; // true if owner password is correct -#endif + Guchar fileKey[16]; // file decryption key + int keyLength; // length of key, in bytes + int encVersion; // encryption algorithm Guint getStartXref(); GBool readXRef(Guint *pos); @@ -128,7 +125,6 @@ private: GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n); GBool readXRefStream(Stream *xrefStr, Guint *pos); GBool constructXRef(); - GBool checkEncrypted(GString *ownerPassword, GString *userPassword); Guint strToUnsigned(char *s); }; From eb6fa20390227e198226171f400cdf57bad4b802 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 18 Aug 2005 19:10:52 +0000 Subject: [PATCH 138/245] Fordward port 450671 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=450673 --- core/generator_pdf/generator_pdf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index f7ce136f6..477ed995e 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -175,8 +175,8 @@ bool PDFGenerator::loadDocument( const QString & filePath, QVector & pagesVector.resize( pageCount ); for ( uint i = 0; i < pageCount ; i++ ) { - KPDFPage * page = new KPDFPage( i, pdfdoc->getPageMediaWidth(i+1), - pdfdoc->getPageMediaHeight(i+1), + KPDFPage * page = new KPDFPage( i, pdfdoc->getPageCropWidth(i+1), + pdfdoc->getPageCropHeight(i+1), pdfdoc->getPageRotate(i+1) ); addTransition( i, page ); pagesVector[i] = page; From 86d98acbe2bdfbc9afe4a79d81a51314a903e886 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 20 Aug 2005 11:49:53 +0000 Subject: [PATCH 139/245] Forgot those two new files, thanks brad for reminding svn path=/trunk/KDE/kdegraphics/kpdf/; revision=451311 --- xpdf/xpdf/SecurityHandler.cc | 376 +++++++++++++++++++++++++++++++++++ xpdf/xpdf/SecurityHandler.h | 155 +++++++++++++++ 2 files changed, 531 insertions(+) create mode 100644 xpdf/xpdf/SecurityHandler.cc create mode 100644 xpdf/xpdf/SecurityHandler.h diff --git a/xpdf/xpdf/SecurityHandler.cc b/xpdf/xpdf/SecurityHandler.cc new file mode 100644 index 000000000..8825ce85e --- /dev/null +++ b/xpdf/xpdf/SecurityHandler.cc @@ -0,0 +1,376 @@ +//======================================================================== +// +// SecurityHandler.cc +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "GString.h" +#include "PDFDoc.h" +#include "Decrypt.h" +#include "Error.h" +#include "GlobalParams.h" +#if HAVE_XPDFCORE +# include "XPDFCore.h" +#elif HAVE_WINPDFCORE +# include "WinPDFCore.h" +#endif +#ifdef ENABLE_PLUGINS +# include "XpdfPluginAPI.h" +#endif +#include "SecurityHandler.h" + +//------------------------------------------------------------------------ +// SecurityHandler +//------------------------------------------------------------------------ + +SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) { + Object filterObj; + SecurityHandler *secHdlr; + XpdfSecurityHandler *xsh; + + encryptDictA->dictLookup("Filter", &filterObj); + if (filterObj.isName("Standard")) { + secHdlr = new StandardSecurityHandler(docA, encryptDictA); + } else if (filterObj.isName()) { +#ifdef ENABLE_PLUGINS + if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) { + secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh); + } else { +#endif + error(-1, "Couldn't find the '%s' security handler", + filterObj.getName()); + secHdlr = NULL; +#ifdef ENABLE_PLUGINS + } +#endif + } else { + error(-1, "Missing or invalid 'Filter' entry in encryption dictionary"); + secHdlr = NULL; + } + filterObj.free(); + return secHdlr; +} + +SecurityHandler::SecurityHandler(PDFDoc *docA) { + doc = docA; +} + +SecurityHandler::~SecurityHandler() { +} + +GBool SecurityHandler::checkEncryption(GString *ownerPassword, + GString *userPassword) { + void *authData; + GBool ok; + int i; + + if (ownerPassword || userPassword) { + authData = makeAuthData(ownerPassword, userPassword); + } else { + authData = NULL; + } + ok = authorize(authData); + if (authData) { + freeAuthData(authData); + } + for (i = 0; !ok && i < 3; ++i) { + if (!(authData = getAuthData())) { + break; + } + ok = authorize(authData); + if (authData) { + freeAuthData(authData); + } + } + if (!ok) { + error(-1, "Incorrect password"); + } + return ok; +} + +//------------------------------------------------------------------------ +// StandardSecurityHandler +//------------------------------------------------------------------------ + +class StandardAuthData { +public: + + StandardAuthData(GString *ownerPasswordA, GString *userPasswordA) { + ownerPassword = ownerPasswordA; + userPassword = userPasswordA; + } + + ~StandardAuthData() { + if (ownerPassword) { + delete ownerPassword; + } + if (userPassword) { + delete userPassword; + } + } + + GString *ownerPassword; + GString *userPassword; +}; + +StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA, + Object *encryptDictA): + SecurityHandler(docA) +{ + Object versionObj, revisionObj, lengthObj; + Object ownerKeyObj, userKeyObj, permObj, fileIDObj; + Object fileIDObj1; + Object cryptFiltersObj, streamFilterObj, stringFilterObj; + Object cryptFilterObj, cfmObj, cfLengthObj; + Object encryptMetadataObj; + + ok = gFalse; + fileID = NULL; + ownerKey = NULL; + userKey = NULL; + + encryptDictA->dictLookup("V", &versionObj); + encryptDictA->dictLookup("R", &revisionObj); + encryptDictA->dictLookup("Length", &lengthObj); + encryptDictA->dictLookup("O", &ownerKeyObj); + encryptDictA->dictLookup("U", &userKeyObj); + encryptDictA->dictLookup("P", &permObj); + doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj); + if (versionObj.isInt() && + revisionObj.isInt() && + ownerKeyObj.isString() && ownerKeyObj.getString()->getLength() == 32 && + userKeyObj.isString() && userKeyObj.getString()->getLength() == 32 && + permObj.isInt()) { + encVersion = versionObj.getInt(); + encRevision = revisionObj.getInt(); + // revision 2 forces a 40-bit key - some buggy PDF generators + // set the Length value incorrectly + if (encRevision == 2 || !lengthObj.isInt()) { + fileKeyLength = 5; + } else { + fileKeyLength = lengthObj.getInt() / 8; + } + encryptMetadata = gTrue; + //~ this currently only handles a subset of crypt filter functionality + if (encVersion == 4 && encRevision == 4) { + encryptDictA->dictLookup("CF", &cryptFiltersObj); + encryptDictA->dictLookup("StmF", &streamFilterObj); + encryptDictA->dictLookup("StrF", &stringFilterObj); + if (cryptFiltersObj.isDict() && + streamFilterObj.isName() && + stringFilterObj.isName() && + !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) { + if (cryptFiltersObj.dictLookup(streamFilterObj.getName(), + &cryptFilterObj)->isDict()) { + if (cryptFilterObj.dictLookup("CFM", &cfmObj)->isName("V2")) { + encVersion = 2; + encRevision = 3; + if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { + //~ according to the spec, this should be cfLengthObj / 8 + fileKeyLength = cfLengthObj.getInt(); + } + cfLengthObj.free(); + } + cfmObj.free(); + } + cryptFilterObj.free(); + } + stringFilterObj.free(); + streamFilterObj.free(); + cryptFiltersObj.free(); + if (encryptDictA->dictLookup("EncryptMetadata", + &encryptMetadataObj)->isBool()) { + encryptMetadata = encryptMetadataObj.getBool(); + } + encryptMetadataObj.free(); + } + permFlags = permObj.getInt(); + ownerKey = ownerKeyObj.getString()->copy(); + userKey = userKeyObj.getString()->copy(); + if (encVersion >= 1 && encVersion <= 2 && + encRevision >= 2 && encRevision <= 3) { + if (fileIDObj.isArray()) { + if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) { + fileID = fileIDObj1.getString()->copy(); + } else { + fileID = new GString(); + } + fileIDObj1.free(); + } else { + fileID = new GString(); + } + ok = gTrue; + } else { + error(-1, "Unsupported version/revision (%d/%d) of Standard security handler", + encVersion, encRevision); + } + } else { + error(-1, "Weird encryption info"); + } + if (fileKeyLength > 16) { + fileKeyLength = 16; + } + fileIDObj.free(); + permObj.free(); + userKeyObj.free(); + ownerKeyObj.free(); + lengthObj.free(); + revisionObj.free(); + versionObj.free(); +} + +StandardSecurityHandler::~StandardSecurityHandler() { + if (fileID) { + delete fileID; + } + if (ownerKey) { + delete ownerKey; + } + if (userKey) { + delete userKey; + } +} + +void *StandardSecurityHandler::makeAuthData(GString *ownerPassword, + GString *userPassword) { + return new StandardAuthData(ownerPassword ? ownerPassword->copy() + : (GString *)NULL, + userPassword ? userPassword->copy() + : (GString *)NULL); +} + +void *StandardSecurityHandler::getAuthData() { +#if HAVE_XPDFCORE + XPDFCore *core; + GString *password; + + if (!(core = (XPDFCore *)doc->getGUIData()) || + !(password = core->getPassword())) { + return NULL; + } + return new StandardAuthData(password, password->copy()); +#elif HAVE_WINPDFCORE + WinPDFCore *core; + GString *password; + + if (!(core = (WinPDFCore *)doc->getGUIData()) || + !(password = core->getPassword())) { + return NULL; + } + return new StandardAuthData(password, password->copy()); +#else + return NULL; +#endif +} + +void StandardSecurityHandler::freeAuthData(void *authData) { + delete (StandardAuthData *)authData; +} + +GBool StandardSecurityHandler::authorize(void *authData) { + GString *ownerPassword, *userPassword; + + if (!ok) { + return gFalse; + } + if (authData) { + ownerPassword = ((StandardAuthData *)authData)->ownerPassword; + userPassword = ((StandardAuthData *)authData)->userPassword; + } else { + ownerPassword = NULL; + userPassword = NULL; + } + if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength, + ownerKey, userKey, permFlags, fileID, + ownerPassword, userPassword, fileKey, + encryptMetadata, &ownerPasswordOk)) { + return gFalse; + } + return gTrue; +} + +#ifdef ENABLE_PLUGINS + +//------------------------------------------------------------------------ +// ExternalSecurityHandler +//------------------------------------------------------------------------ + +ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA, + Object *encryptDictA, + XpdfSecurityHandler *xshA): + SecurityHandler(docA) +{ + encryptDictA->copy(&encryptDict); + xsh = xshA; + ok = gFalse; + + if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA, + (XpdfObject)encryptDictA, &docData)) { + return; + } + + ok = gTrue; +} + +ExternalSecurityHandler::~ExternalSecurityHandler() { + (*xsh->freeDoc)(xsh->handlerData, docData); + encryptDict.free(); +} + +void *ExternalSecurityHandler::makeAuthData(GString *ownerPassword, + GString *userPassword) { + char *opw, *upw; + void *authData; + + opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL; + upw = userPassword ? userPassword->getCString() : (char *)NULL; + if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) { + return NULL; + } + return authData; +} + +void *ExternalSecurityHandler::getAuthData() { + void *authData; + + if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) { + return NULL; + } + return authData; +} + +void ExternalSecurityHandler::freeAuthData(void *authData) { + (*xsh->freeAuthData)(xsh->handlerData, docData, authData); +} + +GBool ExternalSecurityHandler::authorize(void *authData) { + char *key; + int length; + + if (!ok) { + return gFalse; + } + permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData); + if (!(permFlags & xpdfPermissionOpen)) { + return gFalse; + } + if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion)) { + return gFalse; + } + if ((fileKeyLength = length) > 16) { + fileKeyLength = 16; + } + memcpy(fileKey, key, fileKeyLength); + (*xsh->freeKey)(xsh->handlerData, docData, key, length); + return gTrue; +} + +#endif // ENABLE_PLUGINS diff --git a/xpdf/xpdf/SecurityHandler.h b/xpdf/xpdf/SecurityHandler.h new file mode 100644 index 000000000..127acb769 --- /dev/null +++ b/xpdf/xpdf/SecurityHandler.h @@ -0,0 +1,155 @@ +//======================================================================== +// +// SecurityHandler.h +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SECURITYHANDLER_H +#define SECURITYHANDLER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" + +class GString; +class PDFDoc; +struct XpdfSecurityHandler; + +//------------------------------------------------------------------------ +// SecurityHandler +//------------------------------------------------------------------------ + +class SecurityHandler { +public: + + static SecurityHandler *make(PDFDoc *docA, Object *encryptDictA); + + SecurityHandler(PDFDoc *docA); + virtual ~SecurityHandler(); + + // Check the document's encryption. If the document is encrypted, + // this will first try and (in + // "batch" mode), and if those fail, it will attempt to request a + // password from the user. This is the high-level function that + // calls the lower level functions for the specific security handler + // (requesting a password three times, etc.). Returns true if the + // document can be opened (if it's unencrypted, or if a correct + // password is obtained); false otherwise (encrypted and no correct + // password). + GBool checkEncryption(GString *ownerPassword, + GString *userPassword); + + // Create authorization data for the specified owner and user + // passwords. If the security handler doesn't support "batch" mode, + // this function should return NULL. + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword) = 0; + + // Construct authorization data, typically by prompting the user for + // a password. Returns an authorization data object, or NULL to + // cancel. + virtual void *getAuthData() = 0; + + // Free the authorization data returned by makeAuthData or + // getAuthData. + virtual void freeAuthData(void *authData) = 0; + + // Attempt to authorize the document, using the supplied + // authorization data (which may be NULL). Returns true if + // successful (i.e., if at least the right to open the document was + // granted). + virtual GBool authorize(void *authData) = 0; + + // Return the various authorization parameters. These are only + // valid after authorize has returned true. + virtual int getPermissionFlags() = 0; + virtual GBool getOwnerPasswordOk() = 0; + virtual Guchar *getFileKey() = 0; + virtual int getFileKeyLength() = 0; + virtual int getEncVersion() = 0; + +protected: + + PDFDoc *doc; +}; + +//------------------------------------------------------------------------ +// StandardSecurityHandler +//------------------------------------------------------------------------ + +class StandardSecurityHandler: public SecurityHandler { +public: + + StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA); + virtual ~StandardSecurityHandler(); + + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword); + virtual void *getAuthData(); + virtual void freeAuthData(void *authData); + virtual GBool authorize(void *authData); + virtual int getPermissionFlags() { return permFlags; } + virtual GBool getOwnerPasswordOk() { return ownerPasswordOk; } + virtual Guchar *getFileKey() { return fileKey; } + virtual int getFileKeyLength() { return fileKeyLength; } + virtual int getEncVersion() { return encVersion; } + +private: + + int permFlags; + GBool ownerPasswordOk; + Guchar fileKey[16]; + int fileKeyLength; + int encVersion; + int encRevision; + GBool encryptMetadata; + + GString *ownerKey, *userKey; + GString *fileID; + GBool ok; +}; + +#ifdef ENABLE_PLUGINS +//------------------------------------------------------------------------ +// ExternalSecurityHandler +//------------------------------------------------------------------------ + +class ExternalSecurityHandler: public SecurityHandler { +public: + + ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA, + XpdfSecurityHandler *xshA); + virtual ~ExternalSecurityHandler(); + + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword); + virtual void *getAuthData(); + virtual void freeAuthData(void *authData); + virtual GBool authorize(void *authData); + virtual int getPermissionFlags() { return permFlags; } + virtual GBool getOwnerPasswordOk() { return gFalse; } + virtual Guchar *getFileKey() { return fileKey; } + virtual int getFileKeyLength() { return fileKeyLength; } + virtual int getEncVersion() { return encVersion; } + +private: + + Object encryptDict; + XpdfSecurityHandler *xsh; + void *docData; + int permFlags; + Guchar fileKey[16]; + int fileKeyLength; + int encVersion; + GBool ok; +}; +#endif // ENABLE_PLUGINS + +#endif From ed88e19ae84930cab1c9d41907a8760b826d3958 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 24 Aug 2005 09:35:38 +0000 Subject: [PATCH 140/245] Fordward port Dirk's fix for delete -> delete[] svn path=/trunk/KDE/kdegraphics/kpdf/; revision=452738 --- core/generator_pdf/gp_outputdev.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/generator_pdf/gp_outputdev.cpp b/core/generator_pdf/gp_outputdev.cpp index 4e621f556..5c098c029 100644 --- a/core/generator_pdf/gp_outputdev.cpp +++ b/core/generator_pdf/gp_outputdev.cpp @@ -112,7 +112,7 @@ void KPDFOutputDev::endPage() img->setPixel( i, j, qRgb( pixel[0], pixel[1], pixel[2] ) ); } } - delete pixel; + delete[] pixel; // use the QImage or convert it immediately to QPixmap for better // handling and memory unloading From dddf2164063e8ee2a7e4978f51107e4aa47914d0 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 26 Aug 2005 13:11:41 +0000 Subject: [PATCH 141/245] Fordward port fix for bug 110171 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=453552 --- ui/minibar.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/minibar.cpp b/ui/minibar.cpp index 6f70c0907..663ba97a9 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -165,7 +165,6 @@ void MiniBar::notifySetup( const QVector< KPDFPage * > & pageVector, bool change m_nextButton->setFixedHeight( fixedHeight ); // update child widgets - m_pagesEdit->setText( "" ); m_pagesEdit->setPagesNumber( pages ); m_pagesButton->setText( QString::number( pages ) ); m_prevButton->setEnabled( false ); From d2af5239b75e654a0f8ebe9c11a23c0380dea443 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 28 Aug 2005 10:53:50 +0000 Subject: [PATCH 142/245] Fordward port fix for bug 110666 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=454213 --- core/generator_pdf/generator_pdf.cpp | 79 ++++++++++++++++++---------- core/generator_pdf/generator_pdf.h | 3 ++ ui/toc.cpp | 37 +++++++------ ui/toc.h | 2 + 4 files changed, 76 insertions(+), 45 deletions(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 477ed995e..1bb036c29 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -482,13 +482,7 @@ QString PDFGenerator::getMetaData( const QString & key, const QString & option ) LinkDest * destination = pdfdoc->findDest( namedDest ); if ( destination ) { - if ( !destination->isPageRef() ) - viewport.pageNumber = destination->getPageNum() - 1; - else - { - Ref ref = destination->getPageRef(); - viewport.pageNumber = pdfdoc->findPage( ref.num, ref.gen ) - 1; - } + fillViewportFromLink( viewport, destination ); } docLock.unlock(); delete namedDest; @@ -783,7 +777,7 @@ void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items ) // 2. find the page the link refers to LinkAction * a = outlineItem->getAction(); - if ( a && a->getKind() == actionGoTo ) + if ( a && ( a->getKind() == actionGoTo || a->getKind() == actionGoToR ) ) { // page number is contained/referenced in a LinkGoTo LinkGoTo * g = static_cast< LinkGoTo * >( a ); @@ -798,28 +792,12 @@ void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items ) } else if ( destination->isOk() ) { - // we have valid 'destination' -> get page number - int pageNumber = destination->getPageNum() - 1; - if ( destination->isPageRef() ) - { - Ref ref = destination->getPageRef(); - pageNumber = pdfdoc->findPage( ref.num, ref.gen ) - 1; - } - // set page as attribute to node - // TODO add other attributes to the viewport (taken from link) - item.setAttribute( "Viewport", DocumentViewport( pageNumber ).toString() ); - } - } - else if ( a && a->getKind() == actionGoToR ) - { - LinkGoToR * g = static_cast< LinkGoToR * >( a ); - LinkDest * destination = g->getDest(); - if ( !destination && g->getNamedDest() ) - { - item.setAttribute( "ViewportName", g->getNamedDest()->getCString() ); + DocumentViewport vp; + fillViewportFromLink( vp, destination ); + item.setAttribute( "Viewport", vp.toString() ); } - - item.setAttribute( "ExternalFileName", g->getFileName()->getCString() ); + if ( a->getKind() == actionGoToR ) + item.setAttribute( "ExternalFileName", g->getFileName()->getCString() ); } // 3. recursively descend over children @@ -830,6 +808,49 @@ void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items ) } } +void PDFGenerator::fillViewportFromLink( DocumentViewport &viewport, LinkDest *destination ) +{ + if ( !destination->isPageRef() ) + viewport.pageNumber = destination->getPageNum() - 1; + else + { + Ref ref = destination->getPageRef(); + viewport.pageNumber = pdfdoc->findPage( ref.num, ref.gen ) - 1; + } + + // get destination position + // TODO add other attributes to the viewport (taken from link) + switch ( destination->getKind() ) + { + case destXYZ: + if (destination->getChangeLeft() || destination->getChangeTop()) + { + double CTM[6]; + Page *page = pdfdoc->getCatalog()->getPage( viewport.pageNumber + 1 ); + // TODO remember to change this if we implement DPI and/or rotation + page->getDefaultCTM(CTM, 72.0, 72.0, 0, gTrue); + + int left, top; + // this is OutputDev::cvtUserToDev + left = (int)(CTM[0] * destination->getLeft() + CTM[2] * destination->getTop() + CTM[4] + 0.5); + top = (int)(CTM[1] * destination->getLeft() + CTM[3] * destination->getTop() + CTM[5] + 0.5); + + viewport.rePos.normalizedX = (double)left / (double)page->getCropWidth(); + viewport.rePos.normalizedY = (double)top / (double)page->getCropHeight(); + viewport.rePos.enabled = true; + viewport.rePos.pos = DocumentViewport::TopLeft; + } + /* TODO + if ( dest->getChangeZoom() ) + make zoom change*/ + break; + + default: + // implement the others cases + break; + } +} + void PDFGenerator::addTransition( int pageNumber, KPDFPage * page ) { Page *pdfPage = pdfdoc->getCatalog()->getPage( pageNumber + 1 ); diff --git a/core/generator_pdf/generator_pdf.h b/core/generator_pdf/generator_pdf.h index 67d789a69..fce494929 100644 --- a/core/generator_pdf/generator_pdf.h +++ b/core/generator_pdf/generator_pdf.h @@ -22,6 +22,7 @@ class Dict; class GfxFont; +class LinkDest; class Ref; class PDFDoc; class GList; @@ -89,6 +90,8 @@ class PDFGenerator : public Generator void scanFonts(Dict *resDict, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize); void scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize); + void fillViewportFromLink( DocumentViewport &viewport, LinkDest *destination ); + // private functions for accessing document informations via PDFDoc QString getDocumentInfo( const QString & data ) const; QString getDocumentDate( const QString & data ) const; diff --git a/ui/toc.cpp b/ui/toc.cpp index c06342821..cc0229008 100644 --- a/ui/toc.cpp +++ b/ui/toc.cpp @@ -13,7 +13,6 @@ // local includes #include "toc.h" -#include "core/document.h" #include "core/link.h" #include "core/page.h" @@ -73,7 +72,7 @@ uint TOC::observerId() const return TOC_ID; } -void TOC::notifySetup( const QVector< KPDFPage * > & pages, bool documentChanged ) +void TOC::notifySetup( const QVector< KPDFPage * > & /*pages*/, bool documentChanged ) { if ( !documentChanged ) return; @@ -130,25 +129,31 @@ void TOC::slotExecuted( Q3ListViewItem *i ) QString externalFileName = e.attribute( "ExternalFileName" ); if ( !externalFileName.isEmpty() ) { - KPDFLinkGoto link( externalFileName, DocumentViewport() ); + KPDFLinkGoto link( externalFileName, getViewport( e ) ); m_document->processLink( &link ); } else { - if ( e.hasAttribute( "Viewport" ) ) - { - // if the node has a viewport, set it - m_document->setViewport( DocumentViewport( e.attribute( "Viewport" ) ), TOC_ID ); - } - else if ( e.hasAttribute( "ViewportName" ) ) - { - // if the node references a viewport, get the reference and set it - const QString & page = e.attribute( "ViewportName" ); - const QString & viewport = m_document->getMetaData( "NamedViewport", page ); - if ( !viewport.isNull() ) - m_document->setViewport( DocumentViewport( viewport ), TOC_ID ); - } + m_document->setViewport( getViewport( e ), TOC_ID ); + } +} + +DocumentViewport TOC::getViewport( const QDomElement &e ) const +{ + if ( e.hasAttribute( "Viewport" ) ) + { + // if the node has a viewport, set it + return DocumentViewport( e.attribute( "Viewport" ) ); + } + else if ( e.hasAttribute( "ViewportName" ) ) + { + // if the node references a viewport, get the reference and set it + const QString & page = e.attribute( "ViewportName" ); + const QString & viewport = m_document->getMetaData( "NamedViewport", page ); + if ( !viewport.isNull() ) + return DocumentViewport( viewport ); } + return DocumentViewport(); } #include "toc.moc" diff --git a/ui/toc.h b/ui/toc.h index 82314e794..56861c680 100644 --- a/ui/toc.h +++ b/ui/toc.h @@ -12,6 +12,7 @@ #include #include +#include "core/document.h" #include "core/observer.h" class KPDFDocument; @@ -34,6 +35,7 @@ Q_OBJECT private: void addChildren( const QDomNode & parentNode, KListViewItem * parentItem = 0 ); + DocumentViewport getViewport( const QDomElement &e ) const; KPDFDocument *m_document; }; From 71c09c02843b020f7eb1e79df2f0b49f6b875c66 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 28 Aug 2005 18:46:05 +0000 Subject: [PATCH 143/245] Fordward port the makeItCompile svn path=/trunk/KDE/kdegraphics/kpdf/; revision=454380 --- core/generator_pdf/generator_pdf.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 1bb036c29..b5f1ac82b 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -797,7 +797,10 @@ void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items ) item.setAttribute( "Viewport", vp.toString() ); } if ( a->getKind() == actionGoToR ) - item.setAttribute( "ExternalFileName", g->getFileName()->getCString() ); + { + LinkGoToR * g2 = static_cast< LinkGoToR * >( a ); + item.setAttribute( "ExternalFileName", g2->getFileName()->getCString() ); + } } // 3. recursively descend over children From 2c43c2b6dcc7e86ee0d20c9680a338638fd3bedb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 1 Sep 2005 14:08:14 +0000 Subject: [PATCH 144/245] Fordwardport If somebody from the upper spheres (like Konqui for example) gives us the mimetype use it instead trying to guess the mimetype ourselves for the file we are opening, fixes problem in opening a pdf file generated by php code svn path=/trunk/KDE/kdegraphics/kpdf/; revision=455836 --- core/document.cpp | 4 +--- core/document.h | 4 +++- part.cpp | 12 ++++++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 20892bc23..6bf547558 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -133,7 +132,7 @@ KPDFDocument::~KPDFDocument() } -bool KPDFDocument::openDocument( const QString & docFile, const KURL & url ) +bool KPDFDocument::openDocument( const QString & docFile, const KURL & url, const KMimeType::Ptr &mime ) { // docFile is always local so we can use QFile on it QFile fileReadTest( docFile ); @@ -151,7 +150,6 @@ bool KPDFDocument::openDocument( const QString & docFile, const KURL & url ) d->xmlFileName = locateLocal( "data", fn ); // create the generator based on the file's mimetype - KMimeType::Ptr mime = KMimeType::findByPath( docFile ); if ( (*mime).is( "application/pdf" ) ) generator = new PDFGenerator( this ); // else if ( mimeName == "application/postscript" ) diff --git a/core/document.h b/core/document.h index 2df9a3a13..497d9afe2 100644 --- a/core/document.h +++ b/core/document.h @@ -18,6 +18,8 @@ class QColor; +#include + class KPDFPage; class KPDFLink; class DocumentObserver; @@ -55,7 +57,7 @@ class KPDFDocument : public QObject ~KPDFDocument(); // document handling - bool openDocument( const QString & docFile, const KURL & url ); + bool openDocument( const QString & docFile, const KURL & url, const KMimeType::Ptr &mime ); void closeDocument(); // misc methods diff --git a/part.cpp b/part.cpp index 84f442e33..03cfdfdf2 100644 --- a/part.cpp +++ b/part.cpp @@ -347,7 +347,15 @@ KAboutData* Part::createAboutData() bool Part::openFile() { - KMimeType::Ptr mime = KMimeType::findByPath( m_file ); + KMimeType::Ptr mime; + if ( m_bExtension->urlArgs().serviceType.isEmpty() ) + { + mime = KMimeType::findByPath( m_file ); + } + else + { + mime = KMimeType::mimeType( m_bExtension->urlArgs().serviceType ); + } if ( (*mime).is( "application/postscript" ) ) { QString app = KStandardDirs::findExe( "ps2pdf" ); @@ -377,7 +385,7 @@ bool Part::openFile() m_temporaryLocalFile = QString::null; - bool ok = m_document->openDocument( m_file, url() ); + bool ok = m_document->openDocument( m_file, url(), mime ); // update one-time actions m_find->setEnabled( ok && m_document-> supportsSearching()); From 7cde12502b25b5484e6aaed322abb5a3074d7c14 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 1 Sep 2005 16:17:54 +0000 Subject: [PATCH 145/245] Don't disable print action when reloading a modified document svn path=/trunk/KDE/kdegraphics/kpdf/; revision=455895 --- part.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/part.cpp b/part.cpp index 03cfdfdf2..c66a9cb1f 100644 --- a/part.cpp +++ b/part.cpp @@ -503,6 +503,7 @@ void Part::slotDoFileDirty() if (m_viewportDirty.pageNumber >= (int)m_document->pages()) m_viewportDirty.pageNumber = (int)m_document->pages() - 1; m_document->setViewport(m_viewportDirty); m_viewportDirty.pageNumber = -1; + emit enablePrintAction(true); } else { From efdcff8460c816187288dad9af314c75785cd094 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 3 Sep 2005 10:44:18 +0000 Subject: [PATCH 146/245] Fordwardport fix for 105361 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=456599 --- ui/presentationwidget.cpp | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index ff0c3f5df..82e577afc 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -715,19 +715,26 @@ void PresentationWidget::slotNextPage() { // go to next page changePage( m_frameIndex + 1 ); + + // auto advance to the next page if set + if ( KpdfSettings::slidesAdvance() ) + QTimer::singleShot( KpdfSettings::slidesAdvanceTime() * 1000, this, SLOT( slotNextPage() ) ); } - else if ( m_transitionTimer->isActive() ) + else { - m_transitionTimer->stop(); - update(); +#ifdef ENABLE_PROGRESS_OVERLAY + if ( KpdfSettings::slidesShowProgress() ) + generateOverlay(); +#endif + if ( m_transitionTimer->isActive() ) + { + m_transitionTimer->stop(); + update(); + } } // we need the setFocus() call here to let KCursor::autoHide() work correctly setFocus(); - - // auto advance to the next page if set - if ( KpdfSettings::slidesAdvance() ) - QTimer::singleShot( KpdfSettings::slidesAdvanceTime() * 1000, this, SLOT( slotNextPage() ) ); } void PresentationWidget::slotPrevPage() @@ -736,11 +743,22 @@ void PresentationWidget::slotPrevPage() { // go to previous page changePage( m_frameIndex - 1 ); + + // auto advance to the next page if set + if ( KpdfSettings::slidesAdvance() ) + QTimer::singleShot( KpdfSettings::slidesAdvanceTime() * 1000, this, SLOT( slotNextPage() ) ); } - else if ( m_transitionTimer->isActive() ) + else { - m_transitionTimer->stop(); - update(); +#ifdef ENABLE_PROGRESS_OVERLAY + if ( KpdfSettings::slidesShowProgress() ) + generateOverlay(); +#endif + if ( m_transitionTimer->isActive() ) + { + m_transitionTimer->stop(); + update(); + } } } From ed7f67662598b38adcb7f0af2b5da0eb47cb87df Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Wed, 7 Sep 2005 21:26:27 +0000 Subject: [PATCH 147/245] Fir virtual destructor svn path=/trunk/KDE/kdegraphics/kpdf/; revision=458352 --- core/observer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/core/observer.h b/core/observer.h index 39d54582d..de6037fbe 100644 --- a/core/observer.h +++ b/core/observer.h @@ -40,6 +40,7 @@ class KPDFPage; class DocumentObserver { public: + virtual ~DocumentObserver(){} // you must give each observer a unique ID (used for notifications) virtual uint observerId() const = 0; From db94015b2db284bb3748c9e6e129ae3320df7dd3 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 9 Sep 2005 13:53:13 +0000 Subject: [PATCH 148/245] unblock the viewportupdating when we get a invalid viewport svn path=/trunk/KDE/kdegraphics/kpdf/; revision=458975 --- ui/pageview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 770ddf6be..982579965 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -313,6 +313,7 @@ void PageView::notifyViewportChanged( bool smoothMove ) if ( !item ) { kdDebug() << "viewport has no matching item!" << endl; + d->blockViewport = false; return; } From df91a1004ef1dea2a551cb779526e13b4bd3f62a Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 9 Sep 2005 18:27:37 +0000 Subject: [PATCH 149/245] Fordward port the usage of UGString for LinkDests and Dict Keys that makes bug 110278 work svn path=/trunk/KDE/kdegraphics/kpdf/; revision=459065 --- core/generator_pdf/generator_pdf.cpp | 27 ++++++--- core/generator_pdf/gp_outputdev.cpp | 2 +- core/generator_pdf/gp_outputdev.h | 2 +- xpdf/xpdf/Annot.cc | 9 +-- xpdf/xpdf/Catalog.cc | 16 ++++-- xpdf/xpdf/Catalog.h | 7 ++- xpdf/xpdf/Dict.cc | 17 +++--- xpdf/xpdf/Dict.h | 16 +++--- xpdf/xpdf/Function.cc | 1 + xpdf/xpdf/Gfx.cc | 2 + xpdf/xpdf/GfxFont.cc | 5 +- xpdf/xpdf/GfxState.cc | 1 + xpdf/xpdf/Link.cc | 9 +-- xpdf/xpdf/Link.h | 9 +-- xpdf/xpdf/Makefile.am | 2 +- xpdf/xpdf/Object.h | 17 +++--- xpdf/xpdf/Outline.cc | 1 + xpdf/xpdf/PDFDoc.cc | 1 + xpdf/xpdf/PDFDoc.h | 2 +- xpdf/xpdf/PSOutputDev.cc | 5 +- xpdf/xpdf/Page.cc | 1 + xpdf/xpdf/Parser.cc | 3 + xpdf/xpdf/SecurityHandler.cc | 1 + xpdf/xpdf/Stream.cc | 1 + xpdf/xpdf/UGString.cc | 86 ++++++++++++++++++++++++++++ xpdf/xpdf/UGString.h | 55 ++++++++++++++++++ xpdf/xpdf/XRef.cc | 1 + 27 files changed, 241 insertions(+), 58 deletions(-) create mode 100644 xpdf/xpdf/UGString.cc create mode 100644 xpdf/xpdf/UGString.h diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index b5f1ac82b..8c63ed0d8 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -35,6 +35,7 @@ #include "xpdf/ErrorCodes.h" #include "xpdf/UnicodeMap.h" #include "xpdf/Outline.h" +#include "xpdf/UGString.h" #include "goo/GList.h" // local includes @@ -464,6 +465,14 @@ bool PDFGenerator::print( KPrinter& printer ) } } +static UGString *QStringToUGString(const QString &s) { + int len = s.length(); + Unicode *u = (Unicode *)gmallocn(s.length(), sizeof(Unicode)); + for (int i = 0; i < len; ++i) + u[i] = s.at(i).unicode(); + return new UGString(u, len); +} + QString PDFGenerator::getMetaData( const QString & key, const QString & option ) { if ( key == "StartFullScreen" ) @@ -477,7 +486,7 @@ QString PDFGenerator::getMetaData( const QString & key, const QString & option ) // asking for the page related to a 'named link destination'. the // option is the link name. @see addSynopsisChildren. DocumentViewport viewport; - GString * namedDest = new GString( option.latin1() ); + UGString * namedDest = QStringToUGString( option ); docLock.lock(); LinkDest * destination = pdfdoc->findDest( namedDest ); if ( destination ) @@ -788,7 +797,9 @@ void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items ) // get the destination for the page now, but it's VERY time consuming, // so better storing the reference and provide the viewport as metadata // on demand - item.setAttribute( "ViewportName", g->getNamedDest()->getCString() ); + UGString *s = g->getNamedDest(); + QString aux = unicodeToQString( s->unicode(), s->getLength() ); + item.setAttribute( "ViewportName", aux ); } else if ( destination->isOk() ) { @@ -823,9 +834,9 @@ void PDFGenerator::fillViewportFromLink( DocumentViewport &viewport, LinkDest *d // get destination position // TODO add other attributes to the viewport (taken from link) - switch ( destination->getKind() ) - { - case destXYZ: +// switch ( destination->getKind() ) +// { +// case destXYZ: if (destination->getChangeLeft() || destination->getChangeTop()) { double CTM[6]; @@ -846,12 +857,12 @@ void PDFGenerator::fillViewportFromLink( DocumentViewport &viewport, LinkDest *d /* TODO if ( dest->getChangeZoom() ) make zoom change*/ - break; +/* break; default: // implement the others cases - break; - } + break;*/ +// } } void PDFGenerator::addTransition( int pageNumber, KPDFPage * page ) diff --git a/core/generator_pdf/gp_outputdev.cpp b/core/generator_pdf/gp_outputdev.cpp index 5c098c029..1ea21909a 100644 --- a/core/generator_pdf/gp_outputdev.cpp +++ b/core/generator_pdf/gp_outputdev.cpp @@ -321,7 +321,7 @@ KPDFLink * KPDFOutputDev::generateLink( LinkAction * a ) return link; } -DocumentViewport KPDFOutputDev::decodeViewport( GString * namedDest, LinkDest * dest ) +DocumentViewport KPDFOutputDev::decodeViewport( UGString * namedDest, LinkDest * dest ) // note: this function is called when processing a page, when the MUTEX is already LOCKED { DocumentViewport vp( -1 ); diff --git a/core/generator_pdf/gp_outputdev.h b/core/generator_pdf/gp_outputdev.h index ee8951687..c938eb543 100644 --- a/core/generator_pdf/gp_outputdev.h +++ b/core/generator_pdf/gp_outputdev.h @@ -71,7 +71,7 @@ class KPDFOutputDev : public SplashOutputDev // generate a valid KPDFLink subclass (or null) from a xpdf's LinkAction KPDFLink * generateLink( LinkAction * a ); // fills up a Viewport structure out of a given LinkGoto link - DocumentViewport decodeViewport( GString *, class LinkDest * ); + DocumentViewport decodeViewport( UGString *, class LinkDest * ); // generator switches and parameters bool m_qtThreadSafety; diff --git a/xpdf/xpdf/Annot.cc b/xpdf/xpdf/Annot.cc index 68bfb6d0b..4e5041bce 100644 --- a/xpdf/xpdf/Annot.cc +++ b/xpdf/xpdf/Annot.cc @@ -19,6 +19,7 @@ #include "Gfx.h" #include "Lexer.h" #include "Annot.h" +#include "UGString.h" //------------------------------------------------------------------------ // Annot @@ -210,15 +211,15 @@ void Annot::generateAppearance(Dict *acroForm, Dict *dict) { // build the appearance stream dictionary appearDict.initDict(xref); - appearDict.dictAdd(copyString("Length"), + appearDict.dictAdd("Length", obj1.initInt(appearBuf->getLength())); - appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form")); + appearDict.dictAdd("Subtype", obj1.initName("Form")); obj1.initArray(xref); obj1.arrayAdd(obj2.initReal(0)); obj1.arrayAdd(obj2.initReal(0)); obj1.arrayAdd(obj2.initReal(xMax - xMin)); obj1.arrayAdd(obj2.initReal(yMax - yMin)); - appearDict.dictAdd(copyString("BBox"), &obj1); + appearDict.dictAdd("BBox", &obj1); // find the resource dictionary dict->lookup("DR", &drObj); @@ -243,7 +244,7 @@ void Annot::generateAppearance(Dict *acroForm, Dict *dict) { } } if (drObj.isDict()) { - appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1)); + appearDict.dictAdd("Resources", drObj.copy(&obj1)); } drObj.free(); diff --git a/xpdf/xpdf/Catalog.cc b/xpdf/xpdf/Catalog.cc index 6c3da8df9..097d5094e 100644 --- a/xpdf/xpdf/Catalog.cc +++ b/xpdf/xpdf/Catalog.cc @@ -23,6 +23,7 @@ #include "Page.h" #include "Error.h" #include "Link.h" +#include "UGString.h" #include "Catalog.h" //------------------------------------------------------------------------ @@ -269,7 +270,7 @@ int Catalog::findPage(int num, int gen) { return 0; } -LinkDest *Catalog::findDest(GString *name) { +LinkDest *Catalog::findDest(UGString *name) { LinkDest *dest; Object obj1, obj2; GBool found; @@ -277,7 +278,7 @@ LinkDest *Catalog::findDest(GString *name) { // try named destination dictionary then name tree found = gFalse; if (dests.isDict()) { - if (!dests.dictLookup(name->getCString(), &obj1)->isNull()) + if (!dests.dictLookup(*name, &obj1)->isNull()) found = gTrue; else obj1.free(); @@ -321,12 +322,15 @@ NameTree::NameTree(void) } NameTree::Entry::Entry(Array *array, int index) { - if (!array->getString(index, &name) || !array->getNF(index + 1, &value)) + GString n; + if (!array->getString(index, &n) || !array->getNF(index + 1, &value)) error(-1, "Invalid page tree"); + name = new UGString(n); } NameTree::Entry::~Entry() { value.free(); + delete name; } void NameTree::addEntry(Entry *entry) @@ -380,13 +384,13 @@ void NameTree::parse(Object *tree) { int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry) { - GString *key = (GString *) voidKey; + UGString *key = (UGString *) voidKey; Entry *entry = *(NameTree::Entry **) voidEntry; - return key->cmp(&entry->name); + return key->cmp(entry->name); } -GBool NameTree::lookup(GString *name, Object *obj) +GBool NameTree::lookup(UGString *name, Object *obj) { Entry *entry; diff --git a/xpdf/xpdf/Catalog.h b/xpdf/xpdf/Catalog.h index 2ca6db9e9..700618d66 100644 --- a/xpdf/xpdf/Catalog.h +++ b/xpdf/xpdf/Catalog.h @@ -21,6 +21,7 @@ class Page; class PageAttrs; struct Ref; class LinkDest; +class UGString; //------------------------------------------------------------------------ // NameTree @@ -31,14 +32,14 @@ public: NameTree(); void init(XRef *xref, Object *tree); void parse(Object *tree); - GBool lookup(GString *name, Object *obj); + GBool lookup(UGString *name, Object *obj); void free(); private: struct Entry { Entry(Array *array, int index); ~Entry(); - GString name; + UGString *name; Object value; void free(); static int cmp(const void *key, const void *entry); @@ -104,7 +105,7 @@ public: // Find a named destination. Returns the link destination, or // NULL if is not a destination. - LinkDest *findDest(GString *name); + LinkDest *findDest(UGString *name); Object *getOutline() { return &outline; } diff --git a/xpdf/xpdf/Dict.cc b/xpdf/xpdf/Dict.cc index f17aca444..1edb3a4b4 100644 --- a/xpdf/xpdf/Dict.cc +++ b/xpdf/xpdf/Dict.cc @@ -18,6 +18,7 @@ #include "Object.h" #include "XRef.h" #include "Dict.h" +#include "UGString.h" //------------------------------------------------------------------------ // Dict @@ -34,13 +35,13 @@ Dict::~Dict() { int i; for (i = 0; i < length; ++i) { - gfree((void*)entries[i].key); + delete entries[i].key; entries[i].val.free(); } gfree(entries); } -void Dict::add(const char *key, Object *val) { +void Dict::add(const UGString &key, Object *val) { if (length == size) { if (length == 0) { size = 8; @@ -49,16 +50,16 @@ void Dict::add(const char *key, Object *val) { } entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry)); } - entries[length].key = key; + entries[length].key = new UGString(key); entries[length].val = *val; ++length; } -inline DictEntry *Dict::find(const char *key) { +inline DictEntry *Dict::find(const UGString &key) { int i; for (i = 0; i < length; ++i) { - if (!strcmp(key, entries[i].key)) + if (!key.cmp(entries[i].key)) return &entries[i]; } return NULL; @@ -70,19 +71,19 @@ GBool Dict::is(const char *type) { return (e = find("Type")) && e->val.isName(type); } -Object *Dict::lookup(const char *key, Object *obj) { +Object *Dict::lookup(const UGString &key, Object *obj) { DictEntry *e; return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull(); } -Object *Dict::lookupNF(const char *key, Object *obj) { +Object *Dict::lookupNF(const UGString &key, Object *obj) { DictEntry *e; return (e = find(key)) ? e->val.copy(obj) : obj->initNull(); } -const char *Dict::getKey(int i) { +UGString *Dict::getKey(int i) { return entries[i].key; } diff --git a/xpdf/xpdf/Dict.h b/xpdf/xpdf/Dict.h index ba8f70118..22b49b1f9 100644 --- a/xpdf/xpdf/Dict.h +++ b/xpdf/xpdf/Dict.h @@ -17,12 +17,14 @@ #include "Object.h" +class UGString; + //------------------------------------------------------------------------ // Dict //------------------------------------------------------------------------ struct DictEntry { - const char *key; + UGString *key; Object val; }; @@ -42,19 +44,19 @@ public: // Get number of entries. int getLength() { return length; } - // Add an entry. NB: does not copy key. - void add(const char *key, Object *val); + // Add an entry. + void add(const UGString &key, Object *val); // Check if dictionary is of specified type. GBool is(const char *type); // Look up an entry and return the value. Returns a null object // if is not in the dictionary. - Object *lookup(const char *key, Object *obj); - Object *lookupNF(const char *key, Object *obj); + Object *lookup(const UGString &key, Object *obj); + Object *lookupNF(const UGString &key, Object *obj); // Iterative accessors. - const char *getKey(int i); + UGString *getKey(int i); Object *getVal(int i, Object *obj); Object *getValNF(int i, Object *obj); @@ -71,7 +73,7 @@ private: int length; // number of entries in dictionary int ref; // reference count - DictEntry *find(const char *key); + DictEntry *find(const UGString &key); }; #endif diff --git a/xpdf/xpdf/Function.cc b/xpdf/xpdf/Function.cc index b1caf39ed..4b66ee918 100644 --- a/xpdf/xpdf/Function.cc +++ b/xpdf/xpdf/Function.cc @@ -22,6 +22,7 @@ #include "Stream.h" #include "Error.h" #include "Function.h" +#include "UGString.h" //------------------------------------------------------------------------ // Function diff --git a/xpdf/xpdf/Gfx.cc b/xpdf/xpdf/Gfx.cc index c2235331d..cb93a405f 100644 --- a/xpdf/xpdf/Gfx.cc +++ b/xpdf/xpdf/Gfx.cc @@ -32,6 +32,7 @@ #include "Page.h" #include "Error.h" #include "Gfx.h" +#include "UGString.h" // the MSVC math.h doesn't define this #ifndef M_PI @@ -3489,6 +3490,7 @@ Stream *Gfx::buildImageStream() { break; } dict.dictAdd(key, &obj); + gfree((void*)key); } parser->getObj(&obj); } diff --git a/xpdf/xpdf/GfxFont.cc b/xpdf/xpdf/GfxFont.cc index 9c031c932..ea407761e 100644 --- a/xpdf/xpdf/GfxFont.cc +++ b/xpdf/xpdf/GfxFont.cc @@ -28,6 +28,7 @@ #include "FoFiType1.h" #include "FoFiType1C.h" #include "FoFiTrueType.h" +#include "UGString.h" #include "GfxFont.h" //------------------------------------------------------------------------ @@ -1555,8 +1556,10 @@ GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { r.gen = 999999; } } - fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i), + const char *aux = fontDict->getKey(i)->getCString(); + fonts[i] = GfxFont::makeFont(xref, aux, r, obj2.getDict()); + delete[] aux; if (fonts[i] && !fonts[i]->isOk()) { delete fonts[i]; fonts[i] = NULL; diff --git a/xpdf/xpdf/GfxState.cc b/xpdf/xpdf/GfxState.cc index a5d5bf931..a2219b8be 100644 --- a/xpdf/xpdf/GfxState.cc +++ b/xpdf/xpdf/GfxState.cc @@ -20,6 +20,7 @@ #include "Object.h" #include "Array.h" #include "Page.h" +#include "UGString.h" #include "GfxState.h" //------------------------------------------------------------------------ diff --git a/xpdf/xpdf/Link.cc b/xpdf/xpdf/Link.cc index 26f3054d5..ab833d120 100644 --- a/xpdf/xpdf/Link.cc +++ b/xpdf/xpdf/Link.cc @@ -16,6 +16,7 @@ #include #include "gmem.h" #include "GString.h" +#include "UGString.h" #include "Error.h" #include "Object.h" #include "Array.h" @@ -419,9 +420,9 @@ LinkGoTo::LinkGoTo(Object *destObj) { // named destination if (destObj->isName()) { - namedDest = new GString(destObj->getName()); + namedDest = new UGString(destObj->getName()); } else if (destObj->isString()) { - namedDest = destObj->getString()->copy(); + namedDest = new UGString(*destObj->getString()); // destination dictionary } else if (destObj->isArray()) { @@ -457,9 +458,9 @@ LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) { // named destination if (destObj->isName()) { - namedDest = new GString(destObj->getName()); + namedDest = new UGString(destObj->getName()); } else if (destObj->isString()) { - namedDest = destObj->getString()->copy(); + namedDest = new UGString(*destObj->getString()); // destination dictionary } else if (destObj->isArray()) { diff --git a/xpdf/xpdf/Link.h b/xpdf/xpdf/Link.h index 75fb4dc71..c2c973466 100644 --- a/xpdf/xpdf/Link.h +++ b/xpdf/xpdf/Link.h @@ -18,6 +18,7 @@ #include "Object.h" class GString; +class UGString; class Array; class Dict; @@ -136,13 +137,13 @@ public: // Accessors. virtual LinkActionKind getKind() { return actionGoTo; } LinkDest *getDest() { return dest; } - GString *getNamedDest() { return namedDest; } + UGString *getNamedDest() { return namedDest; } private: LinkDest *dest; // regular destination (NULL for remote // link with bad destination) - GString *namedDest; // named destination (only one of dest and + UGString *namedDest; // named destination (only one of dest and // and namedDest may be non-NULL) }; @@ -167,14 +168,14 @@ public: virtual LinkActionKind getKind() { return actionGoToR; } GString *getFileName() { return fileName; } LinkDest *getDest() { return dest; } - GString *getNamedDest() { return namedDest; } + UGString *getNamedDest() { return namedDest; } private: GString *fileName; // file name LinkDest *dest; // regular destination (NULL for remote // link with bad destination) - GString *namedDest; // named destination (only one of dest and + UGString *namedDest; // named destination (only one of dest and // and namedDest may be non-NULL) }; diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am index db2709e24..f24d09dd9 100644 --- a/xpdf/xpdf/Makefile.am +++ b/xpdf/xpdf/Makefile.am @@ -9,7 +9,7 @@ libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ JBIG2Stream.cc Lexer.cc Link.cc NameToCharCode.cc Object.cc Outline.cc \ OutputDev.cc PDFDoc.cc PDFDocEncoding.cc PSTokenizer.cc \ Page.cc Parser.cc PSOutputDev.cc SecurityHandler.cc SplashOutputDev.cc Stream.cc JPXStream.cc \ - TextOutputDev.cc UnicodeMap.cc UnicodeTypeTable.cc XRef.cc + TextOutputDev.cc UnicodeMap.cc UnicodeTypeTable.cc UGString.cc XRef.cc noinst_LTLIBRARIES = libxpdf.la diff --git a/xpdf/xpdf/Object.h b/xpdf/xpdf/Object.h index 2982f9ae3..2a1d927be 100644 --- a/xpdf/xpdf/Object.h +++ b/xpdf/xpdf/Object.h @@ -25,6 +25,7 @@ class XRef; class Array; class Dict; class Stream; +class UGString; //------------------------------------------------------------------------ // Ref @@ -165,11 +166,11 @@ public: // Dict accessors. int dictGetLength(); - void dictAdd(const char *key, Object *val); + void dictAdd(const UGString &key, Object *val); GBool dictIs(const char *dictType); - Object *dictLookup(const char *key, Object *obj); - Object *dictLookupNF(const char *key, Object *obj); - const char *dictGetKey(int i); + Object *dictLookup(const UGString &key, Object *obj); + Object *dictLookupNF(const UGString &key, Object *obj); + UGString *dictGetKey(int i); Object *dictGetVal(int i, Object *obj); Object *dictGetValNF(int i, Object *obj); @@ -240,7 +241,7 @@ inline Object *Object::arrayGetNF(int i, Object *obj) inline int Object::dictGetLength() { return dict->getLength(); } -inline void Object::dictAdd(const char *key, Object *val) +inline void Object::dictAdd(const UGString &key, Object *val) { dict->add(key, val); } inline GBool Object::dictIs(const char *dictType) @@ -249,13 +250,13 @@ inline GBool Object::dictIs(const char *dictType) inline GBool Object::isDict(const char *dictType) { return type == objDict && dictIs(dictType); } -inline Object *Object::dictLookup(const char *key, Object *obj) +inline Object *Object::dictLookup(const UGString &key, Object *obj) { return dict->lookup(key, obj); } -inline Object *Object::dictLookupNF(const char *key, Object *obj) +inline Object *Object::dictLookupNF(const UGString &key, Object *obj) { return dict->lookupNF(key, obj); } -inline const char *Object::dictGetKey(int i) +inline UGString *Object::dictGetKey(int i) { return dict->getKey(i); } inline Object *Object::dictGetVal(int i, Object *obj) diff --git a/xpdf/xpdf/Outline.cc b/xpdf/xpdf/Outline.cc index 39e89a3c3..cc607e2eb 100644 --- a/xpdf/xpdf/Outline.cc +++ b/xpdf/xpdf/Outline.cc @@ -17,6 +17,7 @@ #include "GList.h" #include "Link.h" #include "PDFDocEncoding.h" +#include "UGString.h" #include "Outline.h" //------------------------------------------------------------------------ diff --git a/xpdf/xpdf/PDFDoc.cc b/xpdf/xpdf/PDFDoc.cc index 9849d74a3..0046d37cf 100644 --- a/xpdf/xpdf/PDFDoc.cc +++ b/xpdf/xpdf/PDFDoc.cc @@ -33,6 +33,7 @@ #ifndef DISABLE_OUTLINE #include "Outline.h" #endif +#include "UGString.h" #include "PDFDoc.h" //------------------------------------------------------------------------ diff --git a/xpdf/xpdf/PDFDoc.h b/xpdf/xpdf/PDFDoc.h index e2131edbd..4542e9158 100644 --- a/xpdf/xpdf/PDFDoc.h +++ b/xpdf/xpdf/PDFDoc.h @@ -130,7 +130,7 @@ public: // Find a named destination. Returns the link destination, or // NULL if is not a destination. - LinkDest *findDest(GString *name) + LinkDest *findDest(UGString *name) { return catalog->findDest(name); } #ifndef DISABLE_OUTLINE diff --git a/xpdf/xpdf/PSOutputDev.cc b/xpdf/xpdf/PSOutputDev.cc index 5322264b3..50186c3f8 100644 --- a/xpdf/xpdf/PSOutputDev.cc +++ b/xpdf/xpdf/PSOutputDev.cc @@ -35,6 +35,7 @@ #include "Page.h" #include "Stream.h" #include "Annot.h" +#include "UGString.h" #include "PSOutputDev.h" #ifdef MACOS @@ -2293,7 +2294,9 @@ void PSOutputDev::setupType3Font(GfxFont *font, GString *psName, t3Cacheable = gFalse; for (i = 0; i < charProcs->getLength(); ++i) { writePS("/"); - writePSName(charProcs->getKey(i)); + const char *aux = charProcs->getKey(i)->getCString(); + writePSName(aux); + delete[] aux; writePS(" {\n"); gfx->display(charProcs->getVal(i, &charProc)); charProc.free(); diff --git a/xpdf/xpdf/Page.cc b/xpdf/xpdf/Page.cc index 227ba0782..3f035c452 100644 --- a/xpdf/xpdf/Page.cc +++ b/xpdf/xpdf/Page.cc @@ -26,6 +26,7 @@ #include "Annot.h" #endif #include "Error.h" +#include "UGString.h" #include "Page.h" //------------------------------------------------------------------------ diff --git a/xpdf/xpdf/Parser.cc b/xpdf/xpdf/Parser.cc index 892b72a92..e9e3809ed 100644 --- a/xpdf/xpdf/Parser.cc +++ b/xpdf/xpdf/Parser.cc @@ -20,6 +20,7 @@ #include "XRef.h" #include "Error.h" #include "Decrypt.h" +#include "UGString.h" Parser::Parser(XRef *xrefA, Lexer *lexerA) { xref = xrefA; @@ -75,6 +76,7 @@ Object *Parser::getObj(Object *obj, error(getPos(), "Dictionary key must be a name object"); shift(); } else { + // this copyString is necessary if not the shift changes the value of key key = copyString(buf1.getName()); shift(); if (buf1.isEOF() || buf1.isError()) { @@ -82,6 +84,7 @@ Object *Parser::getObj(Object *obj, break; } obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); + gfree((void*)key); } } if (buf1.isEOF()) diff --git a/xpdf/xpdf/SecurityHandler.cc b/xpdf/xpdf/SecurityHandler.cc index 8825ce85e..31bd86718 100644 --- a/xpdf/xpdf/SecurityHandler.cc +++ b/xpdf/xpdf/SecurityHandler.cc @@ -25,6 +25,7 @@ #ifdef ENABLE_PLUGINS # include "XpdfPluginAPI.h" #endif +#include "UGString.h" #include "SecurityHandler.h" //------------------------------------------------------------------------ diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc index c4c6abfed..2435070ed 100644 --- a/xpdf/xpdf/Stream.cc +++ b/xpdf/xpdf/Stream.cc @@ -33,6 +33,7 @@ #include "JPXStream.h" #include "Stream-CCITT.h" #include "DCTStream.h" +#include "UGString.h" #ifdef __DJGPP__ static GBool setDJSYSFLAGS = gFalse; diff --git a/xpdf/xpdf/UGString.cc b/xpdf/xpdf/UGString.cc new file mode 100644 index 000000000..f99234eb4 --- /dev/null +++ b/xpdf/xpdf/UGString.cc @@ -0,0 +1,86 @@ +//======================================================================== +// +// UGString.cc +// +// Unicode string +// +// Copyright 2005 Albert Astals Cid +// +//======================================================================== + +#include + +#include "gmem.h" +#include "GString.h" +#include "PDFDocEncoding.h" +#include "UGString.h" + +UGString::UGString(Unicode *u, int l) +{ + s = u; + length = l; +} + +UGString::UGString(GString &str) +{ + if ((str.getChar(0) & 0xff) == 0xfe && (str.getChar(1) & 0xff) == 0xff) + { + length = (str.getLength() - 2) / 2; + s = (Unicode *)gmallocn(length, sizeof(Unicode)); + for (int j = 0; j < length; ++j) { + s[j] = ((str.getChar(2 + 2*j) & 0xff) << 8) | (str.getChar(3 + 2*j) & 0xff); + } + } else + initChar(str); +} + +UGString::UGString(const UGString &str) +{ + length = str.length; + s = (Unicode *)gmallocn(length, sizeof(Unicode)); + memcpy(s, str.s, length * sizeof(Unicode)); +} + +UGString::UGString(const char *str) +{ + GString aux(str); + initChar(aux); +} + +void UGString::initChar(GString &str) +{ + length = str.getLength(); + s = (Unicode *)gmallocn(length, sizeof(Unicode)); + for (int j = 0; j < length; ++j) { + s[j] = pdfDocEncoding[str.getChar(j) & 0xff]; + } +} + +UGString::~UGString() +{ + gfree(s); +} + +int UGString::cmp(UGString *str) const +{ + int n1, n2, i, x; + Unicode *p1, *p2; + + n1 = length; + n2 = str->length; + for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + return n1 - n2; +} + +const char *UGString::getCString() const +{ + char *res = new char[length + 1]; + for (int i = 0; i < length; i++) res[i] = s[i]; + res[length] = '\0'; + return res; +} diff --git a/xpdf/xpdf/UGString.h b/xpdf/xpdf/UGString.h new file mode 100644 index 000000000..9a03b65a2 --- /dev/null +++ b/xpdf/xpdf/UGString.h @@ -0,0 +1,55 @@ +//======================================================================== +// +// UGString.h +// +// Unicode string +// +// Copyright 2005 Albert Astals Cid +// +//======================================================================== + +#ifndef UGSTRING_H +#define UGSTRING_H + +#include "CharTypes.h" + +class GString; + +class UGString +{ +public: + // Create an unicode string + UGString(Unicode *u, int l); + + // Create a unicode string from . + UGString(GString &str); + + // Copy the unicode string + UGString(const UGString &str); + + // Create a unicode string from . + UGString(const char *str); + + // Destructor. + ~UGString(); + + // Get length. + int getLength() const { return length; } + + // Compare two strings: -1:< 0:= +1:> + int cmp(UGString *str) const; + + // get the unicode + Unicode *unicode() const { return s; } + + // get the const char* + const char *getCString() const; + +private: + void initChar(GString &str); + + int length; + Unicode *s; +}; + +#endif diff --git a/xpdf/xpdf/XRef.cc b/xpdf/xpdf/XRef.cc index 928931eb4..accbff3cc 100644 --- a/xpdf/xpdf/XRef.cc +++ b/xpdf/xpdf/XRef.cc @@ -24,6 +24,7 @@ #include "Dict.h" #include "Error.h" #include "ErrorCodes.h" +#include "UGString.h" #include "XRef.h" //------------------------------------------------------------------------ From 6a304a7925cd6fa90811d552ea416b60be025f12 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 10 Sep 2005 12:02:29 +0000 Subject: [PATCH 150/245] Do not launch the relayouting immediately but wait to return to the event loop as that relayouting interferes with observer loading svn path=/trunk/KDE/kdegraphics/kpdf/; revision=459218 --- ui/pageview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 982579965..6c57be5f8 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -273,7 +273,7 @@ void PageView::notifySetup( const QVector< KPDFPage * > & pageSet, bool document // Need slotRelayoutPages() here instead of d->dirtyLayout = true // because opening a pdf from another pdf will not trigger a viewportchange // so pages are never relayouted - slotRelayoutPages(); + QTimer::singleShot(0, this, SLOT(slotRelayoutPages())); else { // update the mouse cursor when closing because we may have close through a link and From 729ce7418e6b62abb936cca04016132ee1a6e3d7 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 10 Sep 2005 18:14:36 +0000 Subject: [PATCH 151/245] Fordwardport fix for bug 112332 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=459401 --- ui/minibar.cpp | 43 +++---------------------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/ui/minibar.cpp b/ui/minibar.cpp index 663ba97a9..d7d4feab7 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -69,12 +69,7 @@ class HoverButton : public QPushButton HoverButton( QWidget * parent ); protected: - void mouseMoveEvent( QMouseEvent * e ); - void mouseReleaseEvent( QMouseEvent * e ); void paintEvent( QPaintEvent * e ); - - private: - bool m_hovering; }; @@ -404,7 +399,7 @@ void PagesEdit::wheelEvent( QWheelEvent * e ) /** HoverButton **/ HoverButton::HoverButton( QWidget * parent ) - : QPushButton( parent ), m_hovering( false ) + : QPushButton( parent ) { setMouseTracking( true ); #if KDE_IS_VERSION(3,3,90) @@ -412,48 +407,16 @@ HoverButton::HoverButton( QWidget * parent ) #endif } -void HoverButton::mouseMoveEvent( QMouseEvent * e ) -{ - // check for mouse hovering - const QRect myGeom( 0,0, width(), height() ); - bool hover = myGeom.contains( e->pos() ); - - // if hover state changed update gfx - if ( m_hovering != hover ) - { - m_hovering = hover; - update(); - } -} - -void HoverButton::mouseReleaseEvent( QMouseEvent * e ) -{ - // call default handler - QPushButton::mouseReleaseEvent( e ); - - // reset hover state when clicking - m_hovering = false; - update(); -} - void HoverButton::paintEvent( QPaintEvent * e ) { - // always not hovering in disabled state - if ( !isEnabled() ) - m_hovering = false; - - // paint button in different flavours - if ( m_hovering ) + if ( hasMouse() ) { - // if we're hovering the button, draw it using QPushButton style - setPaletteBackgroundColor( palette().active().button() ); QPushButton::paintEvent( e ); } else { - // custom drawing of unhovered button QPainter p( this ); - setPaletteBackgroundColor( palette().active().background() ); + p.fillRect(e->rect(), parentWidget() ? parentWidget()->palette().brush(QPalette::Active, QColorGroup::Background) : paletteBackgroundColor()); #warning drawButtonLabel does not exists in Qt4 // drawButtonLabel( &p ); } From ef18caf0169973770f70cc20c9564c9d0149ad59 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 10 Sep 2005 18:17:56 +0000 Subject: [PATCH 152/245] Qt4 build fix svn path=/trunk/KDE/kdegraphics/kpdf/; revision=459402 --- ui/minibar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/minibar.cpp b/ui/minibar.cpp index d7d4feab7..21417dc48 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -416,7 +416,7 @@ void HoverButton::paintEvent( QPaintEvent * e ) else { QPainter p( this ); - p.fillRect(e->rect(), parentWidget() ? parentWidget()->palette().brush(QPalette::Active, QColorGroup::Background) : paletteBackgroundColor()); + p.fillRect(e->rect(), parentWidget() ? parentWidget()->palette().brush(QPalette::Active, QColorGroup::Background) : QBrush(paletteBackgroundColor())); #warning drawButtonLabel does not exists in Qt4 // drawButtonLabel( &p ); } From fb499e8567ecfd8ab10ddcd098adfe5d1261c47b Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Sun, 11 Sep 2005 13:11:42 +0000 Subject: [PATCH 153/245] Adapt to new api Remove kde_version svn path=/trunk/KDE/kdegraphics/kpdf/; revision=459570 --- part.cpp | 2 -- ui/minibar.cpp | 2 -- ui/pageview.cpp | 2 -- 3 files changed, 6 deletions(-) diff --git a/part.cpp b/part.cpp index c66a9cb1f..357025875 100644 --- a/part.cpp +++ b/part.cpp @@ -637,11 +637,9 @@ void Part::slotFind() { KFindDialog dlg( widget() ); dlg.setHasCursor( false ); -#if KDE_IS_VERSION(3,3,90) dlg.setSupportsBackwardsFind( false ); dlg.setSupportsWholeWordsFind( false ); dlg.setSupportsRegularExpressionFind( false ); -#endif if ( dlg.exec() == QDialog::Accepted ) { m_searchStarted = true; diff --git a/ui/minibar.cpp b/ui/minibar.cpp index 21417dc48..8da2623a4 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -402,9 +402,7 @@ HoverButton::HoverButton( QWidget * parent ) : QPushButton( parent ) { setMouseTracking( true ); -#if KDE_IS_VERSION(3,3,90) KAcceleratorManager::setNoAccel( this ); -#endif } void HoverButton::paintEvent( QPaintEvent * e ) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 6c57be5f8..52b8dfa2a 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -180,9 +180,7 @@ void PageView::setupActions( KActionCollection * ac ) // Zoom actions ( higher scales takes lots of memory! ) d->aZoom = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, this, SLOT( slotZoom() ), ac, "zoom_to" ); d->aZoom->setEditable( true ); -#if KDE_IS_VERSION(3,4,89) d->aZoom->setMaxComboViewCount( 13 ); -#endif updateZoomText(); KStdAction::zoomIn( this, SLOT( slotZoomIn() ), ac, "zoom_in" ); From 9ae8acd6ef6766fa6cffa8704e59617383563e80 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 11 Sep 2005 20:24:53 +0000 Subject: [PATCH 154/245] Ensure the button is updated on enter/leave events, as some styles may not do that. svn path=/trunk/KDE/kdegraphics/kpdf/; revision=459781 --- ui/minibar.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ui/minibar.cpp b/ui/minibar.cpp index 8da2623a4..c7c51cd90 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -70,6 +70,8 @@ class HoverButton : public QPushButton protected: void paintEvent( QPaintEvent * e ); + void enterEvent( QPaintEvent * e ); + void leaveEvent( QPaintEvent * e ); }; @@ -405,6 +407,18 @@ HoverButton::HoverButton( QWidget * parent ) KAcceleratorManager::setNoAccel( this ); } +void HoverButton::enterEvent( QPaintEvent * e ) +{ + update(); + QPushButton::enterEvent( e ); +} + +void HoverButton::leaveEvent( QPaintEvent * e ) +{ + update(); + QPushButton::leaveEvent( e ); +} + void HoverButton::paintEvent( QPaintEvent * e ) { if ( hasMouse() ) From f292dd1abd7467ffdc735d4b906ce88d14d3ea8a Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 16 Sep 2005 11:14:55 +0000 Subject: [PATCH 155/245] fordwardport fix for bug 112271 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=461062 --- part.cpp | 12 ++++++++++++ part.h | 1 + 2 files changed, 13 insertions(+) diff --git a/part.cpp b/part.cpp index 357025875..c9dd740f2 100644 --- a/part.cpp +++ b/part.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -85,6 +86,9 @@ Part::Part(QWidget *parentWidget, const char *widgetName, : DCOPObject("kpdf"), KParts::ReadOnlyPart(parent, name), m_showMenuBarAction(0), m_showFullScreenAction(0), m_actionsSearched(false), m_searchStarted(false) { + // connect the started signal to tell the job the mimetypes we like + connect(this, SIGNAL(started(KIO::Job *)), this, SLOT(setMimeTypes(KIO::Job *))); + // load catalog for translation KGlobal::locale()->insertCatalogue("kpdf"); @@ -442,6 +446,14 @@ bool Part::openURL(const KURL &url) return b; } +void Part::setMimeTypes(KIO::Job *job) +{ + if (job) + { + job->addMetaData("accept", "application/pdf, */*;q=0.5"); + } +} + bool Part::closeURL() { if (!m_temporaryLocalFile.isNull()) diff --git a/part.h b/part.h index c81a9a989..9e2f8bf60 100644 --- a/part.h +++ b/part.h @@ -114,6 +114,7 @@ protected slots: void enableTOC(bool enable); void psTransformEnded(); void cannotQuit(); + void setMimeTypes(KIO::Job *job); public slots: // connected to Shell action (and browserExtension), not local one From 0f5a9a7a348d8f5312ff32362f367a7b8be30e24 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 16 Sep 2005 20:30:15 +0000 Subject: [PATCH 156/245] add guards to check the document is opened because that slots can not be called from the ui when there's no document, but they can be called by dcop svn path=/trunk/KDE/kdegraphics/kpdf/; revision=461203 --- part.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/part.cpp b/part.cpp index c9dd740f2..8ee318da2 100644 --- a/part.cpp +++ b/part.cpp @@ -615,24 +615,26 @@ void Part::slotGoToPage() void Part::slotPreviousPage() { - if ( !m_document->currentPage() < 1 ) + if ( m_document->isOpened() && !m_document->currentPage() < 1 ) m_document->setViewportPage( m_document->currentPage() - 1 ); } void Part::slotNextPage() { - if ( m_document->currentPage() < (m_document->pages() - 1) ) + if ( m_document->isOpened() && m_document->currentPage() < (m_document->pages() - 1) ) m_document->setViewportPage( m_document->currentPage() + 1 ); } void Part::slotGotoFirst() { - m_document->setViewportPage( 0 ); + if ( m_document->isOpened() ) + m_document->setViewportPage( 0 ); } void Part::slotGotoLast() { - m_document->setViewportPage( m_document->pages() - 1 ); + if ( m_document->isOpened() ) + m_document->setViewportPage( m_document->pages() - 1 ); } void Part::slotHistoryBack() From 40237914b648ccbb4a6365e811129660df2de5dc Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 18 Sep 2005 21:50:39 +0000 Subject: [PATCH 157/245] Don't crash on documents with toc links that point to unexistant pages svn path=/trunk/KDE/kdegraphics/kpdf/; revision=461853 --- core/generator_pdf/generator_pdf.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 8c63ed0d8..a1b50a02b 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -832,6 +832,8 @@ void PDFGenerator::fillViewportFromLink( DocumentViewport &viewport, LinkDest *d viewport.pageNumber = pdfdoc->findPage( ref.num, ref.gen ) - 1; } + if (viewport.pageNumber == -1) return; + // get destination position // TODO add other attributes to the viewport (taken from link) // switch ( destination->getKind() ) From d459f627fc9add2e3c5ddb47a5d24bf488885002 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 29 Sep 2005 19:51:53 +0000 Subject: [PATCH 158/245] fix for bug 109764 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=465441 --- part.cpp | 14 +++++++++----- part.h | 1 + ui/pageview.cpp | 4 ++++ ui/thumbnaillist.cpp | 1 + 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/part.cpp b/part.cpp index 8ee318da2..9024c6ec0 100644 --- a/part.cpp +++ b/part.cpp @@ -271,6 +271,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, splitterSizes.push_back( 500 ); } m_splitter->setSizes( splitterSizes ); + connect(m_splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(saveSplitterSize())); m_watcher = new KDirWatch( this ); connect( m_watcher, SIGNAL( dirty( const QString& ) ), this, SLOT( slotFileDirty( const QString& ) ) ); m_dirtyHandler = new QTimer( this ); @@ -281,6 +282,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, // [SPEECH] check for KTTSD presence and usability KTrader::OfferList offers = KTrader::self()->query("DCOP/Text-to-Speech", "Name == 'KTTSD'"); KpdfSettings::setUseKTTSD( (offers.count() > 0) ); + KpdfSettings::writeConfig(); // set our XML-UI resource file setXMLFile("part.rc"); @@ -289,11 +291,6 @@ Part::Part(QWidget *parentWidget, const char *widgetName, Part::~Part() { - // save internal settings - KpdfSettings::setSplitterSizes( m_splitter->sizes() ); - // write to disk config file - KpdfSettings::writeConfig(); - delete m_document; if ( --m_count == 0 ) delete globalParams; @@ -483,6 +480,7 @@ void Part::slotShowLeftPanel() { bool showLeft = m_showLeftPanel->isChecked(); KpdfSettings::setShowLeftPanel(showLeft); + KpdfSettings::writeConfig(); // show/hide left qtoolbox m_leftPanel->setShown( showLeft ); // this needs to be hidden explicitly to disable thumbnails gen @@ -576,6 +574,12 @@ void Part::cannotQuit() KMessageBox::information(widget(), i18n("This link points to a quit application action that does not work when using the embedded viewer."), QString::null, "warnNoQuitIfNotInKPDF"); } +void Part::saveSplitterSize() +{ + KpdfSettings::setSplitterSizes( m_splitter->sizes() ); + KpdfSettings::writeConfig(); +} + //BEGIN go to page dialog class KPDFGotoPageDialog : public KDialogBase { diff --git a/part.h b/part.h index 9e2f8bf60..b203def2b 100644 --- a/part.h +++ b/part.h @@ -114,6 +114,7 @@ protected slots: void enableTOC(bool enable); void psTransformEnded(); void cannotQuit(); + void saveSplitterSize(); void setMimeTypes(KIO::Job *job); public slots: diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 52b8dfa2a..da53efc89 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -1098,6 +1098,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) { d->messageWindow->display( i18n("Starting KTTSD Failed: %1").arg(error) ); KpdfSettings::setUseKTTSD(false); + KpdfSettings::writeConfig(); } } if ( KpdfSettings::useKTTSD() ) @@ -1450,6 +1451,7 @@ void PageView::updateZoom( ZoomMode newZoomMode ) // save selected zoom factor KpdfSettings::setZoomMode(newZoomMode); KpdfSettings::setZoomFactor(newFactor); + KpdfSettings::writeConfig(); } } @@ -1919,6 +1921,7 @@ void PageView::slotTwoPagesToggled( bool on ) if ( KpdfSettings::viewColumns() != newColumns ) { KpdfSettings::setViewColumns( newColumns ); + KpdfSettings::writeConfig(); if ( d->document->pages() > 0 ) slotRelayoutPages(); } @@ -1929,6 +1932,7 @@ void PageView::slotContinuousToggled( bool on ) if ( KpdfSettings::viewContinuous() != on ) { KpdfSettings::setViewContinuous( on ); + KpdfSettings::writeConfig(); if ( d->document->pages() > 0 ) slotRelayoutPages(); } diff --git a/ui/thumbnaillist.cpp b/ui/thumbnaillist.cpp index 6d14754c2..06b17fb88 100644 --- a/ui/thumbnaillist.cpp +++ b/ui/thumbnaillist.cpp @@ -248,6 +248,7 @@ void ThumbnailList::slotFilterBookmarks( bool filterOn ) { // save state KpdfSettings::setFilterBookmarks( filterOn ); + KpdfSettings::writeConfig(); // ask for the 'notifySetup' with a little trick (on reinsertion the // document sends the list again) m_document->removeObserver( this ); From e56c246b9a49aea08852e54712e3eea5038fc9e8 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 3 Oct 2005 18:14:31 +0000 Subject: [PATCH 159/245] Fordward port fix for bug 113771 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=466935 --- xpdf/xpdf/GlobalParams.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index 4b1af8955..371173e71 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -113,8 +113,10 @@ static const char *displayFontDirs[] = { #else static const char *displayFontDirs[] = { "/usr/share/ghostscript/fonts", + "/usr/pkg/share/ghostscript/fonts", "/usr/local/share/ghostscript/fonts", "/usr/share/fonts/default/Type1", + "/usr/X11R6/lib/X11/fonts/Type1", "/usr/share/fonts/default/ghostscript", "/usr/share/fonts/type1/gsfonts", NULL From a613ed772f610e7746c0b2c829ad5e5f82857cfb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 3 Oct 2005 22:09:30 +0000 Subject: [PATCH 160/245] Some porting to new kdelibs snapshot svn path=/trunk/KDE/kdegraphics/kpdf/; revision=466997 --- conf/dlggeneral.ui.h | 4 ++-- core/document.cpp | 5 +++-- core/generator_pdf/generator_pdf.cpp | 4 ++-- ui/pageview.cpp | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/conf/dlggeneral.ui.h b/conf/dlggeneral.ui.h index 8eafde39c..1b5095b75 100644 --- a/conf/dlggeneral.ui.h +++ b/conf/dlggeneral.ui.h @@ -10,7 +10,7 @@ ** destructor. *****************************************************************************/ -#include +#include #include @@ -19,7 +19,7 @@ void DlgGeneral::showEvent( QShowEvent * ) #if KPDF_FORCE_DRM kcfg_ObeyDRM->hide(); #else - if (kapp->authorize("skip_drm")) kcfg_ObeyDRM->show(); + if (KAuthorized::authorize("skip_drm")) kcfg_ObeyDRM->show(); else kcfg_ObeyDRM->hide(); #endif } diff --git a/core/document.cpp b/core/document.cpp index 6bf547558..e4588e43e 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -9,6 +9,7 @@ ***************************************************************************/ // qt/kde/system includes +#include #include #include #include @@ -23,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -1048,7 +1049,7 @@ void KPDFDocument::processLink( const KPDFLink * link ) const KPDFLinkBrowse * browse = static_cast< const KPDFLinkBrowse * >( link ); // if the url is a mailto one, invoke mailer if ( browse->url().startsWith( "mailto:", false ) ) - kapp->invokeMailer( browse->url() ); + KToolInvocation::invokeMailer( browse->url() ); else { QString url = browse->url(); diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index a1b50a02b..87abd5bc7 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -257,7 +257,7 @@ const DocumentSynopsis * PDFGenerator::generateDocumentSynopsis() bool PDFGenerator::isAllowed( int permissions ) { #if !KPDF_FORCE_DRM - if (kapp->authorize("skip_drm") && !KpdfSettings::obeyDRM()) return true; + if (KAuthorized::authorize("skip_drm") && !KpdfSettings::obeyDRM()) return true; #endif bool b = true; diff --git a/ui/pageview.cpp b/ui/pageview.cpp index da53efc89..8fbe13cd7 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include // system includes @@ -1094,7 +1094,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) if (!client->isApplicationRegistered("kttsd")) { QString error; - if (KApplication::startServiceByDesktopName("kttsd", QStringList(), &error)) + if (KToolInvocation::startServiceByDesktopName("kttsd", QStringList(), &error)) { d->messageWindow->display( i18n("Starting KTTSD Failed: %1").arg(error) ); KpdfSettings::setUseKTTSD(false); From c26bc60c3090e3d75427729faf15941a1244d801 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 4 Oct 2005 18:33:43 +0000 Subject: [PATCH 161/245] build svn path=/trunk/KDE/kdegraphics/kpdf/; revision=467254 --- part.cpp | 21 +++++++++++---------- part.h | 2 +- ui/minibar.cpp | 2 +- ui/pageview.cpp | 15 +++++++-------- ui/searchwidget.cpp | 4 ++-- ui/searchwidget.h | 3 +-- ui/thumbnaillist.cpp | 6 ++---- 7 files changed, 25 insertions(+), 28 deletions(-) diff --git a/part.cpp b/part.cpp index 9024c6ec0..b81d79e91 100644 --- a/part.cpp +++ b/part.cpp @@ -22,6 +22,7 @@ ***************************************************************************/ // qt/kde includes +#include #include #include #include @@ -39,15 +40,14 @@ #include #include #include -#include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -83,14 +83,14 @@ unsigned int Part::m_count = 0; Part::Part(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const QStringList & /*args*/ ) - : DCOPObject("kpdf"), KParts::ReadOnlyPart(parent, name), m_showMenuBarAction(0), m_showFullScreenAction(0), + : DCOPObject("kpdf"), KParts::ReadOnlyPart(parent), m_showMenuBarAction(0), m_showFullScreenAction(0), m_actionsSearched(false), m_searchStarted(false) { // connect the started signal to tell the job the mimetypes we like connect(this, SIGNAL(started(KIO::Job *)), this, SLOT(setMimeTypes(KIO::Job *))); // load catalog for translation - KGlobal::locale()->insertCatalogue("kpdf"); + KGlobal::locale()->insertCatalog("kpdf"); // create browser extension (for printing when embedded into browser) m_bExtension = new BrowserExtension(this); @@ -662,7 +662,7 @@ void Part::slotFind() { m_searchStarted = true; m_document->resetSearch( PART_SEARCH_ID ); - m_document->searchText( PART_SEARCH_ID, dlg.pattern(), false, dlg.options() & KFindDialog::CaseSensitive, + m_document->searchText( PART_SEARCH_ID, dlg.pattern(), false, dlg.options() & KFind::CaseSensitive, KPDFDocument::NextMatch, true, qRgb( 255, 255, 64 ) ); } } @@ -682,7 +682,7 @@ void Part::slotSaveFileAs() { if ( KIO::NetAccess::exists( saveURL, false, widget() ) ) { - if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.filename(), QString::null, i18n("Overwrite"))) != KMessageBox::Continue) + if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.fileName(), QString::null, i18n("Overwrite"))) != KMessageBox::Continue) return; } @@ -808,10 +808,10 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) } - KPopupMenu *popup = new KPopupMenu( widget(), "rmb popup" ); + Q3PopupMenu *popup = new Q3PopupMenu( widget() ); if (page) { - popup->insertTitle( i18n( "Page %1" ).arg( page->number() + 1 ) ); + popup->setTitle( i18n( "Page %1" ).arg( page->number() + 1 ) ); if ( page->hasBookmark() ) popup->insertItem( QIcon(SmallIcon("bookmark")), i18n("Remove Bookmark"), 1 ); else @@ -832,7 +832,8 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) if ((m_showMenuBarAction && !m_showMenuBarAction->isChecked()) || (m_showFullScreenAction && m_showFullScreenAction->isChecked())) { - popup->insertTitle( i18n( "Tools" ) ); +#warning this is not going to work KPopupMenu supported multiple titles and now it's gone :-/ + popup->setTitle( i18n( "Tools" ) ); if (m_showMenuBarAction && !m_showMenuBarAction->isChecked()) m_showMenuBarAction->plug(popup); if (m_showFullScreenAction && m_showFullScreenAction->isChecked()) m_showFullScreenAction->plug(popup); reallyShow = true; @@ -936,7 +937,7 @@ void Part::saveDocumentRestoreInfo(KConfig* config) * BrowserExtension class */ BrowserExtension::BrowserExtension(Part* parent) - : KParts::BrowserExtension( parent, "KPDF::BrowserExtension" ) + : KParts::BrowserExtension( parent ) { emit enableAction("print", true); setURLDropHandlingEnabled(true); diff --git a/part.h b/part.h index b203def2b..e23ef9491 100644 --- a/part.h +++ b/part.h @@ -61,7 +61,7 @@ Q_OBJECT public: // Default constructor Part(QWidget* parentWidget, const char* widgetName, - QObject* parent, const char* name, const QStringList& args); + QObject* parent, const char *name, const QStringList& args); // Destructor ~Part(); diff --git a/ui/minibar.cpp b/ui/minibar.cpp index c7c51cd90..3cdf165d5 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include // local includes diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 8fbe13cd7..7568b22a5 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -19,6 +19,7 @@ // qt/kde includes #include #include +#include #include #include #include @@ -27,11 +28,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -1023,17 +1022,18 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) } // popup that ask to copy:text and copy/save:image - KPopupMenu menu( this ); + Q3PopupMenu menu( this ); if ( !selectedText.isEmpty() ) { - menu.insertTitle( i18n( "Text (1 character)", "Text (%n characters)", selectedText.length() ) ); + menu.setTitle( i18n( "Text (1 character)", "Text (%n characters)", selectedText.length() ) ); menu.insertItem( QIcon(SmallIcon("editcopy")), i18n( "Copy to Clipboard" ), 1 ); if ( !d->document->isAllowed( KPDFDocument::AllowCopy ) ) menu.setItemEnabled( 1, false ); if ( KpdfSettings::useKTTSD() ) menu.insertItem( QIcon(SmallIcon("kttsd")), i18n( "Speak Text" ), 2 ); } - menu.insertTitle( i18n( "Image (%1 by %2 pixels)" ).arg( selectionRect.width() ).arg( selectionRect.height() ) ); +#warning this is not going to work KPopupMenu supported multiple titles and now it's gone :-/ + menu.setTitle( i18n( "Image (%1 by %2 pixels)" ).arg( selectionRect.width() ).arg( selectionRect.height() ) ); menu.insertItem( QIcon(SmallIcon("image")), i18n( "Copy to Clipboard" ), 3 ); menu.insertItem( QIcon(SmallIcon("filesave")), i18n( "Save to File..." ), 4 ); int choice = menu.exec( e->globalPos() ); @@ -1201,9 +1201,8 @@ void PageView::dragEnterEvent( QDragEnterEvent * ev ) void PageView::dropEvent( QDropEvent * ev ) { - KURL::List lst; - if ( KURLDrag::decode( ev, lst ) ) - emit urlDropped( lst.first() ); + if ( KURL::List::canDecode( ev->mimeData() ) ) + emit urlDropped( KURL::List::fromMimeData( ev->mimeData() ).first() ); } //END widget events diff --git a/ui/searchwidget.cpp b/ui/searchwidget.cpp index 90ebcd990..0870f6b42 100644 --- a/ui/searchwidget.cpp +++ b/ui/searchwidget.cpp @@ -8,6 +8,7 @@ ***************************************************************************/ // qt/kde includes +#include #include #include #include @@ -16,7 +17,6 @@ #include #include #include -#include #include // local includes @@ -55,7 +55,7 @@ SearchWidget::SearchWidget( QWidget * parent, KPDFDocument * document ) i18n( "Clear filter" ), 0/*index*/ ); // 3.1. create the popup menu for changing filtering features - m_menu = new KPopupMenu( this ); + m_menu = new QMenu( this ); m_menu->insertItem( i18n("Case Sensitive"), 1 ); m_menu->insertSeparator( 2 ); m_menu->insertItem( i18n("Match Phrase"), 3 ); diff --git a/ui/searchwidget.h b/ui/searchwidget.h index 9f2a1e443..a6ca076c4 100644 --- a/ui/searchwidget.h +++ b/ui/searchwidget.h @@ -12,7 +12,6 @@ #include -class KPopupMenu; class KPDFDocument; class m_inputDelayTimer; @@ -36,7 +35,7 @@ class SearchWidget : public KToolBar private: KPDFDocument * m_document; - KPopupMenu * m_menu; + QMenu * m_menu; QTimer * m_inputDelayTimer; int m_searchType; bool m_caseSensitive; diff --git a/ui/thumbnaillist.cpp b/ui/thumbnaillist.cpp index 06b17fb88..d313770ed 100644 --- a/ui/thumbnaillist.cpp +++ b/ui/thumbnaillist.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -367,9 +366,8 @@ void ThumbnailList::dragEnterEvent( QDragEnterEvent * ev ) void ThumbnailList::dropEvent( QDropEvent * ev ) { - KURL::List lst; - if ( KURLDrag::decode( ev, lst ) ) - emit urlDropped( lst.first() ); + if ( KURL::List::canDecode( ev->mimeData() ) ) + emit urlDropped( KURL::List::fromMimeData( ev->mimeData() ).first() ); } //END widget events From 5ca7b205d8a7593e70d82bdc125af47abeca89a5 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 4 Oct 2005 18:53:13 +0000 Subject: [PATCH 162/245] Q3PopupMenu -> KMenu svn path=/trunk/KDE/kdegraphics/kpdf/; revision=467259 --- part.cpp | 34 ++++++++++++++-------------------- ui/pageview.cpp | 30 +++++++++++++++--------------- 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/part.cpp b/part.cpp index b81d79e91..b861974aa 100644 --- a/part.cpp +++ b/part.cpp @@ -22,7 +22,6 @@ ***************************************************************************/ // qt/kde includes -#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -808,16 +808,19 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) } - Q3PopupMenu *popup = new Q3PopupMenu( widget() ); + KMenu *popup = new KMenu( widget() ); + QAction *toggleBookmark, *fitPageWidth; + toggleBookmark = 0; + fitPageWidth = 0; if (page) { - popup->setTitle( i18n( "Page %1" ).arg( page->number() + 1 ) ); - if ( page->hasBookmark() ) - popup->insertItem( QIcon(SmallIcon("bookmark")), i18n("Remove Bookmark"), 1 ); + popup->addTitle( i18n( "Page %1" ).arg( page->number() + 1 ) ); + if ( page->hasBookmark() ) + toggleBookmark = popup->addAction( QIcon(SmallIcon("bookmark")), i18n("Remove Bookmark") ); else - popup->insertItem( QIcon(SmallIcon("bookmark_add")), i18n("Add Bookmark"), 1 ); + toggleBookmark = popup->addAction( QIcon(SmallIcon("bookmark_add")), i18n("Add Bookmark") ); if ( m_pageView->canFitPageWidth() ) - popup->insertItem( QIcon(SmallIcon("viewmagfit")), i18n("Fit Width"), 2 ); + fitPageWidth = popup->addAction( QIcon(SmallIcon("viewmagfit")), i18n("Fit Width") ); //popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 ); //popup->setItemEnabled( 3, false ); reallyShow = true; @@ -832,8 +835,7 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) if ((m_showMenuBarAction && !m_showMenuBarAction->isChecked()) || (m_showFullScreenAction && m_showFullScreenAction->isChecked())) { -#warning this is not going to work KPopupMenu supported multiple titles and now it's gone :-/ - popup->setTitle( i18n( "Tools" ) ); + popup->addTitle( i18n( "Tools" ) ); if (m_showMenuBarAction && !m_showMenuBarAction->isChecked()) m_showMenuBarAction->plug(popup); if (m_showFullScreenAction && m_showFullScreenAction->isChecked()) m_showFullScreenAction->plug(popup); reallyShow = true; @@ -842,17 +844,9 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) if (reallyShow) { - switch ( popup->exec(point) ) - { - case 1: - m_document->toggleBookmark( page->number() ); - break; - case 2: - m_pageView->fitPageWidth( page->number() ); - break; - // case 3: // switch to edit mode - // break; - } + QAction *res = popup->exec(point); + if (res == toggleBookmark) m_document->toggleBookmark( page->number() ); + else if (res == fitPageWidth) m_pageView->fitPageWidth( page->number() ); } delete popup; } diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 7568b22a5..440b669e4 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -19,7 +19,6 @@ // qt/kde includes #include #include -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1022,23 +1022,23 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) } // popup that ask to copy:text and copy/save:image - Q3PopupMenu menu( this ); + KMenu menu( this ); + QAction *textToClipboard = 0, *speakText = 0, *imageToClipboard = 0, *imageToFile = 0; if ( !selectedText.isEmpty() ) { - menu.setTitle( i18n( "Text (1 character)", "Text (%n characters)", selectedText.length() ) ); - menu.insertItem( QIcon(SmallIcon("editcopy")), i18n( "Copy to Clipboard" ), 1 ); + menu.addTitle( i18n( "Text (1 character)", "Text (%n characters)", selectedText.length() ) ); + textToClipboard = menu.addAction( QIcon(SmallIcon("editcopy")), i18n( "Copy to Clipboard" ) ); if ( !d->document->isAllowed( KPDFDocument::AllowCopy ) ) menu.setItemEnabled( 1, false ); if ( KpdfSettings::useKTTSD() ) - menu.insertItem( QIcon(SmallIcon("kttsd")), i18n( "Speak Text" ), 2 ); + speakText = menu.addAction( QIcon(SmallIcon("kttsd")), i18n( "Speak Text" ) ); } -#warning this is not going to work KPopupMenu supported multiple titles and now it's gone :-/ - menu.setTitle( i18n( "Image (%1 by %2 pixels)" ).arg( selectionRect.width() ).arg( selectionRect.height() ) ); - menu.insertItem( QIcon(SmallIcon("image")), i18n( "Copy to Clipboard" ), 3 ); - menu.insertItem( QIcon(SmallIcon("filesave")), i18n( "Save to File..." ), 4 ); - int choice = menu.exec( e->globalPos() ); + menu.addTitle( i18n( "Image (%1 by %2 pixels)" ).arg( selectionRect.width() ).arg( selectionRect.height() ) ); + imageToClipboard = menu.addAction( QIcon(SmallIcon("image")), i18n( "Copy to Clipboard" ) ); + imageToFile = menu.addAction( QIcon(SmallIcon("filesave")), i18n( "Save to File..." ) ); + QAction *choice = menu.exec( e->globalPos() ); // IMAGE operation choosen - if ( choice > 2 ) + if ( choice == imageToClipboard || choice == imageToFile ) { // renders page into a pixmap QPixmap copyPix( selectionRect.width(), selectionRect.height() ); @@ -1046,7 +1046,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) copyPainter.translate( -selectionRect.left(), -selectionRect.top() ); paintItems( ©Painter, selectionRect ); - if ( choice == 3 ) + if ( choice == imageToClipboard ) { // [2] copy pixmap to clipboard QClipboard *cb = QApplication::clipboard(); @@ -1055,7 +1055,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) cb->setPixmap( copyPix, QClipboard::Selection ); d->messageWindow->display( i18n( "Image [%1x%2] copied to clipboard." ).arg( copyPix.width() ).arg( copyPix.height() ) ); } - else if ( choice == 4 ) + else if ( choice == imageToFile ) { // [3] save pixmap to file QString fileName = KFileDialog::getSaveFileName( QString::null, "image/png image/jpeg", this ); @@ -1074,7 +1074,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) // TEXT operation choosen else { - if ( choice == 1 ) + if ( choice == textToClipboard ) { // [1] copy text to clipboard QClipboard *cb = QApplication::clipboard(); @@ -1082,7 +1082,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) if ( cb->supportsSelection() ) cb->setText( selectedText, QClipboard::Selection ); } - else if ( choice == 2 ) + else if ( choice == speakText ) { // [2] speech selection using KTTSD DCOPClient * client = DCOPClient::mainClient(); From 6069ce7720f580bcada8d523a6ab8855f11d35b6 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Wed, 5 Oct 2005 12:09:02 +0000 Subject: [PATCH 163/245] Launch my script svn path=/trunk/KDE/kdegraphics/kpdf/; revision=467474 --- ui/presentationwidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index 82e577afc..b09ded027 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -28,6 +28,7 @@ // system includes #include #include +#include // local includes #include "presentationwidget.h" @@ -862,7 +863,7 @@ const KPDFPageTransition PresentationWidget::defaultTransition( int type ) const } case KpdfSettings::EnumSlidesTransition::Random: { - return defaultTransition( KApplication::random() % 18 ); + return defaultTransition( KRandom::random() % 18 ); break; } case KpdfSettings::EnumSlidesTransition::SplitHorizontalIn: From 09526f6bb2f11ba43e5ac042f7e55d0525293ef5 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 13 Oct 2005 19:22:12 +0000 Subject: [PATCH 164/245] don't use freetype internals svn path=/trunk/KDE/kdegraphics/kpdf/; revision=470329 --- xpdf/splash/SplashFTFont.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xpdf/splash/SplashFTFont.cc b/xpdf/splash/SplashFTFont.cc index 95ff56562..65c9dd9f3 100644 --- a/xpdf/splash/SplashFTFont.cc +++ b/xpdf/splash/SplashFTFont.cc @@ -14,7 +14,8 @@ #include #include FT_OUTLINE_H -#include FT_INTERNAL_OBJECTS_H // needed for FT_New_Size decl +#include FT_SIZES_H +#include FT_GLYPH_H #include "gmem.h" #include "SplashMath.h" #include "SplashGlyphBitmap.h" From ce086b803081d5181ea444363b8537c998c76edb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sat, 22 Oct 2005 22:04:15 +0000 Subject: [PATCH 165/245] Fordwardport r473205 change Force loading of hardcoded font substitutions svn path=/trunk/KDE/kdegraphics/kpdf/; revision=473206 --- xpdf/xpdf/GlobalParams.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc index 371173e71..12e81e7a5 100644 --- a/xpdf/xpdf/GlobalParams.cc +++ b/xpdf/xpdf/GlobalParams.cc @@ -1142,10 +1142,6 @@ void GlobalParams::setupBaseFonts(char *dir) { #endif for (i = 0; displayFontTab[i].name; ++i) { fontName = new GString(displayFontTab[i].name); - if (getDisplayFont(fontName)) { - delete fontName; - continue; - } fileName = NULL; kind = displayFontT1; // make gcc happy if (dir) { From 6e1fec918528856ab545e86d43480f4a8a410f59 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 24 Oct 2005 21:54:50 +0000 Subject: [PATCH 166/245] Remove HAVE_FREETYPE_217_OR_OLDER as that is detected on runtime now, add a note to warn all that freetype < 2.1.10 users that a upgrade to 2.1.10 can help kpdf svn path=/trunk/KDE/kdegraphics/kpdf/; revision=473888 --- configure.in.bot | 10 ++++++++++ configure.in.in | 11 +++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/configure.in.bot b/configure.in.bot index 48cf5b52d..43342e132 100644 --- a/configure.in.bot +++ b/configure.in.bot @@ -5,6 +5,15 @@ if test -z "$FREETYPE_CONFIG"; then echo "" fi +if test x$FREETYPE_VERSION != x; then + if test $FREETYPE_VERSION -lt 9008003; then + echo "" + echo "You're are using freetype older than 2.1.10, it is not mandatory" + echo "to use 2.1.10 but kpdf improves its rendering in some pdf with it" + echo "" + fi +fi + if test -z "$XFT_LIBS"; then echo "" echo "You're missing XFT development libs." @@ -18,3 +27,4 @@ if test "$HAVE_LIBJPEG" = "no"; then echo "KPDF will not be build without them" echo "" fi + diff --git a/configure.in.in b/configure.in.in index 25bc3436e..54827f102 100644 --- a/configure.in.in +++ b/configure.in.in @@ -7,8 +7,8 @@ KDE_FIND_PATH(freetype-config, FREETYPE_CONFIG, [${prefix}/bin ${exec_prefix}/bi ]) if test -n "$FREETYPE_CONFIG"; then - vers=`$FREETYPE_CONFIG --version 2>/dev/null | sed -e 's/libfreetype //' | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` - if test -n "$vers" && test "$vers" -ge 9000000; then + FREETYPE_VERSION=`$FREETYPE_CONFIG --version 2>/dev/null | sed -e 's/libfreetype //' | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` + if test -n "$FREETYPE_VERSION" && test "$FREETYPE_VERSION" -ge 9000000; then LIBFREETYPE_LIBS="`$FREETYPE_CONFIG --libs`" LIBFREETYPE_RPATH= for args in $LIBFREETYPE_LIBS; do @@ -19,12 +19,6 @@ if test -n "$FREETYPE_CONFIG"; then LIBFREETYPE_RPATH=`echo $LIBFREETYPE_RPATH | sed -e "s/-L/-R/g"` LIBFREETYPE_CFLAGS="`$FREETYPE_CONFIG --cflags`" AC_DEFINE_UNQUOTED(HAVE_FREETYPE, 1, [Defines if your system has the freetype library]) - if test -n "$vers" && test "$vers" -le 9005003; then - AC_DEFINE_UNQUOTED(HAVE_FREETYPE_217_OR_OLDER, 1, [Defines if your system has the freetype library 2.1.7 or older]) - else - AC_DEFINE_UNQUOTED(HAVE_FREETYPE_217_OR_OLDER, 0, [Defines if your system has the freetype library 2.1.7 or older]) - fi - else AC_MSG_WARN([You need at least libfreetype 2.0.5]) DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" @@ -33,6 +27,7 @@ else DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" fi +AC_SUBST(FREETYPE_VERSION) AC_SUBST(LIBFREETYPE_LIBS) AC_SUBST(LIBFREETYPE_CFLAGS) AC_SUBST(LIBFREETYPE_RPATH) From a01673b6eff94ee44b492fe0f3a9d6458625a856 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Tue, 25 Oct 2005 20:39:21 +0000 Subject: [PATCH 167/245] Deprecated-- svn path=/trunk/KDE/kdegraphics/kpdf/; revision=474252 --- shell/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/main.cpp b/shell/main.cpp index 4684a2291..2cfbdbf89 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -53,7 +53,7 @@ int main(int argc, char** argv) KApplication app; // see if we are starting with session management - if (app.isRestored()) + if (app.isSessionRestored()) { RESTORE(KPDF::Shell); } else { From c5d71038007daab976db8e18a99d75731a1a151b Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Thu, 27 Oct 2005 09:06:31 +0000 Subject: [PATCH 168/245] Qt3support-- svn path=/trunk/KDE/kdegraphics/kpdf/; revision=474742 --- core/document.cpp | 4 ++-- ui/pageview.cpp | 12 ++++++------ ui/presentationwidget.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index e4588e43e..03b50af76 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -176,7 +176,7 @@ bool KPDFDocument::openDocument( const QString & docFile, const KURL & url, cons } // 1. load Document (and set busy cursor while loading) - QApplication::setOverrideCursor( Qt::waitCursor ); + QApplication::setOverrideCursor( Qt::WaitCursor ); bool openOk = generator->loadDocument( docFile, pages_vector ); QApplication::restoreOverrideCursor(); if ( !openOk || pages_vector.size() <= 0 ) @@ -652,7 +652,7 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar s->highlightedPages.clear(); // set hourglass cursor - QApplication::setOverrideCursor( Qt::waitCursor ); + QApplication::setOverrideCursor( Qt::WaitCursor ); // 1. ALLDOC - proces all document marking pages if ( type == AllDoc ) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 440b669e4..15c43c071 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -578,7 +578,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) if( d->typeAheadActive ) { // backspace: remove a char and search or terminates search - if( e->key() == Qt::Key_BackSpace ) + if( e->key() == Qt::Key_Backspace ) { if( d->typeAheadString.length() > 1 ) { @@ -827,7 +827,7 @@ void PageView::contentsMousePressEvent( QMouseEvent * e ) if ( e->button() & Qt::MidButton ) { d->mouseMidStartY = e->globalPos().y(); - setCursor( Qt::sizeVerCursor ); + setCursor( Qt::SizeHorCursor ); return; } @@ -844,7 +844,7 @@ void PageView::contentsMousePressEvent( QMouseEvent * e ) { d->mouseGrabPos = d->mouseOnRect ? QPoint() : d->mousePressPos; if ( !d->mouseOnRect ) - setCursor( Qt::sizeAllCursor ); + setCursor( Qt::SizeAllCursor ); } break; @@ -1511,16 +1511,16 @@ void PageView::updateCursor( const QPoint &p ) // if over a ObjectRect (of type Link) change cursor to hand d->mouseOnRect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY ); if ( d->mouseOnRect ) - setCursor( Qt::pointingHandCursor ); + setCursor( Qt::PointingHandCursor ); else - setCursor( Qt::arrowCursor ); + setCursor( Qt::ArrowCursor ); } else { // if there's no page over the cursor and we were showing the pointingHandCursor // go back to the normal one d->mouseOnRect = false; - setCursor( Qt::arrowCursor ); + setCursor( Qt::ArrowCursor ); } } diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index b09ded027..6331252ed 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -185,9 +185,9 @@ void PresentationWidget::keyPressEvent( QKeyEvent * e ) { if (m_width == -1) return; - if ( e->key() == Qt::Key_Left || e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Prior ) + if ( e->key() == Qt::Key_Left || e->key() == Qt::Key_Backspace || e->key() == Qt::Key_PageUp ) slotPrevPage(); - else if ( e->key() == Qt::Key_Right || e->key() == Qt::Key_Space || e->key() == Qt::Key_Next ) + else if ( e->key() == Qt::Key_Right || e->key() == Qt::Key_Space || e->key() == Qt::Key_PageDown ) slotNextPage(); else if ( e->key() == Qt::Key_Home ) slotFirstPage(); From 432022193d066521b3ebe0f021b61b58128f95de Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 28 Oct 2005 22:48:32 +0000 Subject: [PATCH 169/245] Fordwardport fix for i18n problem svn path=/trunk/KDE/kdegraphics/kpdf/; revision=475347 --- part.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/part.cpp b/part.cpp index b861974aa..9893526d2 100644 --- a/part.cpp +++ b/part.cpp @@ -682,7 +682,7 @@ void Part::slotSaveFileAs() { if ( KIO::NetAccess::exists( saveURL, false, widget() ) ) { - if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.fileName(), QString::null, i18n("Overwrite"))) != KMessageBox::Continue) + if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.fileName()), QString::null, i18n("Overwrite")) != KMessageBox::Continue) return; } From e3a87e00c4468eaff3d49d9bc95f7020bd5d8e4d Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Mon, 7 Nov 2005 09:45:33 +0000 Subject: [PATCH 170/245] qt3support-- svn path=/trunk/KDE/kdegraphics/kpdf/; revision=478607 --- ui/pageview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 15c43c071..e4a768157 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -1155,7 +1155,7 @@ void PageView::wheelEvent( QWheelEvent *e ) int delta = e->delta(), vScroll = verticalScrollBar()->value(); e->accept(); - if ( (e->state() & Qt::ControlButton) == Qt::ControlButton ) { + if ( (e->state() & Qt::ControlModifier) == Qt::ControlButton ) { if ( e->delta() < 0 ) slotZoomOut(); else @@ -1868,7 +1868,7 @@ void PageView::slotAutoScoll() int index = abs( d->scrollIncrement ) - 1; // 0..9 const int scrollDelay[10] = { 200, 100, 50, 30, 20, 30, 25, 20, 30, 20 }; const int scrollOffset[10] = { 1, 1, 1, 1, 1, 2, 2, 2, 4, 4 }; - d->autoScrollTimer->changeInterval( scrollDelay[ index ] ); + d->autoScrollTimer->start( scrollDelay[ index ] ); scrollBy( 0, d->scrollIncrement > 0 ? scrollOffset[ index ] : -scrollOffset[ index ] ); } From 9251a809285d559490b8e340d0d37df81550bf61 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Tue, 8 Nov 2005 21:55:35 +0000 Subject: [PATCH 171/245] Qt3support-- svn path=/trunk/KDE/kdegraphics/kpdf/; revision=479025 --- core/document.cpp | 10 +++++----- part.cpp | 6 +++--- ui/pageview.cpp | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 03b50af76..16b287547 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -137,7 +137,7 @@ bool KPDFDocument::openDocument( const QString & docFile, const KURL & url, cons { // docFile is always local so we can use QFile on it QFile fileReadTest( docFile ); - if ( !fileReadTest.open( IO_ReadOnly ) ) + if ( !fileReadTest.open( QIODevice::ReadOnly ) ) { d->docFileName = QString::null; return false; @@ -1208,7 +1208,7 @@ int KPDFDocument::getTotalMemory() #ifdef __linux__ // if /proc/meminfo doesn't exist, return 128MB QFile memFile( "/proc/meminfo" ); - if ( !memFile.open( IO_ReadOnly ) ) + if ( !memFile.open( QIODevice::ReadOnly ) ) return (cachedValue = 134217728); // read /proc/meminfo and sum up the contents of 'MemFree', 'Buffers' @@ -1230,7 +1230,7 @@ int KPDFDocument::getFreeMemory() #ifdef __linux__ // if /proc/meminfo doesn't exist, return MEMORY FULL QFile memFile( "/proc/meminfo" ); - if ( !memFile.open( IO_ReadOnly ) ) + if ( !memFile.open( QIODevice::ReadOnly ) ) return 0; // read /proc/meminfo and sum up the contents of 'MemFree', 'Buffers' @@ -1264,7 +1264,7 @@ void KPDFDocument::loadDocumentInfo() { //kdDebug() << "Using '" << d->xmlFileName << "' as document info file." << endl; QFile infoFile( d->xmlFileName ); - if ( !infoFile.exists() || !infoFile.open( IO_ReadOnly ) ) + if ( !infoFile.exists() || !infoFile.open( QIODevice::ReadOnly ) ) return; // Load DOM from XML file @@ -1377,7 +1377,7 @@ void KPDFDocument::saveDocumentInfo() const return; QFile infoFile( d->xmlFileName ); - if (infoFile.open( IO_WriteOnly | IO_Truncate) ) + if (infoFile.open( QIODevice::WriteOnly | QIODevice::Truncate) ) { // Create DOM QDomDocument doc( "documentInfo" ); diff --git a/part.cpp b/part.cpp index 9893526d2..155335e08 100644 --- a/part.cpp +++ b/part.cpp @@ -153,7 +153,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, // [left toolbox: Table of Contents] | [] TOC * tocFrame = new TOC( m_toolBox, m_document ); connect(tocFrame, SIGNAL(hasTOC(bool)), this, SLOT(enableTOC(bool))); - index = m_toolBox->addItem( tocFrame, QIconSet(SmallIcon("text_left")), i18n("Contents") ); + index = m_toolBox->addItem( tocFrame, QIcon(SmallIcon("text_left")), i18n("Contents") ); m_toolBox->setItemToolTip(index, i18n("Contents")); enableTOC( false ); @@ -168,7 +168,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, thumbsBox->setStretchFactor( m_searchWidget, 100 ); thumbsBox->setStretchFactor( m_thumbnailList, 100 ); // thumbsBox->setStretchFactor( m_tc, 1 ); - index = m_toolBox->addItem( thumbsBox, QIconSet(SmallIcon("thumbnail")), i18n("Thumbnails") ); + index = m_toolBox->addItem( thumbsBox, QIcon(SmallIcon("thumbnail")), i18n("Thumbnails") ); m_toolBox->setItemToolTip(index, i18n("Thumbnails")); m_toolBox->setCurrentItem( thumbsBox ); @@ -176,7 +176,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, /* // [left toolbox: Annotations] | [] QFrame * editFrame = new QFrame( m_toolBox ); - int iIdx = m_toolBox->addItem( editFrame, QIconSet(SmallIcon("pencil")), i18n("Annotations") ); + int iIdx = m_toolBox->addItem( editFrame, QIcon(SmallIcon("pencil")), i18n("Annotations") ); m_toolBox->setItemEnabled( iIdx, false );*/ // widgets: [../miniBarContainer] | [] diff --git a/ui/pageview.cpp b/ui/pageview.cpp index e4a768157..8f7e0f117 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -1106,7 +1106,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) // serialize the text to speech (selectedText) and the // preferred reader ("" is the default voice) ... QByteArray data; - QDataStream arg( &data, IO_WriteOnly ); + QDataStream arg( &data, QIODevice::WriteOnly ); arg.setVersion(QDataStream::Qt_3_1); arg << selectedText; @@ -1117,7 +1117,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) if (client->call( "kttsd", "KSpeech", "setText(QString,QString)", data, replyType, replyData, true )) { QByteArray data2; - QDataStream arg2(&data2, IO_WriteOnly); + QDataStream arg2(&data2, QIODevice::WriteOnly); arg2.setVersion(QDataStream::Qt_3_1); arg2 << 0; @@ -1155,7 +1155,7 @@ void PageView::wheelEvent( QWheelEvent *e ) int delta = e->delta(), vScroll = verticalScrollBar()->value(); e->accept(); - if ( (e->state() & Qt::ControlModifier) == Qt::ControlButton ) { + if ( (e->state() & Qt::ControlModifier) == Qt::ControlModifier ) { if ( e->delta() < 0 ) slotZoomOut(); else From b734531e6ffac5f1436eddcfca00a0aa6cc99b1b Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Wed, 9 Nov 2005 18:23:36 +0000 Subject: [PATCH 172/245] qt3support-- / warning-- svn path=/trunk/KDE/kdegraphics/kpdf/; revision=479237 --- ui/pageview.cpp | 20 ++++++++++---------- ui/pageviewutils.cpp | 2 +- ui/presentationwidget.cpp | 2 +- ui/propertiesdialog.cpp | 8 ++++---- ui/thumbnaillist.cpp | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 8f7e0f117..938e3eeab 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -586,7 +586,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) bool found = d->document->searchText( PAGEVIEW_SEARCH_ID, d->typeAheadString, true, false, KPDFDocument::NextMatch, true, qRgb( 128, 255, 128 ), true ); QString status = found ? i18n("Text found: \"%1\".") : i18n("Text not found: \"%1\"."); - d->messageWindow->display( status.arg(d->typeAheadString.lower()), + d->messageWindow->display( status.arg(d->typeAheadString.toLower()), found ? PageViewMessage::Find : PageViewMessage::Warning, 4000 ); d->findTimeoutTimer->start( 3000, true ); } @@ -606,7 +606,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) // because it activates the accel releaseKeyboard(); if ( d->document->continueSearch( PAGEVIEW_SEARCH_ID ) ) - d->messageWindow->display( i18n("Text found: \"%1\".").arg(d->typeAheadString.lower()), + d->messageWindow->display( i18n("Text found: \"%1\".").arg(d->typeAheadString.toLower()), PageViewMessage::Find, 3000 ); d->findTimeoutTimer->start( 3000, true ); // it is needed to grab the keyboard becase people may have Space assigned to a @@ -626,7 +626,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) bool found = d->document->searchText( PAGEVIEW_SEARCH_ID, d->typeAheadString, false, false, KPDFDocument::NextMatch, true, qRgb( 128, 255, 128 ), true ); QString status = found ? i18n("Text found: \"%1\".") : i18n("Text not found: \"%1\"."); - d->messageWindow->display( status.arg(d->typeAheadString.lower()), + d->messageWindow->display( status.arg(d->typeAheadString.toLower()), found ? PageViewMessage::Find : PageViewMessage::Warning, 4000 ); d->findTimeoutTimer->start( 3000, true ); } @@ -953,7 +953,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) } // find out new zoom ratio and normalized view center (relative to the contentsRect) - double zoom = QMIN( (double)visibleWidth() / (double)selRect.width(), (double)visibleHeight() / (double)selRect.height() ); + double zoom = qMin( (double)visibleWidth() / (double)selRect.width(), (double)visibleHeight() / (double)selRect.height() ); double nX = (double)(selRect.left() + selRect.right()) / (2.0 * (double)contentsWidth()); double nY = (double)(selRect.top() + selRect.bottom()) / (2.0 * (double)contentsHeight()); @@ -1066,7 +1066,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) QString type( KImageIO::type( fileName ) ); if ( type.isNull() ) type = "PNG"; - copyPix.save( fileName, type.latin1() ); + copyPix.save( fileName, type.toLatin1() ); d->messageWindow->display( i18n( "Image [%1x%2] saved to %3 file." ).arg( copyPix.width() ).arg( copyPix.height() ).arg( type ) ); } } @@ -1307,7 +1307,7 @@ void PageView::updateItemSize( PageViewItem * item, int colWidth, int rowHeight { double scaleW = (double)colWidth / (double)width; double scaleH = (double)rowHeight / (double)height; - zoom = QMIN( scaleW, scaleH ); + zoom = qMin( scaleW, scaleH ); item->setWHZ( (int)(zoom * width), (int)(zoom * height), zoom ); d->zoomFactor = zoom; } @@ -1351,8 +1351,8 @@ void PageView::selectionEndPoint( int x, int y ) { // clip selection to the viewport QRect viewportRect( contentsX(), contentsY(), visibleWidth(), visibleHeight() ); - x = QMAX( QMIN( x, viewportRect.right() ), viewportRect.left() ); - y = QMAX( QMIN( y, viewportRect.bottom() ), viewportRect.top() ); + x = qMax( qMin( x, viewportRect.right() ), viewportRect.left() ); + y = qMax( qMin( y, viewportRect.bottom() ), viewportRect.top() ); // if selection changed update rect if ( d->mouseSelectionRect.right() != x || d->mouseSelectionRect.bottom() != y ) { @@ -1458,7 +1458,7 @@ void PageView::updateZoomText() { // use current page zoom as zoomFactor if in ZoomFit/* mode if ( d->zoomMode != ZoomFixed && d->items.count() > 0 ) - d->zoomFactor = d->items[ QMAX( 0, (int)d->document->currentPage() ) ]->zoomFactor(); + d->zoomFactor = d->items[ qMax( 0, (int)d->document->currentPage() ) ]->zoomFactor(); float newFactor = d->zoomFactor; d->aZoom->clear(); @@ -1622,7 +1622,7 @@ void PageView::slotRelayoutPages() } else // viewContinuous is FALSE { - PageViewItem * currentItem = d->items[ QMAX( 0, (int)d->document->currentPage() ) ]; + PageViewItem * currentItem = d->items[ qMax( 0, (int)d->document->currentPage() ) ]; // setup varialbles for a 1(row) x N(columns) grid int nCols = KpdfSettings::viewColumns(), diff --git a/ui/pageviewutils.cpp b/ui/pageviewutils.cpp index c1c4c00ac..3a8488207 100644 --- a/ui/pageviewutils.cpp +++ b/ui/pageviewutils.cpp @@ -73,7 +73,7 @@ void PageViewMessage::display( const QString & message, Icon icon, int durationM } textXOffset = 2 + symbol.width(); width += textXOffset; - height = QMAX( height, symbol.height() ); + height = qMax( height, symbol.height() ); } QRect geometry( 0, 0, width + 10, height + 8 ); QRect geometry2( 0, 0, width + 9, height + 7 ); diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index 6331252ed..b753889d7 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -578,7 +578,7 @@ void PresentationWidget::generateContentsPage( int pageNum, QPainter & p ) // fill unpainted areas with background color QRegion unpainted( QRect( 0, 0, m_width, m_height ) ); QVector rects = unpainted.subtract( frame->geometry ).rects(); - for ( uint i = 0; i < rects.count(); i++ ) + for ( int i = 0; i < rects.count(); i++ ) { const QRect & r = rects[i]; p.fillRect( r, KpdfSettings::slidesBackgroundColor() ); diff --git a/ui/propertiesdialog.cpp b/ui/propertiesdialog.cpp index 1288a9daa..cefa2f262 100644 --- a/ui/propertiesdialog.cpp +++ b/ui/propertiesdialog.cpp @@ -34,7 +34,7 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) } // mime name based on mimetype id - QString mimeName = info->get( "mimeType" ).section( '/', -1 ).upper(); + QString mimeName = info->get( "mimeType" ).section( '/', -1 ).toUpper(); setCaption( i18n("%1 Properties").arg( mimeName ) ); QDomElement docElement = info->documentElement(); @@ -57,7 +57,7 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) row++; // refine maximum width of 'value' labels - valMaxWidth = QMAX( valMaxWidth, fontMetrics().width( valueString ) ); + valMaxWidth = qMax( valMaxWidth, fontMetrics().width( valueString ) ); } // add the number of pages if the generator hasn't done it already @@ -85,10 +85,10 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) int width = layout->minimumSize().width() + valMaxWidth + marginHint() + spacingHint() + marginHint() + 30; if (page2Layout) { - width = QMAX( width, page2Layout->sizeHint().width() + marginHint() + spacingHint() + 31 ); + width = qMax( width, page2Layout->sizeHint().width() + marginHint() + spacingHint() + 31 ); } // stay inside the 2/3 of the screen width QRect screenContainer = KGlobalSettings::desktopGeometry( this ); - width = QMIN( width, 2*screenContainer.width()/3 ); + width = qMin( width, 2*screenContainer.width()/3 ); resize(width, 1); } diff --git a/ui/thumbnaillist.cpp b/ui/thumbnaillist.cpp index d313770ed..54eb28758 100644 --- a/ui/thumbnaillist.cpp +++ b/ui/thumbnaillist.cpp @@ -170,7 +170,7 @@ void ThumbnailList::notifyViewportChanged( bool /*smoothMove*/ ) m_selected->setSelected( true ); if ( KpdfSettings::syncThumbnailsViewport() ) { - int yOffset = QMAX( visibleHeight() / 4, m_selected->height() / 2 ); + int yOffset = qMax( visibleHeight() / 4, m_selected->height() / 2 ); ensureVisible( 0, childY( m_selected ) + m_selected->height()/2, 0, yOffset ); } break; From 6d36df61be5d434e2947f5b18adda4dd5751b525 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Thu, 10 Nov 2005 17:52:04 +0000 Subject: [PATCH 173/245] Byebye q3vbox svn path=/trunk/KDE/kdegraphics/kpdf/; revision=479485 --- part.cpp | 4 ++-- ui/thumbnaillist.h | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/part.cpp b/part.cpp index 155335e08..a154552cb 100644 --- a/part.cpp +++ b/part.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -158,7 +158,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName, enableTOC( false ); // [left toolbox: Thumbnails and Bookmarks] | [] - Q3VBox * thumbsBox = new ThumbnailsBox( m_toolBox ); + KVBox * thumbsBox = new ThumbnailsBox( m_toolBox ); m_searchWidget = new SearchWidget( thumbsBox, m_document ); m_thumbnailList = new ThumbnailList( thumbsBox, m_document ); // ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList ); diff --git a/ui/thumbnaillist.h b/ui/thumbnaillist.h index 73dca883d..3a34bb695 100644 --- a/ui/thumbnaillist.h +++ b/ui/thumbnaillist.h @@ -12,8 +12,9 @@ #include #include -#include + #include +#include #include "core/observer.h" class QTimer; @@ -97,10 +98,10 @@ Q_OBJECT /** * @short A vertical boxed container with zero size hint (for insertion on left toolbox) */ -class ThumbnailsBox : public Q3VBox +class ThumbnailsBox : public KVBox { public: - ThumbnailsBox( QWidget * parent ) : Q3VBox( parent ) {}; + ThumbnailsBox( QWidget * parent ) : KVBox( parent ) {}; QSize sizeHint() const { return QSize(); } }; From 8bc2082259094d50e33295ea2bea89f84675fe17 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Mon, 14 Nov 2005 10:35:54 +0000 Subject: [PATCH 174/245] qt3cstring-- svn path=/trunk/KDE/kdegraphics/kpdf/; revision=480301 --- core/generator_pdf/generator_pdf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 87abd5bc7..d10f769a2 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -111,7 +111,7 @@ bool PDFGenerator::loadDocument( const QString & filePath, QVector & KWallet::Wallet * wallet = 0; while ( !pdfdoc->isOk() && pdfdoc->getErrorCode() == errEncrypted ) { - Q3CString password; + QByteArray password; // 1.A. try to retrieve the first password from the kde wallet system if ( !triedWallet ) From 1145973768bb81073ee256a3a41c9d05a5835bf9 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Mon, 14 Nov 2005 10:39:00 +0000 Subject: [PATCH 175/245] qt3support-- svn path=/trunk/KDE/kdegraphics/kpdf/; revision=480302 --- core/generator_pdf/generator_pdf.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index d10f769a2..f54701984 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -424,9 +423,8 @@ bool PDFGenerator::print( KPrinter& printer ) dummy.setFullPage(true); dummy.setPageSize((QPrinter::PageSize)(ps.isEmpty() ? KGlobal::locale()->pageSize() : pageNameToPageSize(ps))); - Q3PaintDeviceMetrics metrics(&dummy); - globalParams->setPSPaperWidth(metrics.width()); - globalParams->setPSPaperHeight(metrics.height()); + globalParams->setPSPaperWidth(dummy.width()); + globalParams->setPSPaperHeight(dummy.height()); } KTempFile tf( QString::null, ".ps" ); From 440e9bc918169744c930b29f2226868cea655fb4 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Thu, 17 Nov 2005 13:55:17 +0000 Subject: [PATCH 176/245] compile/link++ svn path=/trunk/KDE/kdegraphics/kpdf/; revision=481012 --- part.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/part.cpp b/part.cpp index a154552cb..175498c0e 100644 --- a/part.cpp +++ b/part.cpp @@ -788,11 +788,11 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) if (factory()) { - Q3PtrList clients(factory()->clients()); - Q3PtrListIterator clientsIt( clients ); - for( ; (!m_showMenuBarAction || !m_showFullScreenAction) && clientsIt.current(); ++clientsIt) + QList clients(factory()->clients()); + for (int i = 0; (!m_showMenuBarAction || !m_showFullScreenAction) && i < clients.size() ; ++i) { - client = clientsIt.current(); + + client = clients.at(i); ac = client->actionCollection(); actions = ac->actions(); end = actions.end(); From d0cf2f8debb361f2ea76aac0d18a2feffbabe0a7 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 17 Nov 2005 21:31:54 +0000 Subject: [PATCH 177/245] Fordwardport fix for bug 116384 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=481100 --- xpdf/splash/SplashFTFont.cc | 42 ++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/xpdf/splash/SplashFTFont.cc b/xpdf/splash/SplashFTFont.cc index 65c9dd9f3..00946e4db 100644 --- a/xpdf/splash/SplashFTFont.cc +++ b/xpdf/splash/SplashFTFont.cc @@ -12,6 +12,11 @@ #pragma implementation #endif +#define MAKE_VERSION( a,b,c ) (((a) << 16) | ((b) << 8) | (c)) + +#define FREETYPE_VERSION \ + MAKE_VERSION(FREETYPE_MAJOR,FREETYPE_MINOR,FREETYPE_PATCH) + #include #include FT_OUTLINE_H #include FT_SIZES_H @@ -26,11 +31,19 @@ //------------------------------------------------------------------------ +#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) ) +static int glyphPathMoveTo(const FT_Vector *pt, void *path); +static int glyphPathLineTo(const FT_Vector *pt, void *path); +static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, void *path); +static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, + const FT_Vector *pt, void *path); +#else static int glyphPathMoveTo(FT_Vector *pt, void *path); static int glyphPathLineTo(FT_Vector *pt, void *path); static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path); static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, FT_Vector *pt, void *path); +#endif //------------------------------------------------------------------------ // SplashFTFont @@ -243,7 +256,12 @@ SplashPath *SplashFTFont::getGlyphPath(int c) { return path.path; } -static int glyphPathMoveTo(FT_Vector *pt, void *path) { +#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) ) +static int glyphPathMoveTo(const FT_Vector *pt, void *path) +#else +static int glyphPathMoveTo(FT_Vector *pt, void *path) +#endif +{ SplashFTFontPath *p = (SplashFTFontPath *)path; if (p->needClose) { @@ -254,7 +272,12 @@ static int glyphPathMoveTo(FT_Vector *pt, void *path) { return 0; } -static int glyphPathLineTo(FT_Vector *pt, void *path) { +#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) ) +static int glyphPathLineTo(const FT_Vector *pt, void *path) +#else +static int glyphPathLineTo(FT_Vector *pt, void *path) +#endif +{ SplashFTFontPath *p = (SplashFTFontPath *)path; p->path->lineTo(pt->x / 64.0, -pt->y / 64.0); @@ -262,7 +285,12 @@ static int glyphPathLineTo(FT_Vector *pt, void *path) { return 0; } -static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path) { +#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) ) +static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, void *path) +#else +static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path) +#endif +{ SplashFTFontPath *p = (SplashFTFontPath *)path; SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc; @@ -300,8 +328,12 @@ static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path) { return 0; } -static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, - FT_Vector *pt, void *path) { +#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) ) +static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, const FT_Vector *pt, void *path) +#else +static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, FT_Vector *pt, void *path) +#endif +{ SplashFTFontPath *p = (SplashFTFontPath *)path; p->path->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0, From 6c9fefa63b7f3873873b430e03444256aaadbcbf Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Sun, 20 Nov 2005 15:54:57 +0000 Subject: [PATCH 178/245] Fix menu + checked action svn path=/trunk/KDE/kdegraphics/kpdf/; revision=481788 --- ui/searchwidget.cpp | 49 ++++++++++++++++++++++++++++++++------------- ui/searchwidget.h | 5 +++-- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/ui/searchwidget.cpp b/ui/searchwidget.cpp index 0870f6b42..f037cdbd5 100644 --- a/ui/searchwidget.cpp +++ b/ui/searchwidget.cpp @@ -56,13 +56,19 @@ SearchWidget::SearchWidget( QWidget * parent, KPDFDocument * document ) // 3.1. create the popup menu for changing filtering features m_menu = new QMenu( this ); - m_menu->insertItem( i18n("Case Sensitive"), 1 ); - m_menu->insertSeparator( 2 ); - m_menu->insertItem( i18n("Match Phrase"), 3 ); - m_menu->insertItem( i18n("Match All Words"), 4 ); - m_menu->insertItem( i18n("Match Any Word"), 5 ); - m_menu->setItemChecked( 3, true ); - connect( m_menu, SIGNAL( activated(int) ), SLOT( slotMenuChaged(int) ) ); + m_caseSensitiveAction = m_menu->addAction( i18n("Case Sensitive") ); + m_menu->insertSeparator( ); + m_matchPhraseAction = m_menu->addAction( i18n("Match Phrase") ); + m_marchAllWordsAction = m_menu->addAction( i18n("Match All Words") ); + m_marchAnyWordsAction = m_menu->addAction( i18n("Match Any Word") ); + + m_caseSensitiveAction->setCheckable( true ); + m_matchPhraseAction->setCheckable( true ); + m_marchAllWordsAction->setCheckable( true ); + m_marchAnyWordsAction->setCheckable( true ); + + m_marchAllWordsAction->setChecked( true ); + connect( m_menu, SIGNAL( triggered(QAction *) ), SLOT( slotMenuChaged(QAction*) ) ); // 3.2. create the toolbar button that spawns the popup menu insertButton( "kpdf", FIND_ID, m_menu, true, i18n( "Filter Options" ), 2/*index*/ ); @@ -87,19 +93,34 @@ void SearchWidget::slotTextChanged( const QString & text ) m_inputDelayTimer->start(333, true); } -void SearchWidget::slotMenuChaged( int index ) +void SearchWidget::slotMenuChaged( QAction * act ) { // update internal variables and checked state - if ( index == 1 ) + if ( act == m_caseSensitiveAction ) { m_caseSensitive = !m_caseSensitive; - m_menu->setItemChecked( 1, m_caseSensitive ); + m_caseSensitiveAction->setChecked( m_caseSensitive ); + } + else if ( act == m_matchPhraseAction ) + { + m_searchType = 0; + m_matchPhraseAction->setChecked( true ); + m_marchAllWordsAction->setChecked( false ); + m_marchAnyWordsAction->setChecked( false ); + } + else if ( act == m_marchAllWordsAction ) + { + m_searchType = 1; + m_matchPhraseAction->setChecked( false ); + m_marchAllWordsAction->setChecked( true ); + m_marchAnyWordsAction->setChecked( false ); } - else if ( index >= 3 && index <= 5 ) + else if ( act == m_marchAnyWordsAction ) { - m_searchType = index - 3; - for ( int i = 0; i < 3; i++ ) - m_menu->setItemChecked( i + 3, m_searchType == i ); + m_searchType = 2; + m_matchPhraseAction->setChecked( false ); + m_marchAllWordsAction->setChecked( false ); + m_marchAnyWordsAction->setChecked( true ); } else return; diff --git a/ui/searchwidget.h b/ui/searchwidget.h index a6ca076c4..189f07936 100644 --- a/ui/searchwidget.h +++ b/ui/searchwidget.h @@ -14,6 +14,7 @@ class KPDFDocument; class m_inputDelayTimer; +class QAction; // definition of searchID for this class (publicly available to ThumbnailsList) #define SW_SEARCH_ID 3 @@ -39,10 +40,10 @@ class SearchWidget : public KToolBar QTimer * m_inputDelayTimer; int m_searchType; bool m_caseSensitive; - + QAction *m_matchPhraseAction, *m_caseSensitiveAction, * m_marchAllWordsAction, *m_marchAnyWordsAction; private slots: void slotTextChanged( const QString & text ); - void slotMenuChaged( int index ); + void slotMenuChaged( QAction * ); void startSearch(); }; From d242a306cd9e397d956f15206eb1fc4afc29912f Mon Sep 17 00:00:00 2001 From: Jessica Hall Date: Mon, 21 Nov 2005 09:11:07 +0000 Subject: [PATCH 179/245] more bug fixes from Burkhard. BUG:116019 BUG:116021 BUG:116020 BUG:116093 BUG:116097 svn path=/trunk/KDE/kdegraphics/doc/kpdf/; revision=481963 --- doc/index.docbook | 157 +++++++++++++++++++++++++++++----------------- 1 file changed, 98 insertions(+), 59 deletions(-) diff --git a/doc/index.docbook b/doc/index.docbook index cb31cd712..8a41b7ae3 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -13,7 +13,6 @@ Albert - Astals Cid
tsdgeos@yahoo.es
@@ -148,7 +147,7 @@ - Open a file selected from a drop-down list of + Open a file selected from a combo box list of recently opened files. If a file is currently being displayed it will be closed. @@ -255,51 +254,13 @@ - - The <guimenu>Mouse mode</guimenu> Menu - - - - - Mouse mode - Normal - - - - The mouse will have its normal behaviour, &LMB; for dragging the document and following links and &RMB; for adding bookmarks and fit to width. - - - - - - Mouse mode - Zoom tool - - - - The mouse will work as a zoom tool. Clicking &LMB; and dragging will zoom the view to the selected area, clicking &RMB; will bring the document back to the previous zoom. - - - - - - Mouse mode - Select - - - - The mouse will work as a select tool. In that mode clicking &LMB; and dragging will give the option of copying the text/image of current the selected area to the clipboard, images can be saved to a file too. - - - - - The <guimenu>View</guimenu> Menu + &Ctrl;&Shift;P View Presentation @@ -386,6 +347,30 @@ The <guimenu>Go</guimenu> Menu + + + + Backspace + Go + Previous Page + + + + View the previous page of the document. + + + + + + Space + Go + Next Page + + + + View the next page of the document. + + @@ -401,37 +386,88 @@ - Backspace + &Ctrl; End Go - Previous Page + Last Page - View the previous page of the document. + Go to the last page of the document. - Space + &Alt; Left Go - Next Page + Back - View the next page of the document. - + Go to the page displayed before. + - &Ctrl; End + &Alt;Right Go - Last Page + Forward - Go to the last page of the document. + Go to the page of the document where you were after. + + + + + + &Ctrl;G + Go + Go to Page + + + + Go to a selected page of the document. + + + + + + + The <guimenu>Tools</guimenu> Menu + + + + + Tools + Browse Tool + + + + The mouse will have its normal behaviour, &LMB; for dragging the document and following links and &RMB; for adding bookmarks and fit to width. + + + + + + Tools + Zoom Tool + + + + The mouse will work as a zoom tool. Clicking &LMB; and dragging will zoom the view to the selected area, clicking &RMB; will bring the document back to the previous zoom. + + + + + + Tools + Select Tool + + + + The mouse will work as a select tool. In that mode clicking &LMB; and dragging will give the option of copying the text/image of current the selected area to the clipboard, images can be saved to a file too. @@ -443,8 +479,9 @@ + &Ctrl;M Settings - Show Menubar + Show/Hide Menubar @@ -456,7 +493,7 @@ Settings - Show Toolbar + Show/Hide Toolbar @@ -466,18 +503,19 @@ + &Ctrl;L Settings - Watch File + Show/Hide Navigation Panel - If this is selected the display will automatically - updated if the document file changes. + Toggle the Navigation Panel display on and off. + &Ctrl;&Shift;F Settings Full Screen Mode @@ -600,7 +638,7 @@ Invert colors - Inverts colors on the view, i.e. black things will be shown white. + Inverts colors on the view, &ie; black things will be shown white. @@ -638,7 +676,7 @@ Enable background generation Use a background thread to generate the pages. By disabling - this option the GUI will become less reactive (will be blocked + this option the &GUI; will become less reactive (will be blocked if necessary), but pages will be displayed a bit faster. @@ -708,10 +746,11 @@ Program Copyright: Albert Astals Cidtsdgeos@yahoo.es Current maintainer Christophe Devrieseoelewapperke@ulyssis.org - Wilco Greven greven@kde.org Original author + &Wilco.Greven; Wilco.Greven.mail; Original author Enrico Roseros.kde@email.it Refactoring for 3.4 + &underFDL; &underGPL; From 6925c8a70b2a64edaeefa29437eeea3539b2bdb0 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 1 Dec 2005 22:20:57 +0000 Subject: [PATCH 180/245] fordwardport r484782 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=484783 --- ui/presentationwidget.cpp | 2 ++ ui/presentationwidget.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index b753889d7..57e9a7c72 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -174,12 +174,14 @@ bool PresentationWidget::canUnloadPixmap( int pageNumber ) // +/* This hack was here to fix 103718 but it's no longer necessary on KDE 3.5 and Lubos asked me to remove it bool PresentationWidget::event ( QEvent * e ) { if (e -> type() == QEvent::WindowDeactivate) KWin::clearState(winId(), NET::StaysOnTop); else if (e -> type() == QEvent::WindowActivate) KWin::setState(winId(), NET::StaysOnTop); return QDialog::event(e); } +*/ void PresentationWidget::keyPressEvent( QKeyEvent * e ) { diff --git a/ui/presentationwidget.h b/ui/presentationwidget.h index 6f4e75d78..5f25b6cac 100644 --- a/ui/presentationwidget.h +++ b/ui/presentationwidget.h @@ -46,7 +46,7 @@ class PresentationWidget : public QDialog, public DocumentObserver protected: // widget events - bool event( QEvent * e ); +// bool event( QEvent * e ); void keyPressEvent( QKeyEvent * e ); void wheelEvent( QWheelEvent * e ); void mousePressEvent( QMouseEvent * e ); From 68102cae28ca618b048d398d0ce760b800efc245 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 1 Dec 2005 22:35:18 +0000 Subject: [PATCH 181/245] Fordward port r484787 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=484788 --- xpdf/xpdf/JPXStream.cc | 9 ++++++++- xpdf/xpdf/Stream.cc | 33 ++++++++++++++++++++++++++++++++- xpdf/xpdf/Stream.h | 3 +++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/xpdf/xpdf/JPXStream.cc b/xpdf/xpdf/JPXStream.cc index faa61312e..9c9578abf 100644 --- a/xpdf/xpdf/JPXStream.cc +++ b/xpdf/xpdf/JPXStream.cc @@ -783,7 +783,7 @@ GBool JPXStream::readCodestream(Guint /*len*/) { int segType; GBool haveSIZ, haveCOD, haveQCD, haveSOT; Guint precinctSize, style; - Guint segLen, capabilities, comp, i, j, r; + Guint segLen, capabilities, nTiles, comp, i, j, r; //----- main header haveSIZ = haveCOD = haveQCD = haveSOT = gFalse; @@ -818,6 +818,13 @@ GBool JPXStream::readCodestream(Guint /*len*/) { / img.xTileSize; img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1) / img.yTileSize; + nTiles = img.nXTiles * img.nYTiles; + // check for overflow before allocating memory + if (nTiles == 0 || nTiles / img.nXTiles != img.nYTiles) { + error(getPos(), "Bad tile count in JPX SIZ marker segment"); + return gFalse; + } + img.tiles = (JPXTile *)gmallocn(nTiles, sizeof(JPXTile)); img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles, sizeof(JPXTile)); for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc index 2435070ed..cc915f247 100644 --- a/xpdf/xpdf/Stream.cc +++ b/xpdf/xpdf/Stream.cc @@ -403,18 +403,33 @@ void ImageStream::skipLine() { StreamPredictor::StreamPredictor(Stream *strA, int predictorA, int widthA, int nCompsA, int nBitsA) { + int totalBits; + str = strA; predictor = predictorA; width = widthA; nComps = nCompsA; nBits = nBitsA; + predLine = NULL; + ok = gFalse; nVals = width * nComps; + totalBits = nVals * nBits; + if (totalBits == 0 || + (totalBits / nBits) / nComps != width || + totalBits + 7 < 0) { + return; + } pixBytes = (nComps * nBits + 7) >> 3; - rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; + rowBytes = ((totalBits + 7) >> 3) + pixBytes; + if (rowBytes < 0) { + return; + } predLine = (Guchar *)gmalloc(rowBytes); memset(predLine, 0, rowBytes); predIdx = rowBytes; + + ok = gTrue; } StreamPredictor::~StreamPredictor() { @@ -1006,6 +1021,10 @@ LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors, FilterStream(strA) { if (predictor != 1) { pred = new StreamPredictor(this, predictor, columns, colors, bits); + if (!pred->isOk()) { + delete pred; + pred = NULL; + } } else { pred = NULL; } @@ -2903,6 +2922,14 @@ GBool DCTStream::readBaselineSOF() { height = read16(); width = read16(); numComps = str->getChar(); + if (numComps <= 0 || numComps > 4) { + error(getPos(), "Bad number of components in DCT stream", prec); + return gFalse; + } + if (numComps <= 0 || numComps > 4) { + error(getPos(), "Bad number of components in DCT stream", prec); + return gFalse; + } if (prec != 8) { error(getPos(), "Bad DCT precision %d", prec); return gFalse; @@ -3833,6 +3860,10 @@ FlateStream::FlateStream(Stream *strA, int predictor, int columns, FilterStream(strA) { if (predictor != 1) { pred = new StreamPredictor(this, predictor, columns, colors, bits); + if (!pred->isOk()) { + delete pred; + pred = NULL; + } } else { pred = NULL; } diff --git a/xpdf/xpdf/Stream.h b/xpdf/xpdf/Stream.h index 00f4c79a6..085f3a0a1 100644 --- a/xpdf/xpdf/Stream.h +++ b/xpdf/xpdf/Stream.h @@ -232,6 +232,8 @@ public: ~StreamPredictor(); + GBool isOk() { return ok; } + int lookChar(); int getChar(); @@ -249,6 +251,7 @@ private: int rowBytes; // bytes per line Guchar *predLine; // line buffer int predIdx; // current index in predLine + GBool ok; }; //------------------------------------------------------------------------ From 1aea3a4e3bdefde6d495bd11b81fe7a2c67ae0e9 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 4 Dec 2005 13:16:22 +0000 Subject: [PATCH 182/245] similar patch to fix 117658 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=485452 --- part.cpp | 9 ++++++++- part.h | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/part.cpp b/part.cpp index 175498c0e..fcf8f1afa 100644 --- a/part.cpp +++ b/part.cpp @@ -276,6 +276,8 @@ Part::Part(QWidget *parentWidget, const char *widgetName, connect( m_watcher, SIGNAL( dirty( const QString& ) ), this, SLOT( slotFileDirty( const QString& ) ) ); m_dirtyHandler = new QTimer( this ); connect( m_dirtyHandler, SIGNAL( timeout() ),this, SLOT( slotDoFileDirty() ) ); + m_saveSplitterSizeTimer = new QTimer( this ); + connect( m_saveSplitterSizeTimer, SIGNAL( timeout() ),this, SLOT( reallySaveSplitterSize() ) ); slotNewConfig(); @@ -575,10 +577,15 @@ void Part::cannotQuit() } void Part::saveSplitterSize() +{ + m_saveSplitterSizeTimer->start(500, true); +} + +void Part::reallySaveSplitterSize() { KpdfSettings::setSplitterSizes( m_splitter->sizes() ); KpdfSettings::writeConfig(); -} +} //BEGIN go to page dialog class KPDFGotoPageDialog : public KDialogBase diff --git a/part.h b/part.h index e23ef9491..73ae57131 100644 --- a/part.h +++ b/part.h @@ -114,7 +114,8 @@ protected slots: void enableTOC(bool enable); void psTransformEnded(); void cannotQuit(); - void saveSplitterSize(); + void saveSplitterSize(); + void reallySaveSplitterSize(); void setMimeTypes(KIO::Job *job); public slots: @@ -143,6 +144,11 @@ private: // static instances counter static unsigned int m_count; + + // this is a hack because we can not use writeConfig on part destructor + // and we don't want to writeconfig every time someone moves the splitter + // so we use a QTimer each 500 ms + QTimer *m_saveSplitterSizeTimer; KDirWatch *m_watcher; QTimer *m_dirtyHandler; From bdeb2d921b5a2cb7ca87560f20934052f2d913bb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 4 Dec 2005 18:54:05 +0000 Subject: [PATCH 183/245] =?UTF-8?q?Fix=20typo=20produced=20when=20merging?= =?UTF-8?q?=20CAN-2005-3193=20fix=20-Esta=20l=C3=ADnea=20-y=20las=20que=20?= =?UTF-8?q?est=C3=A1n=20debajo=20ser=C3=A1n=20ignoradas--?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M xpdf/JPXStream.cc svn path=/trunk/KDE/kdegraphics/kpdf/; revision=485522 --- xpdf/xpdf/JPXStream.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/xpdf/xpdf/JPXStream.cc b/xpdf/xpdf/JPXStream.cc index 9c9578abf..b7a1f56b6 100644 --- a/xpdf/xpdf/JPXStream.cc +++ b/xpdf/xpdf/JPXStream.cc @@ -825,8 +825,6 @@ GBool JPXStream::readCodestream(Guint /*len*/) { return gFalse; } img.tiles = (JPXTile *)gmallocn(nTiles, sizeof(JPXTile)); - img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles, - sizeof(JPXTile)); for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps, sizeof(JPXTileComp)); From d338feceb5665d16996c6792eadc93dfc845e66f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 6 Dec 2005 16:10:37 +0000 Subject: [PATCH 184/245] SVN_SILENT Correcting the encoding in the source code to UTF-8 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=486043 --- core/generator_pdf/gp_outputdev.cpp | 2 +- xpdf/README.xpdf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/generator_pdf/gp_outputdev.cpp b/core/generator_pdf/gp_outputdev.cpp index 1ea21909a..e8803e02f 100644 --- a/core/generator_pdf/gp_outputdev.cpp +++ b/core/generator_pdf/gp_outputdev.cpp @@ -3,7 +3,7 @@ * * * Copyright (C) 2003 by Andy Goossens * * Copyright (C) 2003 by Scott Wheeler * - * Copyright (C) 2003 by Ingo Klöcker * + * Copyright (C) 2003 by Ingo Klöcker * * Copyright (C) 2003 by Will Andrews * * Copyright (C) 2004 by Dominique Devriese * * Copyright (C) 2004 by Waldo Bastian * diff --git a/xpdf/README.xpdf b/xpdf/README.xpdf index ff674a2a7..2b8b6ce6f 100644 --- a/xpdf/README.xpdf +++ b/xpdf/README.xpdf @@ -197,7 +197,7 @@ Various people have contributed modifications made for use by the pdftex project: * Han The Thanh -* Martin Schröder of ArtCom GmbH +* Martin Schröder of ArtCom GmbH References From a21f78eeacc4e796b4b2a3a90a4c00200e633d84 Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Fri, 9 Dec 2005 12:56:16 +0000 Subject: [PATCH 185/245] fix integer overflow in gmallocn and friends svn path=/trunk/KDE/kdegraphics/kpdf/; revision=487067 --- xpdf/goo/gmem.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/xpdf/goo/gmem.c b/xpdf/goo/gmem.c index 00cbbda27..1a9c4f008 100644 --- a/xpdf/goo/gmem.c +++ b/xpdf/goo/gmem.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "gmem.h" #ifdef DEBUG_MEM @@ -141,7 +142,7 @@ void *gmallocn(int nObjs, int objSize) { int n; n = nObjs * objSize; - if (objSize == 0 || n / objSize != nObjs) { + if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { fprintf(stderr, "Bogus memory allocation size\n"); exit(1); } @@ -152,7 +153,7 @@ void *greallocn(void *p, int nObjs, int objSize) { int n; n = nObjs * objSize; - if (objSize == 0 || n / objSize != nObjs) { + if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { fprintf(stderr, "Bogus memory allocation size\n"); exit(1); } From 015d60f9a72a771f544172639325dcc4dcde59ad Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Fri, 9 Dec 2005 12:57:31 +0000 Subject: [PATCH 186/245] add missing hunk for CVE-2005-3193 fix svn path=/trunk/KDE/kdegraphics/kpdf/; revision=487068 --- xpdf/xpdf/Stream.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc index cc915f247..ef3a27725 100644 --- a/xpdf/xpdf/Stream.cc +++ b/xpdf/xpdf/Stream.cc @@ -2956,6 +2956,10 @@ GBool DCTStream::readProgressiveSOF() { height = read16(); width = read16(); numComps = str->getChar(); + if (numComps <= 0 || numComps > 4) { + error(getPos(), "Bad number of components in DCT stream"); + return gFalse; + } if (prec != 8) { error(getPos(), "Bad DCT precision %d", prec); return gFalse; @@ -2978,6 +2982,10 @@ GBool DCTStream::readScanInfo() { length = read16() - 2; scanInfo.numComps = str->getChar(); + if (scanInfo.numComps <= 0 || scanInfo.numComps > 4) { + error(getPos(), "Bad number of components in DCT stream"); + return gFalse; + } --length; if (length != 2 * scanInfo.numComps + 3) { error(getPos(), "Bad DCT scan info block"); From 7f14d643a060961914a64120a08ff29eca62c549 Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Fri, 9 Dec 2005 18:26:41 +0000 Subject: [PATCH 187/245] neverending story of integer overflow fixes svn path=/trunk/KDE/kdegraphics/kpdf/; revision=487191 --- xpdf/xpdf/JPXStream.cc | 3 ++- xpdf/xpdf/Stream.cc | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/xpdf/xpdf/JPXStream.cc b/xpdf/xpdf/JPXStream.cc index b7a1f56b6..f8dda64c9 100644 --- a/xpdf/xpdf/JPXStream.cc +++ b/xpdf/xpdf/JPXStream.cc @@ -7,6 +7,7 @@ //======================================================================== #include +#include #ifdef USE_GCC_PRAGMAS #pragma implementation @@ -820,7 +821,7 @@ GBool JPXStream::readCodestream(Guint /*len*/) { / img.yTileSize; nTiles = img.nXTiles * img.nYTiles; // check for overflow before allocating memory - if (nTiles == 0 || nTiles / img.nXTiles != img.nYTiles) { + if (img.nXTiles <= 0 || img.nYTiles <= 0 || img.nXTiles >= INT_MAX / img.nYTiles) { error(getPos(), "Bad tile count in JPX SIZ marker segment"); return gFalse; } diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc index ef3a27725..931354978 100644 --- a/xpdf/xpdf/Stream.cc +++ b/xpdf/xpdf/Stream.cc @@ -15,6 +15,7 @@ #include #include #include +#include #ifndef WIN32 #include #endif @@ -403,8 +404,6 @@ void ImageStream::skipLine() { StreamPredictor::StreamPredictor(Stream *strA, int predictorA, int widthA, int nCompsA, int nBitsA) { - int totalBits; - str = strA; predictor = predictorA; width = widthA; @@ -413,18 +412,19 @@ StreamPredictor::StreamPredictor(Stream *strA, int predictorA, predLine = NULL; ok = gFalse; + if (width <= 0 || nComps <= 0 || nBits <= 0 || + nComps >= INT_MAX / nBits || + width >= INT_MAX / nComps / nBits) + return; + nVals = width * nComps; - totalBits = nVals * nBits; - if (totalBits == 0 || - (totalBits / nBits) / nComps != width || - totalBits + 7 < 0) { + if (nVals + 7 <= 0) return; - } pixBytes = (nComps * nBits + 7) >> 3; - rowBytes = ((totalBits + 7) >> 3) + pixBytes; - if (rowBytes < 0) { + rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; + if (rowBytes < 0) return; - } + predLine = (Guchar *)gmalloc(rowBytes); memset(predLine, 0, rowBytes); predIdx = rowBytes; From b3ebca87cf132178d21af72a80b2a8af7f7b7a3e Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 11 Dec 2005 21:01:08 +0000 Subject: [PATCH 188/245] Forwardport r487750 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=487758 --- xpdf/xpdf/Page.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/xpdf/xpdf/Page.cc b/xpdf/xpdf/Page.cc index 3f035c452..66d47630a 100644 --- a/xpdf/xpdf/Page.cc +++ b/xpdf/xpdf/Page.cc @@ -66,6 +66,13 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { if (!haveCropBox) { cropBox = mediaBox; } + else + { + // cropBox can not be bigger than mediaBox + if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1 || + cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1) + cropBox = mediaBox; + } // other boxes bleedBox = cropBox; From 2f3ede9e28b8c0fb06e450042119d8801aec08fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0smail=20D=C3=B6nmez?= Date: Tue, 13 Dec 2005 13:44:45 +0000 Subject: [PATCH 189/245] backport my menu name fix svn path=/trunk/KDE/kdegraphics/kpdf/; revision=488172 --- part.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/part.rc b/part.rc index b1352ce61..4a3bdade6 100644 --- a/part.rc +++ b/part.rc @@ -35,7 +35,7 @@
- &Tools + &Tools From 4c0cf35355b6b45cf34ef0f97270be3f613ed0d4 Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Tue, 13 Dec 2005 16:45:56 +0000 Subject: [PATCH 190/245] protection against the newest xpdf exploits of the day svn path=/trunk/KDE/kdegraphics/kpdf/; revision=488233 --- xpdf/xpdf/JBIG2Stream.cc | 33 +++++++++++++++++++++++++++++---- xpdf/xpdf/Stream.cc | 15 +++++++-------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/xpdf/xpdf/JBIG2Stream.cc b/xpdf/xpdf/JBIG2Stream.cc index c190aba47..128fe1d5b 100644 --- a/xpdf/xpdf/JBIG2Stream.cc +++ b/xpdf/xpdf/JBIG2Stream.cc @@ -7,6 +7,7 @@ //======================================================================== #include +#include #ifdef USE_GCC_PRAGMAS #pragma implementation @@ -681,9 +682,15 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): w = wA; h = hA; line = (wA + 7) >> 3; - // need to allocate one extra guard byte for use in combine() - data = (Guchar *)gmalloc(h * line + 1); - data[h * line] = 0; + + if (h < 0 || line <= 0 || h >= INT_MAX / line) { + data = NULL; + } + else { + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)gmalloc(h * line + 1); + data[h * line] = 0; + } } JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): @@ -692,6 +699,12 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): w = bitmap->w; h = bitmap->h; line = bitmap->line; + + if (h < 0 || line <= 0 || h >= INT_MAX / line) { + data = NULL; + return; + } + // need to allocate one extra guard byte for use in combine() data = (Guchar *)gmalloc(h * line + 1); memcpy(data, bitmap->data, h * line); @@ -720,7 +733,7 @@ JBIG2Bitmap *JBIG2Bitmap::getSlice(Guint x, Guint y, Guint wA, Guint hA) { } void JBIG2Bitmap::expand(int newH, Guint pixel) { - if (newH <= h) { + if (newH <= h || line <= 0 || newH >= INT_MAX / line) { return; } // need to allocate one extra guard byte for use in combine() @@ -2305,6 +2318,15 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); return; } + if (gridH == 0 || gridW >= INT_MAX / gridH) { + error(getPos(), "Bad size in JBIG2 halftone segment"); + return; + } + if (w == 0 || h >= INT_MAX / w) { + error(getPos(), "Bad size in JBIG2 bitmap segment"); + return; + } + patternDict = (JBIG2PatternDict *)seg; bpp = 0; i = 1; @@ -2936,6 +2958,9 @@ JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h, JBIG2BitmapPtr tpgrCXPtr0, tpgrCXPtr1, tpgrCXPtr2; int x, y, pix; + if (w < 0 || h <= 0 || w >= INT_MAX / h) + return NULL; + bitmap = new JBIG2Bitmap(0, w, h); bitmap->clearToZero(); diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc index 931354978..63c965db6 100644 --- a/xpdf/xpdf/Stream.cc +++ b/xpdf/xpdf/Stream.cc @@ -418,7 +418,7 @@ StreamPredictor::StreamPredictor(Stream *strA, int predictorA, return; nVals = width * nComps; - if (nVals + 7 <= 0) + if (nVals * nBits + 7 <= 0) return; pixBytes = (nComps * nBits + 7) >> 3; rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; @@ -1277,7 +1277,7 @@ CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, endOfLine = endOfLineA; byteAlign = byteAlignA; columns = columnsA; - if (columns < 1) { + if (columns + 3 < 1 || columns + 4 < 1 || columns < 1) { columns = 1; } rows = rowsA; @@ -2923,10 +2923,7 @@ GBool DCTStream::readBaselineSOF() { width = read16(); numComps = str->getChar(); if (numComps <= 0 || numComps > 4) { - error(getPos(), "Bad number of components in DCT stream", prec); - return gFalse; - } - if (numComps <= 0 || numComps > 4) { + numComps = 0; error(getPos(), "Bad number of components in DCT stream", prec); return gFalse; } @@ -2957,6 +2954,7 @@ GBool DCTStream::readProgressiveSOF() { width = read16(); numComps = str->getChar(); if (numComps <= 0 || numComps > 4) { + numComps = 0; error(getPos(), "Bad number of components in DCT stream"); return gFalse; } @@ -2983,6 +2981,7 @@ GBool DCTStream::readScanInfo() { length = read16() - 2; scanInfo.numComps = str->getChar(); if (scanInfo.numComps <= 0 || scanInfo.numComps > 4) { + scanInfo.numComps = 0; error(getPos(), "Bad number of components in DCT stream"); return gFalse; } @@ -3070,12 +3069,12 @@ GBool DCTStream::readHuffmanTables() { while (length > 0) { index = str->getChar(); --length; - if ((index & 0x0f) >= 4) { + if ((index & ~0x10) >= 4 || (index & ~0x10) < 0) { error(getPos(), "Bad DCT Huffman table"); return gFalse; } if (index & 0x10) { - index &= 0x0f; + index &= 0x03; if (index >= numACHuffTables) numACHuffTables = index+1; tbl = &acHuffTables[index]; From 8a1ea7da159c255a1231eaf27162f152a81ffd4d Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Thu, 15 Dec 2005 15:36:09 +0000 Subject: [PATCH 191/245] new round of xpdf fixes svn path=/trunk/KDE/kdegraphics/kpdf/; revision=488718 --- xpdf/xpdf/JBIG2Stream.cc | 16 ++++++++-------- xpdf/xpdf/Stream.cc | 11 ++++++----- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/xpdf/xpdf/JBIG2Stream.cc b/xpdf/xpdf/JBIG2Stream.cc index 128fe1d5b..9354d69a3 100644 --- a/xpdf/xpdf/JBIG2Stream.cc +++ b/xpdf/xpdf/JBIG2Stream.cc @@ -683,14 +683,14 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): h = hA; line = (wA + 7) >> 3; - if (h < 0 || line <= 0 || h >= INT_MAX / line) { + if (h < 0 || line <= 0 || h >= (INT_MAX - 1) / line) { data = NULL; + return; } - else { - // need to allocate one extra guard byte for use in combine() - data = (Guchar *)gmalloc(h * line + 1); - data[h * line] = 0; - } + + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)gmalloc(h * line + 1); + data[h * line] = 0; } JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): @@ -700,7 +700,7 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): h = bitmap->h; line = bitmap->line; - if (h < 0 || line <= 0 || h >= INT_MAX / line) { + if (h < 0 || line <= 0 || h >= (INT_MAX - 1) / line) { data = NULL; return; } @@ -733,7 +733,7 @@ JBIG2Bitmap *JBIG2Bitmap::getSlice(Guint x, Guint y, Guint wA, Guint hA) { } void JBIG2Bitmap::expand(int newH, Guint pixel) { - if (newH <= h || line <= 0 || newH >= INT_MAX / line) { + if (newH <= h || line <= 0 || newH >= (INT_MAX - 1) / line) { return; } // need to allocate one extra guard byte for use in combine() diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc index 63c965db6..e09957391 100644 --- a/xpdf/xpdf/Stream.cc +++ b/xpdf/xpdf/Stream.cc @@ -419,8 +419,8 @@ StreamPredictor::StreamPredictor(Stream *strA, int predictorA, nVals = width * nComps; if (nVals * nBits + 7 <= 0) - return; - pixBytes = (nComps * nBits + 7) >> 3; + return + ixBytes = (nComps * nBits + 7) >> 3; rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; if (rowBytes < 0) return; @@ -1277,8 +1277,9 @@ CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, endOfLine = endOfLineA; byteAlign = byteAlignA; columns = columnsA; - if (columns + 3 < 1 || columns + 4 < 1 || columns < 1) { - columns = 1; + if (columns < 1 || columns >= INT_MAX / sizeof(short)) { + error(getPos(), "Bad number of columns in CCITTFaxStream"); + exit(1); } rows = rowsA; endOfBlock = endOfBlockA; @@ -2924,7 +2925,7 @@ GBool DCTStream::readBaselineSOF() { numComps = str->getChar(); if (numComps <= 0 || numComps > 4) { numComps = 0; - error(getPos(), "Bad number of components in DCT stream", prec); + error(getPos(), "Bad number of components in DCT stream"); return gFalse; } if (prec != 8) { From 0c66afa310f2e26edc7c347a043f60b5d6b31088 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 18 Dec 2005 21:45:42 +0000 Subject: [PATCH 192/245] Fordward port 489480 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=489482 --- xpdf/xpdf/Page.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/xpdf/xpdf/Page.cc b/xpdf/xpdf/Page.cc index 66d47630a..0d7ce873c 100644 --- a/xpdf/xpdf/Page.cc +++ b/xpdf/xpdf/Page.cc @@ -69,9 +69,16 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { else { // cropBox can not be bigger than mediaBox - if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1 || - cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1) - cropBox = mediaBox; + if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1) + { + cropBox.x1 = mediaBox.x1; + cropBox.x2 = mediaBox.x2; + } + if (cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1) + { + cropBox.y1 = mediaBox.y1; + cropBox.y2 = mediaBox.y2; + } } // other boxes From 45b5011d478b88559a035dbfd7c1be8a23455f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burkhard=20L=C3=BCck?= Date: Fri, 23 Dec 2005 11:25:55 +0000 Subject: [PATCH 193/245] kpdf documentation update by Titus Laska svn path=/trunk/KDE/kdegraphics/doc/kpdf/; revision=490836 --- doc/configure.png | Bin 0 -> 11240 bytes doc/index.docbook | 460 +++++++++++++++++++++++++++++++--------------- 2 files changed, 308 insertions(+), 152 deletions(-) create mode 100644 doc/configure.png diff --git a/doc/configure.png b/doc/configure.png new file mode 100644 index 0000000000000000000000000000000000000000..bbe89d9f24243b9f9a15875a29b047bf67144269 GIT binary patch literal 11240 zcma)ibyQr(PUxVgAAa4eb${y0W$m8amn|0QwW0$M}T!U{Ww86$K*`1B4U8`+|r0MN;Z>{33iz zu)Ko=RALwltqTut0}V5okzQ6_wuzYJ5DhJkl_!9ghhDj~n2z-d4bA7J2*3C!k%hII zhMI$v9Q*4yUd0)2sHC=z7VUdhh|UUiAehy-*g1o6Ny}72g?a>qjLrRcoGPW>!!0c>gx|Jl z+J=V1joz92b2uDsiV|dNTB=$s3A)$Y+Pw|7v^*AgRjQ};()Bb7;mPm&UB@HU$;Fwm zlu0O{Ps^iO!=nfBZb2;ghd6RjAncd1U-t7h;*Uw09uk<(_bD_%ZcvpO2kkaM}n zpW-odE#_uQQ9o8+i<(5BPBk=T;+N;GdCX#}0z)H^p}~lRANomSW!~?vYzWp|z=1iu zYqpAkL5sWgkcgNM!@k_nu~GBy-olcvEfd$8y}cyALlNmy&L5lm1GL6H+)E=OjkDJl z!-0v(3BAGgZ*r#3?d-fh``F|yo8;Z={?NVkf3Xo{mXVo}ke3%x*#0{VUYnM7;vcvc z8oChcxtxccUsMqCb!sI;+PnPTV$%HfgX(s&{X+KJ&*h(+OFkz5&|doZF}-H!S58(` z{e9o(FH@xv7pW=5)dw}-z6GuXH?=gTPh_99uw-@K{;DtTY-ztK_c`xFtLmP-`dqr( zkhb1X-_!TKyMOR-k_a_$x75)-&_8rGBGtC=VPNRT@sREB0c7cR$&F|{zU$bNL{o^xpBMW0wGn3~B;Q5)wpIbF|tHuK> z_e%>a3rq8JD{BKs1FOsH2lI>jD?=A66&LeU8*5u@8>{y_5wqL3%LjuOf8KBHY_9HH zOscAMWiO+#lud{oeU~xW9Wge}B@re{yzmbas4txOaAUak72(=j8nI&(-C@ z{nh%}_1)e5&92rHyN8rOH&v38MhgQ_%0Jv-JIKSG(a?a;|GLo8(lSUMgil-)RAin^ z;5;FC`Z8KqE%D1`zIE|zwNb0tBG7}Gbg8Qrk`LUuk*m^pRK6Uaz;@T zCuC%$pULA*a;{3OU8Gz&j7k>1Q`om{4~T8Z?SXQ=O(cKqR6qu_*BpO*!~uN+#y?S5 z7PI{MDS_)pf>LpUva{=cljjSv7H3{E(aTTWk<-psCEau31KfCc_@@avm69II1?u{= zA=4mA+tPAITt0|pZdV!K+%QE}U1}M@`rT1#1r<=>_rOOF$zPMhODC32rp}il2641s zKN@5@sPs)#e+Uo$n76s9=GT$I43Q?CbBhEGzJ1kaJJm*^ADsTK6KWavPOLT-HelCQ zayp}H7)|)5gSjOQVCleA%T%V~86jxI!QFmNccFDQnm@{9ylX| zyh>H)o~biyc_B2DApqeEQ|BHf&94uSHtx#oHz!=@C38rxJWxQ-2q*pmA|QZ;$<__N zT~d}iT^k_HznH)AmA-WNY|}i|Yw-N**Y#r}$oQLNt;!`_JlrN*s#XNTA*!C&_$n-f zQ3M!iF*rEu8H4Qh4vFK3MDV^)Smi&2V5!@N@v2p@+x{G;m+=eUmy)_WCDbH8QOQUJ z{NgN|v@}5=dTzG!Vlkg^8XJ5BbC<l5c4&S{Thz6Q?uFtScpQgpVJ zJCI(CRg%Wi1V_!Kn1eA{-lSNg+BPeG1%>7$&l`RZJebOWzrMb?TTtWbd(M%`6VyES znm0BdFEV)vd0`5!nNS&^QJr?`cwFmJQ_5K>KJ;}x0!0d|!HevU5-~L?i~t;^X=e85 zQCB&f#Ww|*P`%xEJXvue^h%E8atr7QxSbl}f_Eja3P5a@&NV6I zGb%_nxysk;#+~wl8I|6U9|t2n@7v#QDEnGaWeI4-(WxnJu);}Z18azXEca7`I62%X zrcn7T43#u*7UE7YK`mdj*Xw}td(+Kpvof^N{8Ua#9OwY41IQ!K8yC3?uyk1Sm8NkVG2>77Ps?NP|Gfg!un0?0*bY zeVx1({J7TId8B;jlgQBEXFJbGPNU#!W3H zf+~&v1nwJS)!3dk;x@d&dc~;}szki<5Y+XU}4VRuaqMgCw=!`UO9{44TuyLe% z+q=hF5VvkVxzuneP0MoWrIWQ)z2u#)1vn6csQO!-NaVhmqJyzX=$~PKLu>sR6DqDM z+&b4Xl?Bdm)GAuy_k=Jif`Vi$x8<(s0OL(1U3GDW%=^eKKr`YU#7doT298!-XrF^N_ovh_pHUAJ+UIRN^G2gww zVk~~2=Rny$Y4w$bmDOGH+G<4zgFHk<$9M^LvEp%p=L}}D2fI9*(ydLBw*isD=&f0V1BMAjq26sl&xm!3u~s_kO3kGMDpFitlopYg9y z1+35x!tdR|c}m7)DiTV@W#D&) z*8K)?*uJgQqgP9fJtlX5dCXq=z5NzxS_NFa^Q2iie{%KM$WUL$qFjGBJ8*pT_4k41 zrk&%Q4z$1AC-G7;rXkqc-JRm|?Ekb{WP7&qq4UG*?}ML&hrGK-5NM6+G;TSbw)Ff! z5@f+fbk#=s>?ds+2}&CZ;X0e;-hNsmWi%kt1e_-K`jMFNVoZ$S>q$3l(Qm}=V50R} zQ&8GQOop%F^C=``#k`@6E-w>+5DQ>VS5OFI^Cby}rl%97QFNyPmPr4ZUjV3_%hjW<4Ll5j?qj7XI+u z?u}v(XWaB>V!L^LN?0$-@S@-1b#qzFpR1YMDNX`1Zs6Rzo{bHcJq$Y$V>3Zi9GBa2 z?GK7?XQI*z{M4by;fd67{3L8xHY;z|yd{)R$Ba9U^>;uxqilNIc12<~4z;h@OOpMI z^|-nQRA}6aK?-3A)5j`cU9{sLD$)0Ay&v+LefB-@n0@Z(6)GGQ8vU78Hp=TRyot{Y z-bi{|me4PK%?eu_2k0vuepVg|^u~{;o3TUlt5=>uj%G16tVFPvw_H(wy^|~RYv_J+ zT{K!U3%KLas64{hePwkzQa#&SK-FdS3=n4jg_@i|{H-(tXw55*XgaFwbrfFWRsh^) z&iLE!h#vsM0KJ|lazUrPsS5hd!Z+ZI+SI3+&SAL6lp%5P%6gvIn*uUQTs+~^o#R+m z&4onV`Hp@$Hp?CLWcsN)HvsZ4gU~2LnvaEUek0VeNRq}S4&*45g2bf)*dU(5NCo6s z1;pE+v@)@eU}2P89!g(EewS2mLxwHFdmd^?2Z9)eN{=hi2?G3D)m;_pc*4C_Vi?9Q z@U0J=ZaAX*Y0;`AbmNCvV;lGTX{4@HUl$smarqPyFZ6NlXuHuT7%bC;8oi&i5oN-C zH5Y<6dlk~d>F?CXNnw@wT=%bO8NWhhkb5-XT`9%fU1;jo(h=T6noe-y@{(f`rLJDM zhVh*p;SKWy^;6V#)vgbJc!>fcZNRy>?hDS^wlrAWxPHIcoiFZ82=<^Rvw*P%jgSKz z64@74m$fa$Hyl&Q4hk+TT?sO>?;A^Xv)^=3z|OK0Vg7eQN`M!RlmWsRZsr~tjoAcn z^$iq+0;4hRkx<1${k}2dB{A|<$hrphJUP;NL`p6uKoI@ME}zuuf0-Hn#r z&BR7-;^L*4qQ||aT#v)NyYl)umQ^GJmO@ftvC2lDj*gwU6-l755R?0kDY){~OFD87 z9i5}}UcccvT%**LmXaT@2Qs$=cb>R8dP@BR>hN=|PuzVy!O+@drhk_Ei3ceNcBsmo z?c|jVlOVI#LZI8A{41Y6b}jPMns{y$A!8yU+n#RhmebVK#4#3MOqjryKh1OI&o^X&3Jts+=$w^>vRQ zYagcrslgXG53bUn4!J1Ntfa{DF=n8`G;%MvNErd{z{HG#rh@jN&7r~>&zsQS*1rn) zQl4ZdbD`5?$5*YjK$cdk>+$HNtNDgV_h1I|&nZ=W2c5rq?v9KVO#_B|F@TbGZ60ow({tMgFtQ-1FRE=8Nx;|`b2!nb zrexP4Y=J{^6XGAfD`@}<>f@9y(j3YF3z2#*aw(_jB__lk#l3IxPh{2f20JE{i81)H z+6XMawoJz8->nulSd+xcY)&sN-PoHpkCCM1f)Vrpoj^oI1>DQc9lDZwumZHArx{i& zYSMYO8%@^WwRaHZ%#@Ty24E`dgp2nmC)T1$DSo)Iq9f%pw`DT&CGcYN1$BaGmLLe( zga|+oFmPjHf*`69C!beiOSqTkEm14r))Pzt3xT+!z)&YO?FVOjfXDnByXuKQ5$#LK z73y|)9y&jdx{ol7rFE&FwI*tFWtliw4Y65^Wlhu0IrIxOj(~7YNoH;^fPb9KQ6BlL z9LgT&G~j*c+_!i;uJznG{UeVSLqX@v!kursSc1Tt3u6t{Ai&%3rbjH1A7i+TU(3%hW7Mam;ppiCgmAU%V{5z-Z z?4(cmeQxblIq6+%; zFi_85fu({*Y>&>jgyZ>uY`+I4|LkH*@5%s4JU#xf%9!0s7h}A>&pRE`^iMb?(Se! z2t`y2)Fmd|XwO%M5njMOsCG>oMuJGt}`Dd|nZeISbAUdN8^W7<1xn z8JdzClsKG%4$8Egp!N}xz4k|%Gy^C%F9-HwwbtzN7a$_vD;y5#eh%AYMIoKrI=J81 zXKcRcxl=D82gaJX$_?`r)$jKD#D>2odx+A0_yZ;{IzK%`#QTHH@{(BLHBZf$Ir>fE zST)cwb2vj1MCE(24ZNoERqo&QO`S9=`e{o0VKI@#CHy>PA#R6haIpSV>GHDXe26Ix zS%YXVn_m5{LMrTbI>j1;dq$X5Ph2&kqTl-Zf{>2PCrWC$yiwJUY2Q z=xg_>gGa=4VEjd5S>&;ofui82r=gwO{Ua0t105>vGFdH3g+G-A(idE`W*}WxDvUye zu2!_mg>zOWTVvtKbWYXA$oex~Qs7ta(NOzlSF+@%ZnWR+6-780?-|9QVPjtv9MW=K zT|DBOs^Ut=q^YS_Q)G^o)z>U=LXa#r7wL8lNfRp9S9wp0DjIgp)Bdud013NOG7Tm` z8Ye9A5m(XTg);XE154OcZjRVmAdDIvuA36%YkkR7;T`{Z7_}R@cXe>r9 zh}hgC?KV2jndeJqJ!sK^n!yAzW~oj3c@2D&nbHSkN|o6c9!bW@*5D=pzZ(NYd3TX3 z*WraFVr)>^<$my$U`eNI@R&VYGJq8t*6~-UBBtYFIuo}3Hhc4zSw5qM1nT3yXqqy6hF-%E!H4R(CO7E(IDi9*BDe zm|Qg;#N{|l2>djY{JKaV;uQuunHB^;m0<>z@7*sXWt2B~jwLDXFW$3We9{a;W&lHT z!9e#g?qZjT^DAa_po|Ot`_3di->OFA*Vpzf$0u#jBNX@HnHuBBrk6i*#e_Ctc;z39 zUl^H3r;< zORA8c$A&|OiG0X4DJ2nRpxOTsEm(1<11G)hj(bTagkV*wpbctNDe(a$Ejf453)MJ- zno7Bvu)nb&p?3;41hKBCwTKzSmXY}c0}f2-U;86P%yaO_0lJWg9+TJ>3Q$qgbG z-J4pts9oABnI}!f-PXYfKRk*4ZKWs}q|P>l^dCvHBcE;XPMhLH(T_F|-4>2T3jiSb zJ%M;CT|dHmLxh1q;xcf&uC`QYhKDzIJEdcSC0Mh3n!Gc5=O_^UQZOv;g-mOS%c=@G zaJxc11T}9(Q5@CiZw*eUR*}scbIMJpbqH7+Ozax+&-NZ^; zO+;=P;g>0*sqCOFof;1a#sF2i;m-_`r6t}J#)k_q21n2==j{}f46&#Nv%)1<5VWr$ z>K468(H>e*EK>e~#5Ih7m49k>WAIj6F)t*FR41;HA^$1H;rLrpYp5=l>O>NN?1&Oz z#OEjwHBx`jyOcu*B0=_wRQih7LQp~z#SLlzWQ_tyV2=aqJv|`AqSIU_|Hr1t!%C{J zqmlAtP`V9TQAOZu)8lh4dODK)P;*VKXpesvZX3_vt&rQ>qJttbkcZ*h#)fVecx4<( zZBUIWf`zJ$77lTGmZl2=l=?VCTD7d+`Ny)rLKno=&sqqj-USI>{B+#A00fI&?52m} z8+&ciKYXQ?1PhHDIrkzr8|hZVO-Cz#w%@9v0lRykYd6#G;YPk|s(~Hp%&L?NPK%$s zIvx}%9DIk>sAVP2c6xZFjehZ>Hw$Nq-W1tG?%TsRg;!;Cs)l;ol?k_BaLBY^J~*8dMx6@IwmqM;~fS z^vm){=E1rZiRd0w(O0W-MDvDCAW~t2l<~cC_?ZJwwg6*=Bx};FD*Sx~L5usJal>@D35boIU9Y^!XJAA)O!-2k530nPtK27&CmqY`Das2n ze*h@{p8!G?4tF}waGZaoewbWn@m$}}lk;<3e^|Tz%CvAXp_OT6gR}2Gn>#==)&0eT&Cv36Z1--a2DyylI<$PUpIrEmQ(PzEiQ2bhL z9wt9%uL!b|CbUr8AT2mdjrY{-iv*&}C8l?wG2EQOTQq6IpKGzzeX2ZdZbcz>N(Vo4 zHty-qsWcT+16i+By3GQTMe>NKw8-2fliBtHPvd1GSJ+({Vpx+p9|BN$c!Y1IW>{;x z*30$IsNORr29m!eP|%J+j{6UL(27+6yp)7Xp6g#CcU5sXMBeCrk7yq+`Ie6O%28)O zI?S2B_W!Dy?y~YsRm0T{$q2lm}yixC9p&2pITk=_VzC}?DbUbIzR%fbc5rm9& zKbX5rarfo197rwsQ5e&eY%*CHdTL^l>Ki-Klf$<8&?^8LyXft*`Ih>2{Swf6v7AyE z^AY)#iC^v0?T)7?toQA@fpQ51bvU#vXMBB_*V=T{DUf+T76<@x13z1Gy&~s)4~jUV zI!$lP^4@R87r)xdTfF=8?9u@6LV;eAJs%{nWhF<@p%KA`22*xV68RIo*}hJFw&i(u4N^i!*c< z%a@(2QzniX`MUg{5QerY@-u>c@8m zm?9+GpcEhyvLtRzTTO-t6I&)YRUJftmOfl@Jc1lK^_;&dQM)L@F)eU0@yAv+g{&SF zw3R(+xfF5n#o`qQ^MV>NON*g|jNPkvQ(Ac#fms4w*GnF$W3tY(UZ(Y$dcrpr^l?18 zYTrIhJ+JJOT!EFEWfU$6SlDz%@<*N)yASd7+0(Qrnzz>#40fpLGFbWe2&>HQ61hok zpdmfJvMsD*V>_>R%l$Yh*8xz(vh|6X=0f;cO@jz4A*uNzK?X)Ff%pYee$sIPvqZFl zJ0wM{7b+El`!D2aX*_!Jh1l&NkuFA6GGT@^&V`~D?TC+ZeSvFejHiUT?8L^3xPtB1 z>ckErrEA|~URFN=W;Y#_%pAekZ?^K0p=a_x?5j2O8j5umB9CMi&t zpP@u067a|gxkC&o{yTJx(O}HRwyd&pC#z`NJ?1EI(|0tJ-0H*@24GsbwrsbnOwRW_ z#Y_MXe@PTFOs6SEy=n;}Qz{0fT;&6_vTh4ODYzVB6kKHLwVGlMu_pr#k-v(jeuMeIR`3BwJo&LICJrzT#n?n%Jhv{{_ zyBzIQHxHSo3QAQIyKKxqU%#S8xTndM(E7Wd z#g|SJnz`OC>Xm1Z!-`ygWLYJ_&E8Ai+gDu`5*k8NfTYF5N%>KJ^Um7#&!^70J9rGH z{!6RU&I#+DjWn1(7#5jG>iZuDcT8KuyJEYm@53anAl6;!P9w=_*wxJj>zm`S<+Diz zG1WlHrJ~wn$t(#tV);m1>HTfhY^GOwDu5Cec9#C;lLUD)6YtMYNn4xdYtiTjtNG@V zSXY=2Y)tF*Y?g74(BZ&~VTy~r=&WmHd>)_>>S2uQFTV9}I|(>uX#E-u<-hgA0uE1-aBkkqD;Ik=h0 ze86J!-N1|8mYSFmhe6dcIlXHa1nn>T2s^2#GcjS#Q60kyBwW^&G*`L-yu%%JRDQQ@ ztEoXf_yi!|`#$C@?~ARfhAAXTYl%Ot#I;hdOhCtQcGO*owX1W3;aGC7 zK$(L6_f+Dj-)WPm%q~d&wHGGK0SxQ0Uz6SZi&!&JsXIqV)5F#|J&^DA`t2`;s}#R` z#?idtu{P*v1pyAg(D?3H{3eU*Ubx8kK4PoSN@^JkrS1X=hK?VR-5$sl`n134~B9mZd}{hi#2M`n#X;?Ag1vx04O2~pqg{?Icse~ zv5X?n0}Tz!^slo3RVs5^=&dCy=Cl-I_mNhDHJVdwxTF9?4jPW zlE>=F1rF*1j39|l_P+_ckN_km;lrMpw+XFL@ffW@Bjgwh6?Xu!4rNn`2W-*f1OYg; zS*dyCvG{h_xL8dd0a)o$lN*Aapv9V=*|ai z!!mn)qq=FaW)7JQLMxOc=NYW`>qB`ah}OpCdn55wyt9}tRo2{ug_K9Tq%DvRWg`uF z3|X6)`T*2nYg)gGcxJmnxr0^s4A`$;plpkcpyj&8nvNi{=G&{K%@YbN8NYaV@TT!$ z+-N}4>{0CBSmYfBr0t17O+_Jm9&Oh1vmE&5VqDgT+5&Vav|>qoDu?b zOVFy=w>AY~P~m^U2dbJ~mkfn}L@X3y?)vY67679%6ai>Po5dgk@Kt=NhkQ<~ZdR#pEG(T) zUfmHkVx1WQ;v~l3!gA-{gg+BGvhGJK`(NJJ(W}*^#6Pbxl zAJa)$p?`{}WO0(<j4^V);jwvxLR;fyQ7ZDI&T2ZKhXN~+5 zBJ3|ZL0{<;dqjToOqeh4XXaqrSVTZ@Ym#%=1Yoby5@Q(l=)e6cq_<=0;!Xw97H|W_ zY^hgJhi)M;+v;$MK+ZmB3O_K7n4zG2&Rp^)mT@pJ9sKsm6fXS4D{z?sCV#f%X7P*D z#iF0nWxd7_>&+CPJ&8LRP&eCyS%mfS?L=k4wgjg;sv_re58(8M7139#OdhY{vU(BvN9 a1LU%||4e5s?>rnvL{pGal`e-O0{;&(uI>E* literal 0 HcmV?d00001 diff --git a/doc/index.docbook b/doc/index.docbook index 8a41b7ae3..2498d7615 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -18,11 +18,18 @@
tsdgeos@yahoo.es
+ + Titus + Laska + +
titus.laska@gmx.de
+
+
&FDLNotice; - 2005-02-20 - 1.0 + 2005-12-10 + 0.5 &kpdf; is a &kde; PDF viewer based on xpdf code. @@ -35,91 +42,162 @@ Introduction - &kpdf; is a &kde; PDF viewer based on xpdf code. Although being - based on xpdf code, &kpdf; has some unique features like continuous - mode, presentation support, etc. - - - Navigating - This section describes how you can navigate a document in &kpdf;. - - You can scroll up and down the viewing area with the - Up Arrow and Down Arrow keys, using the - mouse wheel, pressing &LMB; and dragging while in normal mode or using - Page Up and Page Down keys. - - - If you click on a page thumbnail the viewing area will be brought to - that page. - - - If the document has a table of contents, clicking on a table - of contents item will bring the document to to the page linked to that - item. - - - If the document has links in it, you can click on them and the view will - change to the page it links to. If the link is to a web page the default - browser will be invoked. - - - You can go to the first page of the document using - &Ctrl;Home or - using - - Go - First Page - . - - - You can go to the last page of the document using - &Ctrl;End or - using - - Go - Last Page - . - - - You can go to the next page of the document using - Space, the Next Page Toolbar - button or using - - Go - Next Page - . + &kpdf; is a &kde; PDF (Portable Document Format) viewer + based on the code of the xpdf application. Although being based on xpdf code, &kpdf; + has some unique features such as continuous mode and presentation support. - You can go to the previous page of the document using - Backspace, the Previous Page Toolbar - button or using - - Go - Previous Page - . + The PDF format is widely used for publishing documents that are + mostly not meant to be edited again. &kpdf; is only a viewer + for these files and therefore it doesn't provide any functionality + to edit or create PDF documents. - - Presentation Mode - - Presentation mode can be enabled in - ViewPresentation. - It shows the document in a page per page basis. The pages are shown with - zoom to page, that means all the page is visible. To navigate between - pages you have to use &LMB; (next page) and &RMB; (previous page). You - can exit presentation mode using ESC key. - - - Presentation mode has a few configuration options, you can find their - meaning at Configuring &kpdf; - + + Using &kpdf; + + Opening Files + + To view a PDF file in &kpdf;, select FileOpen... + , choose a file in the dialogue and click Open. + As long as you selected a valid PDF file, your file should know be displayed in the main window. + + + If you have already opened files in &kpdf; before, you can quickly access them by selecting them in + the FileOpen Recent menu. + + + After having a file opened you probably want to read it and therefore navigate through it. Click + Next to learn more about this. + + + + Navigating + This section describes how you can navigate through a document in &kpdf;. + + There are multiple ways of scrolling the viewing area. One is to use the + Up Arrow and Down Arrow keys. You may also use + the scrollbar, your mousewheel or the Page Up and Page Down + keys. + + + Another way is to hold the &LMB; down at any place on the document while dragging the mouse in the + opposite direction of where you want to move. This procedure only works if the Browse Tool is + enabled, which you can select by choosing ToolsBrowse Tool + . + + + The navigation panel on the left side of the screen enables two more ways of navigating + through a document: + + + + + If you click on a page thumbnail the viewing area will be brought to + that page. + + + + + If the document has a table of contents, clicking on a table + of contents item will bring the document to to the page linked to that + item. + + + + + Some documents have links. In this case you can click on them and the view will + change to the page it links to. If the link is to a web page the default + browser will be invoked. + + + Additionally, you may use the following functionality to quickly move to specific places + in the document: + + + + + You can go to the first page of the document using + &Ctrl;Home or + using + + Go + First Page + . + + + + + You can go to the last page of the document using + &Ctrl;End or + using + + Go + Last Page + . + + + + + You can go to the next page of the document using + Space, the Next Page Toolbar + button or using + + Go + Next Page + . + + + + + You can go to the previous page of the document using + Backspace, the Previous Page Toolbar + button or using + + Go + Previous Page + . + + + + + + Presentation Mode + + The Presentation mode represents another way to view PDF documents in &kpdf;. It can be + enabled in + ViewPresentation. + It shows the document on a page per page basis. The pages are shown with + zoom to page, that means all the page is visible. + + + + PDF documents can even specify that they are always opened in presentation mode. + + + + To navigate between + pages you may use the &LMB; (next page) and the &RMB; (previous page), the mouse + wheel, the arrow icons that appear as soon as you move the mouse to the top of the screen, + or the keys specified in the Navigating + section. + + + You can exit presentation mode at any time by pressing the ESC key or clicking + the Quit icon appearing if you move the mouse to the top of the + screen. + + + Presentation mode has some configuration options, you can find their + description at Configuring &kpdf;. + + The Menubar - - The <guimenu>File</guimenu> Menu + <guimenu>File</guimenu> Menu @@ -133,7 +211,8 @@ - Open a file. If a file is currently being displayed it will be closed. + Open a PDF file. If there is already an opened file it will be closed. + For more information, see the section about Opening Files. @@ -147,9 +226,10 @@ - Open a file selected from a combo box list of - recently opened files. If a file is currently being displayed it - will be closed. + Open a file which was used previously from a + submenu. If a file is currently being displayed it + will be closed. For more information, see the section about + Opening Files. @@ -162,7 +242,7 @@ - Save the currently open file. + Save the currently open file under a different name. @@ -190,8 +270,8 @@ - Shows a preview of how the currently displayed - document will print with the default options. + Show a preview of how the currently displayed + document would be printed with the default options. @@ -204,7 +284,8 @@ - Display some basic information about the document. + Display some basic information about the document, such as + title, author, creation date, and details about the fonts used. @@ -222,9 +303,8 @@ - - The <guimenu>Edit</guimenu> Menu + <guimenu>Edit</guimenu> Menu @@ -235,7 +315,8 @@ - Finds a string in the document text. + Open a dialogue that allows you to search for a string in + the document. @@ -248,14 +329,13 @@ - Finds the previous searched string again. + Try to find the previous searched string again in the document. - - The <guimenu>View</guimenu> Menu + <guimenu>View</guimenu> Menu @@ -266,8 +346,8 @@ - Activates the presentation mode. + Activates the Presentation Mode. For more information, see the + section about Presentation Mode. @@ -303,8 +383,9 @@ - Changes the magnification of the document - view so that the pages width fill all the view space. + Change the magnification of the document + view to a value that makes the pages' width equal to the document + view's width. @@ -315,8 +396,8 @@ - Changes the magnification of the document view - so that the pages fits completely on the view space. + Change the magnification of the document view + to a value that makes at least one whole page visible. @@ -327,7 +408,12 @@ - Enables the continuous page mode. + Enable the continuous page mode. In continuos mode, + all pages of the document are shown, and you can scroll through + them without having to use the Go + Previous Page and + GoNext Page + options. @@ -338,14 +424,14 @@ - Enables the two page mode. + Enable the two page mode, which shows two pages of + the document next to each other.. - - The <guimenu>Go</guimenu> Menu + <guimenu>Go</guimenu> Menu @@ -356,7 +442,7 @@ - View the previous page of the document. + View the previous page of the document. @@ -368,8 +454,8 @@ - View the next page of the document. - + View the next page of the document. + @@ -404,38 +490,37 @@ - Go to the page displayed before. + Go back to the previous view of the document. - &Alt;Right + &Alt; Right Go Forward - + - Go to the page of the document where you were after. + Move forward to the next view of the document. This only works if you have already moved back before. - &Ctrl;G + &Ctrl; G Go - Go to Page - + Go to Page... + - Go to a selected page of the document. + Open a dialog which allows you to go to any page of the document. - - The <guimenu>Tools</guimenu> Menu + <guimenu>Tools</guimenu> Menu @@ -467,19 +552,18 @@ - The mouse will work as a select tool. In that mode clicking &LMB; and dragging will give the option of copying the text/image of current the selected area to the clipboard, images can be saved to a file too. + The mouse will work as a select tool. In that mode clicking &LMB; and dragging will give the option of copying the text/image of current the selected area to the clipboard, or to save it to a file. - - The <guimenu>Settings</guimenu> Menu + <guimenu>Settings</guimenu> Menu - &Ctrl;M + &Ctrl; M Settings Show/Hide Menubar @@ -503,27 +587,27 @@ - &Ctrl;L + &Ctrl; L Settings Show/Hide Navigation Panel - Toggle the Navigation Panel display on and off. + Toggle the navigation panel on and off. - &Ctrl;&Shift;F + &Ctrl; &Shift; F Settings Full Screen Mode - Enables the full screen mode. Note that + Enables the full screen mode. Note that full screen mode is different from presentation mode as the + linkend="presentationMode">presentation mode insofar as the only peculiarity of full screen mode is that it hides the window decorations, the menubar and the toolbar. @@ -536,8 +620,8 @@ - Opens a window that lets you configure the keyboard - shortcuts for many menu commands. + Opens a window that lets you configure the keyboard + shortcuts for many menu commands. @@ -560,7 +644,7 @@ - Opens the Configure + Opens the Configure window. @@ -571,23 +655,50 @@ <guimenu>Help</guimenu> Menu &help.menu.documentation; - - + Configuring &kpdf; - + + Overview + + You can configure &kpdf; by choosing Settings + Configure &kpdf;.... + The configuration dialogue is split into four sections. This chapter describes the available + options in detail. + + + + General + + + Accessibility + + + Performance + + + Presentation + + + + The configuration dialogue + + + + + + The configuration dialogue + + + + + General - Show left panel - - Whether to show the left panel. - - - - Show search bar in thumbnails view + Show search bar in thumbnails list - Whether to show search bar in thumbnails view or not. That + Whether to the show a search bar in the thumbnails view or not. That search bar is useful for filtering pages that contain a given string. @@ -595,14 +706,14 @@ Link thumbnails list with the page - Whether the thumbnails view will always show the current + Whether the thumbnails view should always display the current page or not. Show scrollbars - Whether to show scrollbars. + Whether to show scrollbars for the document view. @@ -612,9 +723,22 @@ load, etc. + + Obey DRM limitations + + Whether &kpdf; should obey DRM (Digital Rights Management) restrictions. DRM limitations are used to make it impossible to perform certain actions with PDF documents, such as copying content to the clipboard. Note that in some configurations of &kpdf;, this option is not available. + + + + Watch file + + Whether opened files should be automatically checked for + changes and updated, if necessary. + + - + Accessibility @@ -638,30 +762,34 @@ Invert colors - Inverts colors on the view, &ie; black things will be shown white. + Inverts colors on the view, &ie; black objects will be shown white. Change paper color - Changes paper color. + Changes the paper's color, &ie; the document's background. Change dark and light colors - Changes the dark and light color, that means black will not be rendered as black but as the dark color and the same for white. + Changes the dark and light color to your preference, that means + black will not be rendered as black but as the selected dark color and white + will not be rendered as white but as the selected light color. Convert to black and white - Converts the document to black and white. + Converts the document to black and white. You can set the + threshold and the contrast. Setting the threshold to a higher value + will result in darker grays used. - + Performance @@ -676,7 +804,7 @@ Enable background generation Use a background thread to generate the pages. By disabling - this option the &GUI; will become less reactive (will be blocked + this option the user interface will become less reactive (will be blocked if necessary), but pages will be displayed a bit faster. @@ -691,13 +819,13 @@ - + Presentation Advance every - Enables auto advancing of pages given a time period. + Enables automatic advancing of pages given a time period. @@ -715,7 +843,8 @@ Default transition - The transition between page and page if the document does not specify one. + The transition effect between page and page if the document does not specify one. Set this to Random + Transition to make &kpdf; randomly choose one of the available effects. @@ -727,7 +856,8 @@ Show progress indicator - Whether to show a progress circle that shows the current page and the total number of pages on the upper right corner. + Whether to show a progress circle that shows the current page and the total number of pages on the upper + right corner of the presentation screen everytime you change the page. @@ -748,15 +878,41 @@ Christophe Devrieseoelewapperke@ulyssis.org &Wilco.Greven; Wilco.Greven.mail; Original author Enrico Roseros.kde@email.it Refactoring for 3.4 + Laurent Montelmontel@kde.org + + &underGPL; + + + Documentation Copyright: + Albert Astals Cidtsdgeos@yahoo.es Author + Titus Laskatitus.laska@gmx.de Some updates and additions - &underFDL; &underGPL; + + + Installation + + How to obtain &kpdf; + &install.intro.documentation; + + + Compilation and Installation + + + If you are reading this help in the &khelpcenter;, &kpdf; has already been + installed on this system and you do not need install it anymore. + + + &install.compile.documentation; + + &documentation.index; + &FDLNotice; - 2005-12-10 + 2006-01-14 0.5 @@ -60,7 +60,7 @@ To view a PDF file in &kpdf;, select FileOpen... , choose a file in the dialogue and click Open. - As long as you selected a valid PDF file, your file should know be displayed in the main window. + As long as you selected a valid PDF file, your file should now be displayed in the main window. If you have already opened files in &kpdf; before, you can quickly access them by selecting them in @@ -850,8 +850,8 @@ Default transition - The transition effect between page and page if the document does not specify one. Set this to Random - Transition to make &kpdf; randomly choose one of the available effects. + The transition effect between page and page if the document does not specify one. Set this to Random + Transition to make &kpdf; randomly choose one of the available effects. @@ -883,7 +883,7 @@ Program Copyright: Albert Astals Cidtsdgeos@yahoo.es Current maintainer Christophe Devrieseoelewapperke@ulyssis.org - &Wilco.Greven; Wilco.Greven.mail; Original author + &Wilco.Greven; &Wilco.Greven.mail; Original author Enrico Roseros.kde@email.it Refactoring for 3.4 Laurent Montelmontel@kde.org From eb85ce2c0fd151cdb453568e8ab82227cd10b09a Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 5 Mar 2006 22:22:00 +0000 Subject: [PATCH 218/245] Come on everybody do the poppler dance! KPDF from trunk now needs poppler >= 0.5.1 kfile pdf plugin ported to Qt4 and needs poppler-qt4 >= 0.4 moved kviewshell poppler check to configure.in.in with the pdf kfile plugin and the kpdf one to have all of them together You'll need to make -f Makefile.cvs and configure again. If i broke something for you just shout at me svn path=/trunk/KDE/kdegraphics/kpdf/; revision=516087 --- Makefile.am | 6 +- configure.in.bot | 30 - configure.in.in | 103 - core/Makefile.am | 2 +- core/generator_pdf/Makefile.am | 4 +- core/generator_pdf/generator_pdf.cpp | 85 +- core/generator_pdf/generator_pdf.h | 4 +- core/generator_pdf/gp_outputdev.cpp | 10 +- core/generator_pdf/gp_outputdev.h | 9 +- core/generator_pdf/pagetransition.cpp | 184 + core/generator_pdf/pagetransition.h | 140 + core/page.cpp | 4 +- error.cpp => error.h | 8 +- part.cpp | 9 +- xpdf/Makefile.am | 1 - xpdf/README.xpdf | 376 -- xpdf/aconf.h | 14 - xpdf/fofi/FoFiBase.cc | 156 - xpdf/fofi/FoFiBase.h | 57 - xpdf/fofi/FoFiEncodings.cc | 994 ----- xpdf/fofi/FoFiEncodings.h | 36 - xpdf/fofi/FoFiTrueType.cc | 1764 --------- xpdf/fofi/FoFiTrueType.h | 141 - xpdf/fofi/FoFiType1.cc | 208 -- xpdf/fofi/FoFiType1.h | 59 - xpdf/fofi/FoFiType1C.cc | 2481 ------------- xpdf/fofi/FoFiType1C.h | 232 -- xpdf/fofi/Makefile.am | 9 - xpdf/goo/GHash.cc | 380 -- xpdf/goo/GHash.h | 78 - xpdf/goo/GList.cc | 97 - xpdf/goo/GList.h | 96 - xpdf/goo/GMutex.h | 49 - xpdf/goo/GString.cc | 319 -- xpdf/goo/GString.h | 97 - xpdf/goo/Makefile.am | 5 - xpdf/goo/gfile.cc | 705 ---- xpdf/goo/gfile.h | 138 - xpdf/goo/gmem.c | 230 -- xpdf/goo/gmem.h | 62 - xpdf/goo/gmempp.cc | 32 - xpdf/goo/gtypes.h | 29 - xpdf/splash/Makefile.am | 8 - xpdf/splash/Splash.cc | 3191 ---------------- xpdf/splash/Splash.h | 204 - xpdf/splash/SplashBitmap.cc | 243 -- xpdf/splash/SplashBitmap.h | 55 - xpdf/splash/SplashClip.cc | 270 -- xpdf/splash/SplashClip.h | 97 - xpdf/splash/SplashErrorCodes.h | 32 - xpdf/splash/SplashFTFont.cc | 346 -- xpdf/splash/SplashFTFont.h | 55 - xpdf/splash/SplashFTFontEngine.cc | 161 - xpdf/splash/SplashFTFontEngine.h | 59 - xpdf/splash/SplashFTFontFile.cc | 122 - xpdf/splash/SplashFTFontFile.h | 70 - xpdf/splash/SplashFont.cc | 172 - xpdf/splash/SplashFont.h | 97 - xpdf/splash/SplashFontEngine.cc | 229 -- xpdf/splash/SplashFontEngine.h | 83 - xpdf/splash/SplashFontFile.cc | 109 - xpdf/splash/SplashFontFile.h | 77 - xpdf/splash/SplashFontFileID.cc | 23 - xpdf/splash/SplashFontFileID.h | 30 - xpdf/splash/SplashGlyphBitmap.h | 26 - xpdf/splash/SplashMath.h | 46 - xpdf/splash/SplashPath.cc | 178 - xpdf/splash/SplashPath.h | 112 - xpdf/splash/SplashPattern.cc | 68 - xpdf/splash/SplashPattern.h | 90 - xpdf/splash/SplashScreen.cc | 141 - xpdf/splash/SplashScreen.h | 50 - xpdf/splash/SplashState.cc | 110 - xpdf/splash/SplashState.h | 91 - xpdf/splash/SplashT1Font.cc | 264 -- xpdf/splash/SplashT1Font.h | 53 - xpdf/splash/SplashT1FontEngine.cc | 122 - xpdf/splash/SplashT1FontEngine.h | 53 - xpdf/splash/SplashT1FontFile.cc | 116 - xpdf/splash/SplashT1FontFile.h | 57 - xpdf/splash/SplashTypes.h | 134 - xpdf/splash/SplashXPath.cc | 414 --- xpdf/splash/SplashXPath.h | 92 - xpdf/splash/SplashXPathScanner.cc | 285 -- xpdf/splash/SplashXPathScanner.h | 74 - xpdf/xpdf/Annot.cc | 316 -- xpdf/xpdf/Annot.h | 73 - xpdf/xpdf/Array.cc | 88 - xpdf/xpdf/Array.h | 59 - xpdf/xpdf/BuiltinFont.cc | 65 - xpdf/xpdf/BuiltinFont.h | 57 - xpdf/xpdf/BuiltinFontTables.cc | 4284 --------------------- xpdf/xpdf/BuiltinFontTables.h | 23 - xpdf/xpdf/CMap.cc | 408 -- xpdf/xpdf/CMap.h | 102 - xpdf/xpdf/Catalog.cc | 426 --- xpdf/xpdf/Catalog.h | 135 - xpdf/xpdf/CharCodeToUnicode.cc | 563 --- xpdf/xpdf/CharCodeToUnicode.h | 117 - xpdf/xpdf/CharTypes.h | 24 - xpdf/xpdf/CompactFontTables.h | 464 --- xpdf/xpdf/DCTStream.cc | 159 - xpdf/xpdf/DCTStream.h | 72 - xpdf/xpdf/Decrypt.cc | 411 -- xpdf/xpdf/Decrypt.h | 63 - xpdf/xpdf/Dict.cc | 96 - xpdf/xpdf/Dict.h | 79 - xpdf/xpdf/Error.h | 23 - xpdf/xpdf/ErrorCodes.h | 36 - xpdf/xpdf/FlateStream.cc | 107 - xpdf/xpdf/FlateStream.h | 67 - xpdf/xpdf/FontEncodingTables.cc | 1824 --------- xpdf/xpdf/FontEncodingTables.h | 20 - xpdf/xpdf/Function.cc | 1536 -------- xpdf/xpdf/Function.h | 225 -- xpdf/xpdf/Gfx.cc | 3598 ------------------ xpdf/xpdf/Gfx.h | 293 -- xpdf/xpdf/GfxFont.cc | 1597 -------- xpdf/xpdf/GfxFont.h | 317 -- xpdf/xpdf/GfxState.cc | 3947 -------------------- xpdf/xpdf/GfxState.h | 1206 ------ xpdf/xpdf/GlobalParams.cc | 2064 ----------- xpdf/xpdf/GlobalParams.h | 337 -- xpdf/xpdf/JArithmeticDecoder.cc | 322 -- xpdf/xpdf/JArithmeticDecoder.h | 109 - xpdf/xpdf/JBIG2Stream.cc | 3411 ----------------- xpdf/xpdf/JBIG2Stream.h | 143 - xpdf/xpdf/JPXStream.cc | 2954 --------------- xpdf/xpdf/JPXStream.h | 349 -- xpdf/xpdf/Lexer.cc | 501 --- xpdf/xpdf/Lexer.h | 82 - xpdf/xpdf/Link.cc | 908 ----- xpdf/xpdf/Link.h | 410 -- xpdf/xpdf/Makefile.am | 19 - xpdf/xpdf/NameToCharCode.cc | 116 - xpdf/xpdf/NameToCharCode.h | 42 - xpdf/xpdf/NameToUnicodeTable.h | 1097 ------ xpdf/xpdf/Object.cc | 235 -- xpdf/xpdf/Object.h | 304 -- xpdf/xpdf/Outline.cc | 152 - xpdf/xpdf/Outline.h | 76 - xpdf/xpdf/OutputDev.cc | 129 - xpdf/xpdf/OutputDev.h | 205 - xpdf/xpdf/PDFDoc.cc | 473 --- xpdf/xpdf/PDFDoc.h | 195 - xpdf/xpdf/PDFDocEncoding.cc | 44 - xpdf/xpdf/PDFDocEncoding.h | 16 - xpdf/xpdf/PSOutputDev.cc | 4953 ------------------------- xpdf/xpdf/PSOutputDev.h | 353 -- xpdf/xpdf/PSTokenizer.cc | 135 - xpdf/xpdf/PSTokenizer.h | 41 - xpdf/xpdf/Page.cc | 485 --- xpdf/xpdf/Page.h | 247 -- xpdf/xpdf/Parser.cc | 217 -- xpdf/xpdf/Parser.h | 56 - xpdf/xpdf/SecurityHandler.cc | 377 -- xpdf/xpdf/SecurityHandler.h | 155 - xpdf/xpdf/SplashOutputDev.cc | 2628 ------------- xpdf/xpdf/SplashOutputDev.h | 222 -- xpdf/xpdf/Stream-CCITT.h | 462 --- xpdf/xpdf/Stream.cc | 4586 ----------------------- xpdf/xpdf/Stream.h | 850 ----- xpdf/xpdf/TextOutputDev.cc | 3613 ------------------ xpdf/xpdf/TextOutputDev.h | 587 --- xpdf/xpdf/UGString.cc | 86 - xpdf/xpdf/UGString.h | 55 - xpdf/xpdf/UTF8.h | 56 - xpdf/xpdf/UnicodeMap.cc | 293 -- xpdf/xpdf/UnicodeMap.h | 123 - xpdf/xpdf/UnicodeMapTables.h | 361 -- xpdf/xpdf/UnicodeTypeTable.cc | 949 ----- xpdf/xpdf/UnicodeTypeTable.h | 20 - xpdf/xpdf/XRef.cc | 906 ----- xpdf/xpdf/XRef.h | 134 - xpdf/xpdf/xpdf_config.h | 110 - 175 files changed, 398 insertions(+), 77987 deletions(-) delete mode 100644 configure.in.bot create mode 100644 core/generator_pdf/pagetransition.cpp create mode 100644 core/generator_pdf/pagetransition.h rename error.cpp => error.h (88%) delete mode 100644 xpdf/Makefile.am delete mode 100644 xpdf/README.xpdf delete mode 100644 xpdf/aconf.h delete mode 100644 xpdf/fofi/FoFiBase.cc delete mode 100644 xpdf/fofi/FoFiBase.h delete mode 100644 xpdf/fofi/FoFiEncodings.cc delete mode 100644 xpdf/fofi/FoFiEncodings.h delete mode 100644 xpdf/fofi/FoFiTrueType.cc delete mode 100644 xpdf/fofi/FoFiTrueType.h delete mode 100644 xpdf/fofi/FoFiType1.cc delete mode 100644 xpdf/fofi/FoFiType1.h delete mode 100644 xpdf/fofi/FoFiType1C.cc delete mode 100644 xpdf/fofi/FoFiType1C.h delete mode 100644 xpdf/fofi/Makefile.am delete mode 100644 xpdf/goo/GHash.cc delete mode 100644 xpdf/goo/GHash.h delete mode 100644 xpdf/goo/GList.cc delete mode 100644 xpdf/goo/GList.h delete mode 100644 xpdf/goo/GMutex.h delete mode 100644 xpdf/goo/GString.cc delete mode 100644 xpdf/goo/GString.h delete mode 100644 xpdf/goo/Makefile.am delete mode 100644 xpdf/goo/gfile.cc delete mode 100644 xpdf/goo/gfile.h delete mode 100644 xpdf/goo/gmem.c delete mode 100644 xpdf/goo/gmem.h delete mode 100644 xpdf/goo/gmempp.cc delete mode 100644 xpdf/goo/gtypes.h delete mode 100644 xpdf/splash/Makefile.am delete mode 100644 xpdf/splash/Splash.cc delete mode 100644 xpdf/splash/Splash.h delete mode 100644 xpdf/splash/SplashBitmap.cc delete mode 100644 xpdf/splash/SplashBitmap.h delete mode 100644 xpdf/splash/SplashClip.cc delete mode 100644 xpdf/splash/SplashClip.h delete mode 100644 xpdf/splash/SplashErrorCodes.h delete mode 100644 xpdf/splash/SplashFTFont.cc delete mode 100644 xpdf/splash/SplashFTFont.h delete mode 100644 xpdf/splash/SplashFTFontEngine.cc delete mode 100644 xpdf/splash/SplashFTFontEngine.h delete mode 100644 xpdf/splash/SplashFTFontFile.cc delete mode 100644 xpdf/splash/SplashFTFontFile.h delete mode 100644 xpdf/splash/SplashFont.cc delete mode 100644 xpdf/splash/SplashFont.h delete mode 100644 xpdf/splash/SplashFontEngine.cc delete mode 100644 xpdf/splash/SplashFontEngine.h delete mode 100644 xpdf/splash/SplashFontFile.cc delete mode 100644 xpdf/splash/SplashFontFile.h delete mode 100644 xpdf/splash/SplashFontFileID.cc delete mode 100644 xpdf/splash/SplashFontFileID.h delete mode 100644 xpdf/splash/SplashGlyphBitmap.h delete mode 100644 xpdf/splash/SplashMath.h delete mode 100644 xpdf/splash/SplashPath.cc delete mode 100644 xpdf/splash/SplashPath.h delete mode 100644 xpdf/splash/SplashPattern.cc delete mode 100644 xpdf/splash/SplashPattern.h delete mode 100644 xpdf/splash/SplashScreen.cc delete mode 100644 xpdf/splash/SplashScreen.h delete mode 100644 xpdf/splash/SplashState.cc delete mode 100644 xpdf/splash/SplashState.h delete mode 100644 xpdf/splash/SplashT1Font.cc delete mode 100644 xpdf/splash/SplashT1Font.h delete mode 100644 xpdf/splash/SplashT1FontEngine.cc delete mode 100644 xpdf/splash/SplashT1FontEngine.h delete mode 100644 xpdf/splash/SplashT1FontFile.cc delete mode 100644 xpdf/splash/SplashT1FontFile.h delete mode 100644 xpdf/splash/SplashTypes.h delete mode 100644 xpdf/splash/SplashXPath.cc delete mode 100644 xpdf/splash/SplashXPath.h delete mode 100644 xpdf/splash/SplashXPathScanner.cc delete mode 100644 xpdf/splash/SplashXPathScanner.h delete mode 100644 xpdf/xpdf/Annot.cc delete mode 100644 xpdf/xpdf/Annot.h delete mode 100644 xpdf/xpdf/Array.cc delete mode 100644 xpdf/xpdf/Array.h delete mode 100644 xpdf/xpdf/BuiltinFont.cc delete mode 100644 xpdf/xpdf/BuiltinFont.h delete mode 100644 xpdf/xpdf/BuiltinFontTables.cc delete mode 100644 xpdf/xpdf/BuiltinFontTables.h delete mode 100644 xpdf/xpdf/CMap.cc delete mode 100644 xpdf/xpdf/CMap.h delete mode 100644 xpdf/xpdf/Catalog.cc delete mode 100644 xpdf/xpdf/Catalog.h delete mode 100644 xpdf/xpdf/CharCodeToUnicode.cc delete mode 100644 xpdf/xpdf/CharCodeToUnicode.h delete mode 100644 xpdf/xpdf/CharTypes.h delete mode 100644 xpdf/xpdf/CompactFontTables.h delete mode 100644 xpdf/xpdf/DCTStream.cc delete mode 100644 xpdf/xpdf/DCTStream.h delete mode 100644 xpdf/xpdf/Decrypt.cc delete mode 100644 xpdf/xpdf/Decrypt.h delete mode 100644 xpdf/xpdf/Dict.cc delete mode 100644 xpdf/xpdf/Dict.h delete mode 100644 xpdf/xpdf/Error.h delete mode 100644 xpdf/xpdf/ErrorCodes.h delete mode 100644 xpdf/xpdf/FlateStream.cc delete mode 100644 xpdf/xpdf/FlateStream.h delete mode 100644 xpdf/xpdf/FontEncodingTables.cc delete mode 100644 xpdf/xpdf/FontEncodingTables.h delete mode 100644 xpdf/xpdf/Function.cc delete mode 100644 xpdf/xpdf/Function.h delete mode 100644 xpdf/xpdf/Gfx.cc delete mode 100644 xpdf/xpdf/Gfx.h delete mode 100644 xpdf/xpdf/GfxFont.cc delete mode 100644 xpdf/xpdf/GfxFont.h delete mode 100644 xpdf/xpdf/GfxState.cc delete mode 100644 xpdf/xpdf/GfxState.h delete mode 100644 xpdf/xpdf/GlobalParams.cc delete mode 100644 xpdf/xpdf/GlobalParams.h delete mode 100644 xpdf/xpdf/JArithmeticDecoder.cc delete mode 100644 xpdf/xpdf/JArithmeticDecoder.h delete mode 100644 xpdf/xpdf/JBIG2Stream.cc delete mode 100644 xpdf/xpdf/JBIG2Stream.h delete mode 100644 xpdf/xpdf/JPXStream.cc delete mode 100644 xpdf/xpdf/JPXStream.h delete mode 100644 xpdf/xpdf/Lexer.cc delete mode 100644 xpdf/xpdf/Lexer.h delete mode 100644 xpdf/xpdf/Link.cc delete mode 100644 xpdf/xpdf/Link.h delete mode 100644 xpdf/xpdf/Makefile.am delete mode 100644 xpdf/xpdf/NameToCharCode.cc delete mode 100644 xpdf/xpdf/NameToCharCode.h delete mode 100644 xpdf/xpdf/NameToUnicodeTable.h delete mode 100644 xpdf/xpdf/Object.cc delete mode 100644 xpdf/xpdf/Object.h delete mode 100644 xpdf/xpdf/Outline.cc delete mode 100644 xpdf/xpdf/Outline.h delete mode 100644 xpdf/xpdf/OutputDev.cc delete mode 100644 xpdf/xpdf/OutputDev.h delete mode 100644 xpdf/xpdf/PDFDoc.cc delete mode 100644 xpdf/xpdf/PDFDoc.h delete mode 100644 xpdf/xpdf/PDFDocEncoding.cc delete mode 100644 xpdf/xpdf/PDFDocEncoding.h delete mode 100644 xpdf/xpdf/PSOutputDev.cc delete mode 100644 xpdf/xpdf/PSOutputDev.h delete mode 100644 xpdf/xpdf/PSTokenizer.cc delete mode 100644 xpdf/xpdf/PSTokenizer.h delete mode 100644 xpdf/xpdf/Page.cc delete mode 100644 xpdf/xpdf/Page.h delete mode 100644 xpdf/xpdf/Parser.cc delete mode 100644 xpdf/xpdf/Parser.h delete mode 100644 xpdf/xpdf/SecurityHandler.cc delete mode 100644 xpdf/xpdf/SecurityHandler.h delete mode 100644 xpdf/xpdf/SplashOutputDev.cc delete mode 100644 xpdf/xpdf/SplashOutputDev.h delete mode 100644 xpdf/xpdf/Stream-CCITT.h delete mode 100644 xpdf/xpdf/Stream.cc delete mode 100644 xpdf/xpdf/Stream.h delete mode 100644 xpdf/xpdf/TextOutputDev.cc delete mode 100644 xpdf/xpdf/TextOutputDev.h delete mode 100644 xpdf/xpdf/UGString.cc delete mode 100644 xpdf/xpdf/UGString.h delete mode 100644 xpdf/xpdf/UTF8.h delete mode 100644 xpdf/xpdf/UnicodeMap.cc delete mode 100644 xpdf/xpdf/UnicodeMap.h delete mode 100644 xpdf/xpdf/UnicodeMapTables.h delete mode 100644 xpdf/xpdf/UnicodeTypeTable.cc delete mode 100644 xpdf/xpdf/UnicodeTypeTable.h delete mode 100644 xpdf/xpdf/XRef.cc delete mode 100644 xpdf/xpdf/XRef.h delete mode 100644 xpdf/xpdf/xpdf_config.h diff --git a/Makefile.am b/Makefile.am index fd5ccb491..7b17f1833 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ -SUBDIRS = xpdf conf core ui shell +SUBDIRS = conf core ui shell -INCLUDES = -I$(srcdir)/xpdf -I$(srcdir)/xpdf/goo -I$(top_builddir)/kpdf $(all_includes) $(FREETYPE_CFLAGS) +INCLUDES = -I$(top_builddir)/kpdf $(all_includes) $(POPPLER_CFLAGS) METASOURCES = AUTO @@ -17,7 +17,7 @@ kde_module_LTLIBRARIES = libkpdfpart.la libkpdfpart_la_SOURCES = dcop.skel error.cpp part.cpp libkpdfpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -libkpdfpart_la_LIBADD = xpdf/xpdf/libxpdf.la conf/libkpdfconf.la \ +libkpdfpart_la_LIBADD = $(POPPLER_LIBS) conf/libkpdfconf.la \ core/libkpdfcore.la ui/libkpdfui.la $(LIB_KPARTS) \ $(LIB_KFILE) $(LIB_KDEPRINT) $(LIB_KUTILS) -lm diff --git a/configure.in.bot b/configure.in.bot deleted file mode 100644 index 43342e132..000000000 --- a/configure.in.bot +++ /dev/null @@ -1,30 +0,0 @@ -if test -z "$FREETYPE_CONFIG"; then - echo "" - echo "You're missing freetype development libs." - echo "KPDF will not be build without them" - echo "" -fi - -if test x$FREETYPE_VERSION != x; then - if test $FREETYPE_VERSION -lt 9008003; then - echo "" - echo "You're are using freetype older than 2.1.10, it is not mandatory" - echo "to use 2.1.10 but kpdf improves its rendering in some pdf with it" - echo "" - fi -fi - -if test -z "$XFT_LIBS"; then - echo "" - echo "You're missing XFT development libs." - echo "KPDF will not be build without them" - echo "" -fi - -if test "$HAVE_LIBJPEG" = "no"; then - echo "" - echo "You're missing libjpeg development libs." - echo "KPDF will not be build without them" - echo "" -fi - diff --git a/configure.in.in b/configure.in.in index 69a8edcac..6726d2a96 100644 --- a/configure.in.in +++ b/configure.in.in @@ -1,100 +1,3 @@ -dnl ##### Check for FreeType 2.0.5+. -dnl ##### (Note: FT_Get_Name_Index was added in FT 2.0.5, and is -dnl ##### the reason that Xpdf requires 2.0.5+.) - -KDE_FIND_PATH(freetype-config, FREETYPE_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin], [ - AC_MSG_WARN([Could not find libfreetype anywhere, check http://www.freetype.org/]) -]) - -if test -n "$FREETYPE_CONFIG"; then - FREETYPE_VERSION=`$FREETYPE_CONFIG --version 2>/dev/null | sed -e 's/libfreetype //' | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` - if test -n "$FREETYPE_VERSION" && test "$FREETYPE_VERSION" -ge 9000000; then - LIBFREETYPE_LIBS="`$FREETYPE_CONFIG --libs`" - LIBFREETYPE_RPATH= - for args in $LIBFREETYPE_LIBS; do - case $args in - -L*) LIBFREETYPE_RPATH="$LIBFREETYPE_RPATH $args" ;; - esac - done - LIBFREETYPE_RPATH=`echo $LIBFREETYPE_RPATH | sed -e "s/-L/-R/g"` - LIBFREETYPE_CFLAGS="`$FREETYPE_CONFIG --cflags`" - AC_DEFINE_UNQUOTED(HAVE_FREETYPE, 1, [Defines if your system has the freetype library]) - else - AC_MSG_WARN([You need at least libfreetype 2.0.5]) - DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" - fi -else - DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" -fi - -AC_SUBST(FREETYPE_VERSION) -AC_SUBST(LIBFREETYPE_LIBS) -AC_SUBST(LIBFREETYPE_CFLAGS) -AC_SUBST(LIBFREETYPE_RPATH) - - -# Check for xft -KDE_FIND_PATH(xft-config, XFT_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],) - -if test -n "$XFT_CONFIG"; then - XFT_CFLAGS="`$XFT_CONFIG --cflags`" - XFT_LIBS="`$XFT_CONFIG --libs`" -fi - -AC_SUBST(XFT_CFLAGS) -AC_SUBST(XFT_LIBS) - -if test -z "$XFT_LIBS"; then - DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" -fi - -dnl ##### Check for libpaper (Debian). -LIBPAPER_LIBS= -KDE_CHECK_HEADER(paper.h, [ - LIBPAPER_LIBS='-lpaper' - AC_DEFINE_UNQUOTED(HAVE_PAPER_H, 1, [Define to 1 if you have the header file.]) -], - AC_DEFINE_UNQUOTED(HAVE_PAPER_H, 0, [Define to 1 if you have the header file.]) -) -AC_SUBST(LIBPAPER_LIBS) - -AC_CHECK_FUNCS(fseek64 mkstemp mkstemps popen) - -AC_FIND_FILE(xpdfrc, [/etc /usr/local/etc /etc/xpdf], xpdfrc) -if test "$xpdfrc" != NO; then - AC_DEFINE_UNQUOTED(SYSTEM_XPDFRC, "$xpdfrc/xpdfrc", [Define the location your xpdfrc]) -fi - -dnl #### Check for FSEEK variants -KDE_CHECK_LARGEFILE -AC_FUNC_FSEEKO -AC_CHECK_FUNCS(fseek64, xpdf_cv_func_fseek64=yes, xpdf_cv_func_fseek64=no) -AC_CHECK_FUNCS(ftell64, xpdf_cv_func_ftell64=yes, xpdf_cv_func_ftell64=no) -if test "$xpdf_cv_func_fseek64" = yes -a "$xpdf_cv_func_ftell64" = yes; then - AC_DEFINE(HAVE_FSEEK64, 1) -else - AC_DEFINE(HAVE_FSEEK64, 0) -fi - -dnl #### Enable the user to enable multithearind on xpdf -AC_ARG_ENABLE(multithreaded-kpdf, - AC_HELP_STRING([--enable-multithreaded-kpdf],[include support for multithreading in xpdf code inside kpdf. Has nothing to do with threaded generation of contents, this is configurable via a dialog inside the program itself]), -[ - case $enableval in - yes) - AC_DEFINE(MULTITHREADED, 1, [Defines if use multithreading in xpdf code inside kpdf]) - ;; - no) - AC_DEFINE(MULTITHREADED, 0, [Defines if use multithreading in xpdf code inside kpdf]) - ;; - *) - AC_DEFINE(MULTITHREADED, 1, [Defines if use multithreading in xpdf code inside kpdf]) - ;; - esac -] -, AC_DEFINE(MULTITHREADED, 0, [Defines if use multithreading in xpdf code inside kpdf]) -) - dnl #### Enable the user to decide if he wants to force drm or not AC_ARG_ENABLE(force-kpdf-drm, AC_HELP_STRING([--enable-force-kpdf-drm],[Forces kpdf to check for DRM to decide if you can copy/print protected pdf. (default=no)]), @@ -113,9 +16,3 @@ AC_ARG_ENABLE(force-kpdf-drm, ] , AC_DEFINE(KPDF_FORCE_DRM, 0, [Defines if force the use DRM in kpdf]) ) - -KDE_CHECK_COMPILER_FLAG([fno-regmove], SUPPORTS_NOREGMOVE=true, SUPPORTS_NOREGMOVE=false) -if test "x$SUPPORTS_NOREGMOVE" = xtrue; then - NOREGMOVE="-fno-regmove" -fi -AC_SUBST(NOREGMOVE) diff --git a/core/Makefile.am b/core/Makefile.am index 74c774855..1f0dd72d1 100644 --- a/core/Makefile.am +++ b/core/Makefile.am @@ -1,6 +1,6 @@ SUBDIRS = generator_pdf generator_kimgio -INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(srcdir)/../xpdf -I$(srcdir)/../xpdf/goo -I$(top_builddir)/kpdf $(all_includes) +INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(top_builddir)/kpdf $(POPPLER_CFLAGS) $(all_includes) METASOURCES = AUTO diff --git a/core/generator_pdf/Makefile.am b/core/generator_pdf/Makefile.am index 700740b7b..b049bf42c 100644 --- a/core/generator_pdf/Makefile.am +++ b/core/generator_pdf/Makefile.am @@ -1,7 +1,7 @@ -INCLUDES = -I$(srcdir)/../.. -I$(srcdir)/../../xpdf -I$(srcdir)/../../xpdf/goo -I$(srcdir)/../../xpdf/splash -I$(top_builddir)/kpdf $(all_includes) +INCLUDES = -I$(srcdir)/../.. -I$(top_builddir)/kpdf $(POPPLER_CFLAGS) $(all_includes) libgeneratorpdf_la_LDFLAGS = $(all_libraries) -libgeneratorpdf_la_SOURCES = generator_pdf.cpp gp_outputdev.cpp +libgeneratorpdf_la_SOURCES = generator_pdf.cpp gp_outputdev.cpp pagetransition.cpp noinst_LTLIBRARIES = libgeneratorpdf.la diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index a410291e8..3c3936813 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -25,21 +25,22 @@ #include // xpdf includes -#include "xpdf/Object.h" -#include "xpdf/Dict.h" -#include "xpdf/Annot.h" -#include "xpdf/PSOutputDev.h" -#include "xpdf/TextOutputDev.h" -#include "xpdf/Link.h" -#include "xpdf/ErrorCodes.h" -#include "xpdf/UnicodeMap.h" -#include "xpdf/Outline.h" -#include "xpdf/UGString.h" -#include "goo/GList.h" +#include "Object.h" +#include "Dict.h" +#include "Annot.h" +#include "PSOutputDev.h" +#include "TextOutputDev.h" +#include "Link.h" +#include "ErrorCodes.h" +#include "UnicodeMap.h" +#include "Outline.h" +#include "UGooString.h" +#include "goo/GooList.h" // local includes #include "generator_pdf.h" #include "gp_outputdev.h" +#include "pagetransition.h" #include "core/observer.h" //for PAGEVIEW_ID #include "core/page.h" #include "core/pagetransition.h" @@ -102,7 +103,7 @@ bool PDFGenerator::loadDocument( const QString & filePath, QVector & } #endif // create PDFDoc for the given file - pdfdoc = new PDFDoc( new GString( QFile::encodeName( filePath ) ), 0, 0 ); + pdfdoc = new PDFDoc( new GooString( QFile::encodeName( filePath ) ), 0, 0 ); // if the file didn't open correctly it might be encrypted, so ask for a pass bool firstInput = true; @@ -148,9 +149,9 @@ bool PDFGenerator::loadDocument( const QString & filePath, QVector & } // 2. reopen the document using the password - GString * pwd2 = new GString( password.data() ); + GooString * pwd2 = new GooString( password.data() ); delete pdfdoc; - pdfdoc = new PDFDoc( new GString( QFile::encodeName( filePath ) ), pwd2, pwd2 ); + pdfdoc = new PDFDoc( new GooString( QFile::encodeName( filePath ) ), pwd2, pwd2 ); delete pwd2; // 3. if the password is correct, store it to the wallet @@ -239,7 +240,7 @@ const DocumentSynopsis * PDFGenerator::generateDocumentSynopsis() if ( !outline ) return NULL; - GList * items = outline->getItems(); + GooList * items = outline->getItems(); if ( !items || items->getLength() < 1 ) return NULL; @@ -428,26 +429,26 @@ bool PDFGenerator::print( KPrinter& printer ) } KTempFile tf( QString::null, ".ps" ); - PSOutputDev *psOut = new PSOutputDev(tf.name().latin1(), pdfdoc->getXRef(), pdfdoc->getCatalog(), 1, pdfdoc->getNumPages(), psModePS); + PSOutputDev *psOut = new PSOutputDev((char*)tf.name().latin1(), pdfdoc->getXRef(), pdfdoc->getCatalog(), 1, pdfdoc->getNumPages(), psModePS); if (psOut->isOk()) { - std::list pages; + QList pageList; if (!printer.previewOnly()) { - QList pageList = printer.pageList(); - QList::const_iterator it; - - for(it = pageList.begin(); it != pageList.end(); ++it) pages.push_back(*it); + pageList = printer.pageList(); } else { - for(int i = 1; i <= pdfdoc->getNumPages(); i++) pages.push_back(i); + for(int i = 1; i <= pdfdoc->getNumPages(); i++) pageList.push_back(i); } docLock.lock(); - pdfdoc->displayPages(psOut, pages, 72, 72, 0, false, globalParams->getPSCrop(), gFalse); + foreach(int page, pageList) + { + pdfdoc->displayPage(psOut, page, 72, 72, 0, false, globalParams->getPSCrop(), gFalse); + } docLock.unlock(); // needs to be here so that the file is flushed, do not merge with the one @@ -463,12 +464,12 @@ bool PDFGenerator::print( KPrinter& printer ) } } -static UGString *QStringToUGString(const QString &s) { +static UGooString *QStringToUGooString(const QString &s) { int len = s.length(); Unicode *u = (Unicode *)gmallocn(s.length(), sizeof(Unicode)); for (int i = 0; i < len; ++i) u[i] = s.at(i).unicode(); - return new UGString(u, len); + return new UGooString(u, len); } QString PDFGenerator::getMetaData( const QString & key, const QString & option ) @@ -476,7 +477,7 @@ QString PDFGenerator::getMetaData( const QString & key, const QString & option ) if ( key == "StartFullScreen" ) { // asking for the 'start in fullscreen mode' (pdf property) - if ( pdfdoc->getCatalog()->getPageMode() == Catalog::FullScreen ) + if ( pdfdoc->getCatalog()->getPageMode() == Catalog::pageModeFullScreen ) return "yes"; } else if ( key == "NamedViewport" && !option.isEmpty() ) @@ -484,7 +485,7 @@ QString PDFGenerator::getMetaData( const QString & key, const QString & option ) // asking for the page related to a 'named link destination'. the // option is the link name. @see addSynopsisChildren. DocumentViewport viewport; - UGString * namedDest = QStringToUGString( option ); + UGooString * namedDest = QStringToUGooString( option ); docLock.lock(); LinkDest * destination = pdfdoc->findDest( namedDest ); if ( destination ) @@ -595,7 +596,7 @@ void PDFGenerator::scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fo { Ref fontRef, embRef; Object fontObj, toUnicodeObj; - GString *name; + GooString *name; GBool emb; int i; @@ -634,7 +635,7 @@ void PDFGenerator::scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fo sName = name->getCString(); if (!emb) { - DisplayFontParam *dfp = globalParams->getDisplayFont(name); + DisplayFontParam *dfp = globalParams->getDisplayFont(font); if (dfp) { if (dfp -> kind == displayFontT1) sPath = dfp->t1.fileName->getCString(); @@ -675,7 +676,7 @@ QString PDFGenerator::getDocumentInfo( const QString & data ) const QString result; Object obj; - GString *s1; + GooString *s1; GBool isUnicode; Unicode u; int i; @@ -764,7 +765,7 @@ QString PDFGenerator::getDocumentDate( const QString & data ) const return result; } -void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items ) +void PDFGenerator::addSynopsisChildren( QDomNode * parent, GooList * items ) { int numItems = items->getLength(); for ( int i = 0; i < numItems; ++i ) @@ -795,7 +796,7 @@ void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items ) // get the destination for the page now, but it's VERY time consuming, // so better storing the reference and provide the viewport as metadata // on demand - UGString *s = g->getNamedDest(); + UGooString *s = g->getNamedDest(); QString aux = unicodeToQString( s->unicode(), s->getLength() ); item.setAttribute( "ViewportName", aux ); } @@ -814,7 +815,7 @@ void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items ) // 3. recursively descend over children outlineItem->open(); - GList * children = outlineItem->getKids(); + GooList * children = outlineItem->getKids(); if ( children ) addSynopsisChildren( &item, children ); } @@ -871,12 +872,14 @@ void PDFGenerator::addTransition( int pageNumber, KPDFPage * page ) if ( !pdfPage ) return; - PageTransition *pdfTransition = pdfPage->getTransition(); - if ( !pdfTransition || pdfTransition->getType() == PageTransition::Replace ) + Object o; + PageTransition *pdfTransition = new PageTransition(pdfPage->getTrans(&o)); + o.free(); + if ( !pdfTransition || pdfTransition->type() == PageTransition::Replace ) return; KPDFPageTransition *transition = new KPDFPageTransition(); - switch ( pdfTransition->getType() ) { + switch ( pdfTransition->type() ) { case PageTransition::Replace: // won't get here, added to avoid warning break; @@ -915,9 +918,9 @@ void PDFGenerator::addTransition( int pageNumber, KPDFPage * page ) break; } - transition->setDuration( pdfTransition->getDuration() ); + transition->setDuration( pdfTransition->duration() ); - switch ( pdfTransition->getAlignment() ) { + switch ( pdfTransition->alignment() ) { case PageTransition::Horizontal: transition->setAlignment( KPDFPageTransition::Horizontal ); break; @@ -926,7 +929,7 @@ void PDFGenerator::addTransition( int pageNumber, KPDFPage * page ) break; } - switch ( pdfTransition->getDirection() ) { + switch ( pdfTransition->direction() ) { case PageTransition::Inward: transition->setDirection( KPDFPageTransition::Inward ); break; @@ -935,8 +938,8 @@ void PDFGenerator::addTransition( int pageNumber, KPDFPage * page ) break; } - transition->setAngle( pdfTransition->getAngle() ); - transition->setScale( pdfTransition->getScale() ); + transition->setAngle( pdfTransition->angle() ); + transition->setScale( pdfTransition->scale() ); transition->setIsRectangular( pdfTransition->isRectangular() == gTrue ); page->setTransition( transition ); diff --git a/core/generator_pdf/generator_pdf.h b/core/generator_pdf/generator_pdf.h index fce494929..3b3024892 100644 --- a/core/generator_pdf/generator_pdf.h +++ b/core/generator_pdf/generator_pdf.h @@ -25,7 +25,7 @@ class GfxFont; class LinkDest; class Ref; class PDFDoc; -class GList; +class GooList; class TextPage; class ObjectRect; @@ -96,7 +96,7 @@ class PDFGenerator : public Generator QString getDocumentInfo( const QString & data ) const; QString getDocumentDate( const QString & data ) const; // private function for creating the document synopsis hieracy - void addSynopsisChildren( QDomNode * parent, GList * items ); + void addSynopsisChildren( QDomNode * parent, GooList * items ); // private function for creating the transition information void addTransition( int pageNumber, KPDFPage * page ); // (async related) receive data from the generator thread diff --git a/core/generator_pdf/gp_outputdev.cpp b/core/generator_pdf/gp_outputdev.cpp index 57e0a3f04..d656a5f0a 100644 --- a/core/generator_pdf/gp_outputdev.cpp +++ b/core/generator_pdf/gp_outputdev.cpp @@ -28,9 +28,9 @@ #include "core/document.h" // for DocumentViewport #include "core/page.h" #include "core/link.h" -#include "xpdf/Link.h" -#include "xpdf/GfxState.h" -#include "xpdf/TextOutputDev.h" +#include "Link.h" +#include "GfxState.h" +#include "TextOutputDev.h" #include "splash/SplashBitmap.h" //NOTE: XPDF/Splash *implementation dependant* code is marked with '###' @@ -263,7 +263,7 @@ KPDFLink * KPDFOutputDev::generateLink( LinkAction * a ) case actionLaunch: { LinkLaunch * e = (LinkLaunch *)a; - GString * p = e->getParams(); + GooString * p = e->getParams(); link = new KPDFLinkExecute( e->getFileName()->getCString(), p ? p->getCString() : 0 ); } break; @@ -321,7 +321,7 @@ KPDFLink * KPDFOutputDev::generateLink( LinkAction * a ) return link; } -DocumentViewport KPDFOutputDev::decodeViewport( UGString * namedDest, LinkDest * dest ) +DocumentViewport KPDFOutputDev::decodeViewport( UGooString * namedDest, LinkDest * dest ) // note: this function is called when processing a page, when the MUTEX is already LOCKED { DocumentViewport vp( -1 ); diff --git a/core/generator_pdf/gp_outputdev.h b/core/generator_pdf/gp_outputdev.h index c938eb543..b487b0f7b 100644 --- a/core/generator_pdf/gp_outputdev.h +++ b/core/generator_pdf/gp_outputdev.h @@ -19,9 +19,12 @@ #pragma interface #endif +#define USE_FIXEDPOINT 0 +#define SPLASH_CMYK 0 + #include -#include "xpdf/PDFDoc.h" // for 'Object' -#include "xpdf/SplashOutputDev.h" +#include "PDFDoc.h" // for 'Object' +#include "SplashOutputDev.h" class QPixmap; class KPDFLink; @@ -71,7 +74,7 @@ class KPDFOutputDev : public SplashOutputDev // generate a valid KPDFLink subclass (or null) from a xpdf's LinkAction KPDFLink * generateLink( LinkAction * a ); // fills up a Viewport structure out of a given LinkGoto link - DocumentViewport decodeViewport( UGString *, class LinkDest * ); + DocumentViewport decodeViewport( UGooString *, class LinkDest * ); // generator switches and parameters bool m_qtThreadSafety; diff --git a/core/generator_pdf/pagetransition.cpp b/core/generator_pdf/pagetransition.cpp new file mode 100644 index 000000000..af7f67766 --- /dev/null +++ b/core/generator_pdf/pagetransition.cpp @@ -0,0 +1,184 @@ +/* PageTransition.cc + * Copyright (C) 2005, Net Integration Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "Object.h" +#include "Error.h" +#include "UGooString.h" +#include "pagetransition.h" + +class PageTransitionData +{ + public: + PageTransition::Type type; + int duration; + PageTransition::Alignment alignment; + PageTransition::Direction direction; + int angle; + double scale; + bool rectangular; +}; + +PageTransition::PageTransition(Object *dictObj) +{ + data = new PageTransitionData(); + data->type = Replace; + data->duration = 1; + data->alignment = Horizontal; + data->direction = Inward; + data->angle = 0; + data->scale = 1.0; + data->rectangular = false; + + // Paranoid safety checks + if (dictObj == 0) { + error(-1, "the method PageTransition_x::PageTransition_x(Object *params.dictObj) was called with params.dictObj==0\n"); + return; + } + if (dictObj->isDict() == false) { + error(-1, "the method PageTransition_x::PageTransition_x(Object *params.dictObj) was called where params.dictObj->isDict()==false\n"); + return; + } + + // Obtain a pointer to the dictionary and start parsing. + Dict *transDict = dictObj->getDict(); + Object obj; + + if (transDict->lookup("S", &obj)->isName()) { + const char *s = obj.getName(); + if (strcmp("R", s) == 0) + data->type = Replace; + else if (strcmp("Split", s) == 0) + data->type = Split; + else if (strcmp("Blinds", s) == 0) + data->type = Blinds; + else if (strcmp("Box", s) == 0) + data->type = Box; + else if (strcmp("Wipe", s) == 0) + data->type = Wipe; + else if (strcmp("Dissolve", s) == 0) + data->type = Dissolve; + else if (strcmp("Glitter", s) == 0) + data->type = Glitter; + else if (strcmp("Fly", s) == 0) + data->type = Fly; + else if (strcmp("Push", s) == 0) + data->type = Push; + else if (strcmp("Cover", s) == 0) + data->type = Cover; + else if (strcmp("Uncover", s) == 0) + data->type = Push; + else if (strcmp("Fade", s) == 0) + data->type = Cover; + } + obj.free(); + + if (transDict->lookup("D", &obj)->isInt()) { + data->duration = obj.getInt(); + } + obj.free(); + + if (transDict->lookup("Dm", &obj)->isName()) { + const char *dm = obj.getName(); + if ( strcmp( "H", dm ) == 0 ) + data->alignment = Horizontal; + else if ( strcmp( "V", dm ) == 0 ) + data->alignment = Vertical; + } + obj.free(); + + if (transDict->lookup("M", &obj)->isName()) { + const char *m = obj.getName(); + if ( strcmp( "I", m ) == 0 ) + data->direction = Inward; + else if ( strcmp( "O", m ) == 0 ) + data->direction = Outward; + } + obj.free(); + + if (transDict->lookup("Di", &obj)->isInt()) { + data->angle = obj.getInt(); + } + obj.free(); + + if (transDict->lookup("Di", &obj)->isName()) { + if ( strcmp( "None", obj.getName() ) == 0 ) + data->angle = 0; + } + obj.free(); + + if (transDict->lookup("SS", &obj)->isReal()) { + data->scale = obj.getReal(); + } + obj.free(); + + if (transDict->lookup("B", &obj)->isBool()) { + data->rectangular = obj.getBool(); + } + obj.free(); +} + +PageTransition::PageTransition(const PageTransition &pt) +{ + data = new PageTransitionData(); + data->type = pt.data->type; + data->duration = pt.data->duration; + data->alignment = pt.data->alignment; + data->direction = pt.data->direction; + data->angle = pt.data->angle; + data->scale = pt.data->scale; + data->rectangular = pt.data->rectangular; +} + +PageTransition::~PageTransition() +{ +} + +PageTransition::Type PageTransition::type() const +{ + return data->type; +} + +int PageTransition::duration() const +{ + return data->duration; +} + +PageTransition::Alignment PageTransition::alignment() const +{ + return data->alignment; +} + +PageTransition::Direction PageTransition::direction() const +{ + return data->direction; +} + +int PageTransition::angle() const +{ + return data->angle; +} + +double PageTransition::scale() const +{ + return data->scale; +} +bool PageTransition::isRectangular() const +{ + return data->rectangular; +} + diff --git a/core/generator_pdf/pagetransition.h b/core/generator_pdf/pagetransition.h new file mode 100644 index 000000000..cd798d71a --- /dev/null +++ b/core/generator_pdf/pagetransition.h @@ -0,0 +1,140 @@ +/* PageTransition.h + * Copyright (C) 2005, Net Integration Technologies, Inc. + * Copyright (C) 2005, Brad Hards + * Copyright (C) 2006, Albert Astals Cid + * + * File taken from poppler distribution, will remove asap we use the Qt4 frontend + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PAGETRANSITION_X_H__ +#define __PAGETRANSITION_X_H__ + +/** + \brief Describes how a PDF file viewer shall perform the transition + from one page to another + + In PDF files there is a way to specify if the viewer shall use + certain effects to perform the transition from one page to + another. This feature can be used, e.g., in a PDF-based beamer + presentation. + + This utility class represents the transition effect, and can be + used to extract the information from a PDF object. +*/ + +class PageTransitionData; + +class PageTransition { + public: + + /** \brief transition effect that shall be used + */ + enum Type { + Replace, + Split, + Blinds, + Box, + Wipe, + Dissolve, + Glitter, + Fly, + Push, + Cover, + Uncover, + Fade + }; + + /** \brief alignment of the transition effect that shall be used + */ + enum Alignment { + Horizontal, + Vertical + }; + + /** \brief direction of the transition effect that shall be used + */ + enum Direction { + Inward, + Outward + }; + + /** \brief Construct a new PageTransition object from a page dictionary. + + Users of the library will rarely need to construct a + PageTransition object themselves. Instead, the method + Poppler::Page::transition() can be used to find out if a certain + transition effect is specified. + + @warning In case or error, this method will print an error message to stderr, + and construct a default object. + + @param params an object whose dictionary will be read and + parsed. This must be a valid object, whose dictionaries are + accessed by the constructor. The object is only accessed by this + constructor, and may be deleted after the constructor returns. + */ + PageTransition(Object *dictObj); + + /** \brief copy constructor */ + PageTransition(const PageTransition &pt); + + /** + Destructor + */ + ~PageTransition(); + + /** + \brief Get type of the transition. + */ + Type type() const; + + /** + \brief Get duration of the transition in seconds. + */ + int duration() const; + + /** + \brief Get dimension in which the transition effect occurs. + */ + Alignment alignment() const; + + /** + \brief Get direction of motion of the transition effect. + */ + Direction direction() const; + + /** + \brief Get direction in which the transition effect moves. + */ + int angle() const; + + /** + \brief Get starting or ending scale. + */ + double scale() const; + + /** + \brief Returns true if the area to be flown is rectangular and + opaque. + */ + bool isRectangular() const; + + private: + PageTransitionData *data; +}; + +#endif diff --git a/core/page.cpp b/core/page.cpp index 0ad711c91..fbb9bb0ed 100644 --- a/core/page.cpp +++ b/core/page.cpp @@ -18,7 +18,7 @@ #include "pagetransition.h" #include "link.h" #include "conf/settings.h" -#include "xpdf/TextOutputDev.h" +#include "TextOutputDev.h" /** class KPDFPage **/ @@ -157,7 +157,7 @@ const QString KPDFPage::getText( const NormalizedRect & rect ) const top = (int)( rect.top * m_height ), right = (int)( rect.right * m_width ), bottom = (int)( rect.bottom * m_height ); - GString * text = m_text->getText( left, top, right, bottom ); + GooString * text = m_text->getText( left, top, right, bottom ); QString result = QString::fromUtf8( text->getCString() ); delete text; return result; diff --git a/error.cpp b/error.h similarity index 88% rename from error.cpp rename to error.h index 6932b3abd..52c632d1a 100644 --- a/error.cpp +++ b/error.h @@ -15,15 +15,13 @@ #include #include #include -#include "xpdf/GlobalParams.h" -#include "xpdf/Error.h" +#include "GlobalParams.h" #include #include -void CDECL error(int pos, const char *msg, ...) { - va_list args; +static void CDECL kpdf_error(int pos, char *msg, va_list args) { QString emsg, tmsg; char buffer[1024]; // should be big enough @@ -36,9 +34,7 @@ void CDECL error(int pos, const char *msg, ...) { } else { emsg = "Error: "; } - va_start(args, msg); vsprintf(buffer, msg, args); - va_end(args); emsg += buffer; kDebug() << emsg << endl; } diff --git a/part.cpp b/part.cpp index c4c9bf7ff..ea77be367 100644 --- a/part.cpp +++ b/part.cpp @@ -55,9 +55,13 @@ #include #include +// poppler includes +#include "GlobalParams.h" +#include "Error.h" + // local includes -#include "xpdf/GlobalParams.h" #include "part.h" +#include "error.h" #include "ui/pageview.h" #include "ui/thumbnaillist.h" #include "ui/searchwidget.h" @@ -99,9 +103,10 @@ Part::Part(QWidget *parentWidget, const char *widgetName, //if ( m_count ) TODO check if we need to insert these lines.. // delete globalParams; globalParams = new GlobalParams(""); - globalParams->setupBaseFonts(NULL); m_count++; + setErrorFunction(kpdf_error); + // we need an instance setInstance(KPDFPartFactory::instance()); diff --git a/xpdf/Makefile.am b/xpdf/Makefile.am deleted file mode 100644 index 0474692c9..000000000 --- a/xpdf/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = fofi goo splash xpdf diff --git a/xpdf/README.xpdf b/xpdf/README.xpdf deleted file mode 100644 index 2b8b6ce6f..000000000 --- a/xpdf/README.xpdf +++ /dev/null @@ -1,376 +0,0 @@ -Xpdf -==== - -version 3.00 -2004-jan-22 - -The Xpdf software and documentation are -copyright 1996-2004 Glyph & Cog, LLC. - -Email: derekn@foolabs.com -WWW: http://www.foolabs.com/xpdf/ - -The PDF data structures, operators, and specification are -copyright 1985-2003 Adobe Systems Inc. - - -What is Xpdf? -------------- - -Xpdf is an open source viewer for Portable Document Format (PDF) -files. (These are also sometimes also called 'Acrobat' files, from -the name of Adobe's PDF software.) The Xpdf project also includes a -PDF text extractor, PDF-to-PostScript converter, and various other -utilities. - -Xpdf runs under the X Window System on UNIX, VMS, and OS/2. The non-X -components (pdftops, pdftotext, etc.) also run on Win32 systems and -should run on pretty much any system with a decent C++ compiler. - -Xpdf is designed to be small and efficient. It can use Type 1 or -TrueType fonts. - - -Distribution ------------- - -Xpdf is licensed under the GNU General Public License (GPL), version -2. In my opinion, the GPL is a convoluted, confusing, ambiguous mess. -But it's also pervasive, and I'm sick of arguing. And even if it is -confusing, the basic idea is good. - -In order to cut down on the confusion a little bit, here are some -informal clarifications: - -- I don't mind if you redistribute Xpdf in source and/or binary form, - as long as you include all of the documentation: README, man pages - (or help files), and COPYING. (Note that the README file contains a - pointer to a web page with the source code.) - -- Selling a CD-ROM that contains Xpdf is fine with me, as long as it - includes the documentation. I wouldn't mind receiving a sample - copy, but it's not necessary. - -- If you make useful changes to Xpdf, please make the source code - available -- post it on a web site, email it to me, whatever. - -If you're interested in commercial licensing, please see the Glyph & -Cog web site: - - http://www.glyphandcog.com/ - - -Compatibility -------------- - -Xpdf is developed and tested on a Linux 2.4 x86 system. - -In addition, it has been compiled by others on Solaris, AIX, HP-UX, -Digital Unix, Irix, and numerous other Unix implementations, as well -as VMS and OS/2. It should work on pretty much any system which runs -X11 and has Unix-like libraries. You'll need ANSI C++ and C compilers -to compile it. - -The non-X components of Xpdf (pdftops, pdftotext, pdfinfo, pdffonts, -pdftoppm, and pdfimages) can also be compiled on Win32 systems. See -the Xpdf web page for details. - -If you compile Xpdf for a system not listed on the web page, please -let me know. If you're willing to make your binary available by ftp -or on the web, I'll be happy to add a link from the Xpdf web page. I -have decided not to host any binaries I didn't compile myself (for -disk space and support reasons). - -If you can't get Xpdf to compile on your system, send me email and -I'll try to help. - -Xpdf has been ported to the Acorn, Amiga, BeOS, and EPOC. See the -Xpdf web page for links. - - -Getting Xpdf ------------- - -The latest version is available from: - - http://www.foolabs.com/xpdf/ - -or: - - ftp://ftp.foolabs.com/pub/xpdf/ - -Source code and several precompiled executables are available. - -Announcements of new versions are posted to several newsgroups -(comp.text.pdf, comp.os.linux.announce, and others) and emailed to a -list of people. If you'd like to receive email notification of new -versions, just let me know. - - -Running Xpdf ------------- - -To run xpdf, simply type: - - xpdf file.pdf - -To generate a PostScript file, hit the "print" button in xpdf, or run -pdftops: - - pdftops file.pdf - -To generate a plain text file, run pdftotext: - - pdftotext file.pdf - -There are four additional utilities (which are fully described in -their man pages): - - pdfinfo -- dumps a PDF file's Info dictionary (plus some other - useful information) - pdffonts -- lists the fonts used in a PDF file along with various - information for each font - pdftoppm -- converts a PDF file to a series of PPM/PGM/PBM-format - bitmaps - pdfimages -- extracts the images from a PDF file - -Command line options and many other details are described in the man -pages (xpdf.1, etc.) and the VMS help files (xpdf.hlp, etc.). - - -Upgrading from Xpdf 2.xx ------------------------- - -WARNING: Xpdf 3.00 switched to a new PDF rasterizer, which no longer -uses X fonts. You'll need a set of Base-14 fonts -- the URW fonts -distributed with ghostscript can be used for this. Xpdf will search -for the URW fonts, but if you have them installed in a non-standard -directory, you'll need to set up an xpdfrc config file to point to -them. For full details, please see the xpdfrc(5) man page. - - -Compiling Xpdf --------------- - -See the separate file, INSTALL. - - -Bugs ----- - -If you find a bug in Xpdf, i.e., if it prints an error message, -crashes, or incorrectly displays a document, and you don't see that -bug listed here, please send me email, with a pointer (URL, ftp site, -etc.) to the PDF file. - - -Acknowledgments ---------------- - -Thanks to: - -* Patrick Voigt for help with the remote server code. -* Patrick Moreau, Martin P.J. Zinser, and David Mathog for the VMS - port. -* David Boldt and Rick Rodgers for sample man pages. -* Brendan Miller for the icon idea. -* Olly Betts for help testing pdftotext. -* Peter Ganten for the OS/2 port. -* Michael Richmond for the Win32 port of pdftops and pdftotext and the - xpdf/cygwin/XFree86 build instructions. -* Frank M. Siegert for improvements in the PostScript code. -* Leo Smiers for the decryption patches. -* Rainer Menzner for creating t1lib, and for helping me adapt it to - xpdf. -* Pine Tree Systems A/S for funding the OPI and EPS support in - pdftops. -* Easy Software Products for funding the "sh" operator support. -* Tom Kacvinsky for help with FreeType and for being my interface to - the FreeType team. -* Theppitak Karoonboonyanan for help with Thai support. -* Leonard Rosenthol for help and contributions on a bunch of things. -* Alexandros Diamantidis and Maria Adaloglou for help with Greek - support. -* Lawrence Lai for help with the CJK Unicode maps. - -Various people have contributed modifications made for use by the -pdftex project: - -* Han The Thanh -* Martin Schröder of ArtCom GmbH - - -References ----------- - -Adobe Systems Inc., _PDF Reference: Adobe Portable Document Format -Version 1.5_. -http://partners.adobe.com/asn/tech/pdf/specifications.jsp -[The manual for PDF version 1.5.] - -Adobe Systems Inc., _PostScript Language Reference_, 3rd ed. -Addison-Wesley, 1999, ISBN 0-201-37922-8. -[The official PostScript manual.] - -Adobe Systems, Inc., _The Type 42 Font Format Specification_, -Adobe Developer Support Technical Specification #5012. 1998. -http://partners.adobe.com/asn/developer/pdfs/tn/5012.Type42_Spec.pdf -[Type 42 is the format used to embed TrueType fonts in PostScript -files.] - -Adobe Systems, Inc., _Adobe CMap and CIDFont Files Specification_, -Adobe Developer Support Technical Specification #5014. 1995. -http://www.adobe.com/supportservice/devrelations/PDFS/TN/5014.CIDFont_Spec.pdf -[CMap file format needed for Japanese and Chinese font support.] - -Adobe Systems, Inc., _Adobe-Japan1-4 Character Collection for -CID-Keyed Fonts_, Adobe Developer Support Technical Note #5078. -2000. -http://partners.adobe.com/asn/developer/PDFS/TN/5078.CID_Glyph.pdf -[The Adobe Japanese character set.] - -Adobe Systems, Inc., _Adobe-GB1-4 Character Collection for -CID-Keyed Fonts_, Adobe Developer Support Technical Note #5079. -2000. -http://partners.adobe.com/asn/developer/pdfs/tn/5079.Adobe-GB1-4.pdf -[The Adobe Chinese GB (simplified) character set.] - -Adobe Systems, Inc., _Adobe-CNS1-3 Character Collection for -CID-Keyed Fonts_, Adobe Developer Support Technical Note #5080. -2000. -http://partners.adobe.com/asn/developer/PDFS/TN/5080.CNS_CharColl.pdf -[The Adobe Chinese CNS (traditional) character set.] - -Adobe Systems Inc., _Supporting the DCT Filters in PostScript Level -2_, Adobe Developer Support Technical Note #5116. 1992. -http://www.adobe.com/supportservice/devrelations/PDFS/TN/5116.PS2_DCT.PDF -[Description of the DCTDecode filter parameters.] - -Adobe Systems Inc., _Open Prepress Interface (OPI) Specification - -Version 2.0_, Adobe Developer Support Technical Note #5660. 2000. -http://partners.adobe.com/asn/developer/PDFS/TN/5660.OPI_2.0.pdf - -Adobe Systems Inc., CMap files. -ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/ -[The actual CMap files for the 16-bit CJK encodings.] - -Adobe Systems Inc., Unicode glyph lists. -http://partners.adobe.com/asn/developer/type/unicodegn.html -http://partners.adobe.com/asn/developer/type/glyphlist.txt -http://partners.adobe.com/asn/developer/type/corporateuse.txt -http://partners.adobe.com/asn/developer/type/zapfdingbats.txt -[Mappings between character names to Unicode.] - -Aldus Corp., _OPI: Open Prepress Interface Specification 1.3_. 1993. -http://partners.adobe.com/asn/developer/PDFS/TN/OPI_13.pdf - -Anonymous, RC4 source code. -ftp://ftp.ox.ac.uk/pub/crypto/misc/rc4.tar.gz -ftp://idea.sec.dsi.unimi.it/pub/crypt/code/rc4.tar.gz -[This is the algorithm used to encrypt PDF files.] - -T. Boutell, et al., "PNG (Portable Network Graphics) Specification, -Version 1.0. RFC 2083. -[PDF uses the PNG filter algorithms.] - -CCITT, "Information Technology - Digital Compression and Coding of -Continuous-tone Still Images - Requirements and Guidelines", CCITT -Recommendation T.81. -http://www.w3.org/Graphics/JPEG/ -[The official JPEG spec.] - -A. Chernov, "Registration of a Cyrillic Character Set". RFC 1489. -[Documentation for the KOI8-R Cyrillic encoding.] - -Roman Czyborra, "The ISO 8859 Alphabet Soup". -http://czyborra.com/charsets/iso8859.html -[Documentation on the various ISO 859 encodings.] - -L. Peter Deutsch, "ZLIB Compressed Data Format Specification version -3.3". RFC 1950. -[Information on the general format used in FlateDecode streams.] - -L. Peter Deutsch, "DEFLATE Compressed Data Format Specification -version 1.3". RFC 1951. -[The definition of the compression algorithm used in FlateDecode -streams.] - -Jim Flowers, "X Logical Font Description Conventions", Version 1.5, X -Consortium Standard, X Version 11, Release 6.1. -ftp://ftp.x.org/pub/R6.1/xc/doc/hardcopy/XLFD/xlfd.PS.Z -[The official specification of X font descriptors, including font -transformation matrices.] - -Foley, van Dam, Feiner, and Hughes, _Computer Graphics: Principles and -Practice_, 2nd ed. Addison-Wesley, 1990, ISBN 0-201-12110-7. -[Colorspace conversion functions, Bezier spline math.] - -Robert L. Hummel, _Programmer's Technical Reference: Data and Fax -Communications_. Ziff-Davis Press, 1993, ISBN 1-56276-077-7. -[CCITT Group 3 and 4 fax decoding.] - -ISO/IEC, _Information technology -- Lossy/lossless coding of bi-level -images_. ISO/IEC 14492, First edition (2001-12-15). -http://webstore.ansi.org/ -[The official JBIG2 standard. The final draft of this spec is -available from http://www.jpeg.org/jbighomepage.html.] - -ISO/IEC, _Information technology -- JPEG 2000 image coding system -- -Part 1: Core coding system_. ISO/IEC 15444-1, First edition -(2000-12-15). -http://webstore.ansi.org/ -[The official JPEG 2000 standard. The final committee draft of this -spec is available from http://www.jpeg.org/JPEG2000.html, but there -were changes made to the bitstream format between that draft and the -published spec.] - -ITU, "Standardization of Group 3 facsimile terminals for document -transmission", ITU-T Recommendation T.4, 1999. -ITU, "Facsimile coding schemes and coding control functions for Group 4 -facsimile apparatus", ITU-T Recommendation T.6, 1993. -http://www.itu.int/ -[The official Group 3 and 4 fax standards - used by the CCITTFaxDecode -stream, as well as the JBIG2Decode stream.] - -Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, "Practical -Fast 1-D DCT Algorithms with 11 Multiplications". IEEE Intl. Conf. on -Acoustics, Speech & Signal Processing, 1989, 988-991. -[The fast IDCT algorithm used in the DCTDecode filter.] - -Microsoft, _TrueType 1.0 Font Files_, rev. 1.66. 1995. -http://www.microsoft.com/typography/tt/tt.htm -[The TrueType font spec (in MS Word format, naturally).] - -Thai Industrial Standard, "Standard for Thai Character Codes for -Computers", TIS-620-2533 (1990). -http://www.nectec.or.th/it-standards/std620/std620.htm -[The TIS-620 Thai encoding.] - -P. Peterlin, "ISO 8859-2 (Latin 2) Resources". -http://sizif.mf.uni-lj.si/linux/cee/iso8859-2.html -[This is a web page with all sorts of useful Latin-2 character set and -font information.] - -Charles Poynton, "Color FAQ". -http://www.inforamp.net/~poynton/ColorFAQ.html -[The mapping from the CIE 1931 (XYZ) color space to RGB.] - -R. Rivest, "The MD5 Message-Digest Algorithm". RFC 1321. -[MD5 is used in PDF document encryption.] - -Unicode Consortium, "Unicode Home Page". -http://www.unicode.org/ -[Online copy of the Unicode spec.] - -W3C Recommendation, "PNG (Portable Network Graphics) Specification -Version 1.0". -http://www.w3.org/Graphics/PNG/ -[Defines the PNG image predictor.] - -Gregory K. Wallace, "The JPEG Still Picture Compression Standard". -ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz -[Good description of the JPEG standard. Also published in CACM, April -1991, and submitted to IEEE Transactions on Consumer Electronics.] - -F. Yergeau, "UTF-8, a transformation format of ISO 10646". RFC 2279. -[A commonly used Unicode encoding.] diff --git a/xpdf/aconf.h b/xpdf/aconf.h deleted file mode 100644 index f86ea517a..000000000 --- a/xpdf/aconf.h +++ /dev/null @@ -1,14 +0,0 @@ -/* define it to 0, if you have it, config.h will have it defined to 1 and that will be used*/ -#define HAVE_FSEEK0 0 - -#include - -#define HAVE_T1LIB_H 0 -#define HAVE_FREETYPE_H HAVE_FREETYPE -#define HAVE_FREETYPE_FREETYPE_H HAVE_FREETYPE -#define OPI_SUPPORT 0 -#define TEXTOUT_WORD_LIST 0 -#define HAVE_MKSTEMPS 1 //libkdefakes provides it -#define SPLASH_CMYK 0 -#define HAVE_XPDFCORE 0 -#define HAVE_WINPDFCORE 0 diff --git a/xpdf/fofi/FoFiBase.cc b/xpdf/fofi/FoFiBase.cc deleted file mode 100644 index 28d0b8ca8..000000000 --- a/xpdf/fofi/FoFiBase.cc +++ /dev/null @@ -1,156 +0,0 @@ -//======================================================================== -// -// FoFiBase.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "FoFiBase.h" - -//------------------------------------------------------------------------ -// FoFiBase -//------------------------------------------------------------------------ - -FoFiBase::FoFiBase(char *fileA, int lenA, GBool freeFileDataA) { - fileData = file = (Guchar *)fileA; - len = lenA; - freeFileData = freeFileDataA; -} - -FoFiBase::~FoFiBase() { - if (freeFileData) { - gfree(fileData); - } -} - -char *FoFiBase::readFile(char *fileName, int *fileLen) { - FILE *f; - char *buf; - int n; - - if (!(f = fopen(fileName, "rb"))) { - return NULL; - } - fseek(f, 0, SEEK_END); - n = (int)ftell(f); - fseek(f, 0, SEEK_SET); - buf = (char *)gmalloc(n); - if ((int)fread(buf, 1, n, f) != n) { - gfree(buf); - fclose(f); - return NULL; - } - fclose(f); - *fileLen = n; - return buf; -} - -int FoFiBase::getS8(int pos, GBool *ok) { - int x; - - if (pos < 0 || pos >= len) { - *ok = gFalse; - return 0; - } - x = file[pos]; - if (x & 0x80) { - x |= ~0xff; - } - return x; -} - -int FoFiBase::getU8(int pos, GBool *ok) { - if (pos < 0 || pos >= len) { - *ok = gFalse; - return 0; - } - return file[pos]; -} - -int FoFiBase::getS16BE(int pos, GBool *ok) { - int x; - - if (pos < 0 || pos+1 >= len) { - *ok = gFalse; - return 0; - } - x = file[pos]; - x = (x << 8) + file[pos+1]; - if (x & 0x8000) { - x |= ~0xffff; - } - return x; -} - -int FoFiBase::getU16BE(int pos, GBool *ok) { - int x; - - if (pos < 0 || pos+1 >= len) { - *ok = gFalse; - return 0; - } - x = file[pos]; - x = (x << 8) + file[pos+1]; - return x; -} - -int FoFiBase::getS32BE(int pos, GBool *ok) { - int x; - - if (pos < 0 || pos+3 >= len) { - *ok = gFalse; - return 0; - } - x = file[pos]; - x = (x << 8) + file[pos+1]; - x = (x << 8) + file[pos+2]; - x = (x << 8) + file[pos+3]; - if (x & 0x80000000) { - x |= ~0xffffffff; - } - return x; -} - -Guint FoFiBase::getU32BE(int pos, GBool *ok) { - Guint x; - - if (pos < 0 || pos+3 >= len) { - *ok = gFalse; - return 0; - } - x = file[pos]; - x = (x << 8) + file[pos+1]; - x = (x << 8) + file[pos+2]; - x = (x << 8) + file[pos+3]; - return x; -} - -Guint FoFiBase::getUVarBE(int pos, int size, GBool *ok) { - Guint x; - int i; - - if (pos < 0 || pos + size > len) { - *ok = gFalse; - return 0; - } - x = 0; - for (i = 0; i < size; ++i) { - x = (x << 8) + file[pos + i]; - } - return x; -} - -GBool FoFiBase::checkRegion(int pos, int size) { - return pos >= 0 && - pos + size >= pos && - pos + size <= len; -} diff --git a/xpdf/fofi/FoFiBase.h b/xpdf/fofi/FoFiBase.h deleted file mode 100644 index 971f63c09..000000000 --- a/xpdf/fofi/FoFiBase.h +++ /dev/null @@ -1,57 +0,0 @@ -//======================================================================== -// -// FoFiBase.h -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef FOFIBASE_H -#define FOFIBASE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -//------------------------------------------------------------------------ - -typedef void (*FoFiOutputFunc)(void *stream, const char *data, int len); - -//------------------------------------------------------------------------ -// FoFiBase -//------------------------------------------------------------------------ - -class FoFiBase { -public: - - virtual ~FoFiBase(); - -protected: - - FoFiBase(char *fileA, int lenA, GBool freeFileDataA); - static char *readFile(char *fileName, int *fileLen); - - // S = signed / U = unsigned - // 8/16/32/Var = word length, in bytes - // BE = big endian - int getS8(int pos, GBool *ok); - int getU8(int pos, GBool *ok); - int getS16BE(int pos, GBool *ok); - int getU16BE(int pos, GBool *ok); - int getS32BE(int pos, GBool *ok); - Guint getU32BE(int pos, GBool *ok); - Guint getUVarBE(int pos, int size, GBool *ok); - - GBool checkRegion(int pos, int size); - - Guchar *fileData; - Guchar *file; - int len; - GBool freeFileData; -}; - -#endif diff --git a/xpdf/fofi/FoFiEncodings.cc b/xpdf/fofi/FoFiEncodings.cc deleted file mode 100644 index e654fab19..000000000 --- a/xpdf/fofi/FoFiEncodings.cc +++ /dev/null @@ -1,994 +0,0 @@ -//======================================================================== -// -// FoFiEncodings.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "FoFiEncodings.h" - -//------------------------------------------------------------------------ -// Type 1 and 1C font data -//------------------------------------------------------------------------ - -const char *fofiType1StandardEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotesingle", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - NULL, - "endash", - "dagger", - "daggerdbl", - "periodcentered", - NULL, - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - NULL, - "questiondown", - NULL, - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - NULL, - "ring", - "cedilla", - NULL, - "hungarumlaut", - "ogonek", - "caron", - "emdash", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "AE", - NULL, - "ordfeminine", - NULL, - NULL, - NULL, - NULL, - "Lslash", - "Oslash", - "OE", - "ordmasculine", - NULL, - NULL, - NULL, - NULL, - NULL, - "ae", - NULL, - NULL, - NULL, - "dotlessi", - NULL, - NULL, - "lslash", - "oslash", - "oe", - "germandbls", - NULL, - NULL, - NULL, - NULL -}; - -const char *fofiType1ExpertEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclamsmall", - "Hungarumlautsmall", - NULL, - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "comma", - "hyphen", - "period", - "fraction", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "colon", - "semicolon", - "commasuperior", - "threequartersemdash", - "periodsuperior", - "questionsmall", - NULL, - "asuperior", - "bsuperior", - "centsuperior", - "dsuperior", - "esuperior", - NULL, - NULL, - NULL, - "isuperior", - NULL, - NULL, - "lsuperior", - "msuperior", - "nsuperior", - "osuperior", - NULL, - NULL, - "rsuperior", - "ssuperior", - "tsuperior", - NULL, - "ff", - "fi", - "fl", - "ffi", - "ffl", - "parenleftinferior", - NULL, - "parenrightinferior", - "Circumflexsmall", - "hyphensuperior", - "Gravesmall", - "Asmall", - "Bsmall", - "Csmall", - "Dsmall", - "Esmall", - "Fsmall", - "Gsmall", - "Hsmall", - "Ismall", - "Jsmall", - "Ksmall", - "Lsmall", - "Msmall", - "Nsmall", - "Osmall", - "Psmall", - "Qsmall", - "Rsmall", - "Ssmall", - "Tsmall", - "Usmall", - "Vsmall", - "Wsmall", - "Xsmall", - "Ysmall", - "Zsmall", - "colonmonetary", - "onefitted", - "rupiah", - "Tildesmall", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "exclamdownsmall", - "centoldstyle", - "Lslashsmall", - NULL, - NULL, - "Scaronsmall", - "Zcaronsmall", - "Dieresissmall", - "Brevesmall", - "Caronsmall", - NULL, - "Dotaccentsmall", - NULL, - NULL, - "Macronsmall", - NULL, - NULL, - "figuredash", - "hypheninferior", - NULL, - NULL, - "Ogoneksmall", - "Ringsmall", - "Cedillasmall", - NULL, - NULL, - NULL, - "onequarter", - "onehalf", - "threequarters", - "questiondownsmall", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - NULL, - NULL, - "zerosuperior", - "onesuperior", - "twosuperior", - "threesuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "eightsuperior", - "ninesuperior", - "zeroinferior", - "oneinferior", - "twoinferior", - "threeinferior", - "fourinferior", - "fiveinferior", - "sixinferior", - "seveninferior", - "eightinferior", - "nineinferior", - "centinferior", - "dollarinferior", - "periodinferior", - "commainferior", - "Agravesmall", - "Aacutesmall", - "Acircumflexsmall", - "Atildesmall", - "Adieresissmall", - "Aringsmall", - "AEsmall", - "Ccedillasmall", - "Egravesmall", - "Eacutesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Igravesmall", - "Iacutesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ethsmall", - "Ntildesmall", - "Ogravesmall", - "Oacutesmall", - "Ocircumflexsmall", - "Otildesmall", - "Odieresissmall", - "OEsmall", - "Oslashsmall", - "Ugravesmall", - "Uacutesmall", - "Ucircumflexsmall", - "Udieresissmall", - "Yacutesmall", - "Thornsmall", - "Ydieresissmall" -}; - -//------------------------------------------------------------------------ -// Type 1C font data -//------------------------------------------------------------------------ - -const char *fofiType1CStdStrings[391] = { - ".notdef", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotesingle", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "endash", - "dagger", - "daggerdbl", - "periodcentered", - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - "questiondown", - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "emdash", - "AE", - "ordfeminine", - "Lslash", - "Oslash", - "OE", - "ordmasculine", - "ae", - "dotlessi", - "lslash", - "oslash", - "oe", - "germandbls", - "onesuperior", - "logicalnot", - "mu", - "trademark", - "Eth", - "onehalf", - "plusminus", - "Thorn", - "onequarter", - "divide", - "brokenbar", - "degree", - "thorn", - "threequarters", - "twosuperior", - "registered", - "minus", - "eth", - "multiply", - "threesuperior", - "copyright", - "Aacute", - "Acircumflex", - "Adieresis", - "Agrave", - "Aring", - "Atilde", - "Ccedilla", - "Eacute", - "Ecircumflex", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Ntilde", - "Oacute", - "Ocircumflex", - "Odieresis", - "Ograve", - "Otilde", - "Scaron", - "Uacute", - "Ucircumflex", - "Udieresis", - "Ugrave", - "Yacute", - "Ydieresis", - "Zcaron", - "aacute", - "acircumflex", - "adieresis", - "agrave", - "aring", - "atilde", - "ccedilla", - "eacute", - "ecircumflex", - "edieresis", - "egrave", - "iacute", - "icircumflex", - "idieresis", - "igrave", - "ntilde", - "oacute", - "ocircumflex", - "odieresis", - "ograve", - "otilde", - "scaron", - "uacute", - "ucircumflex", - "udieresis", - "ugrave", - "yacute", - "ydieresis", - "zcaron", - "exclamsmall", - "Hungarumlautsmall", - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "commasuperior", - "threequartersemdash", - "periodsuperior", - "questionsmall", - "asuperior", - "bsuperior", - "centsuperior", - "dsuperior", - "esuperior", - "isuperior", - "lsuperior", - "msuperior", - "nsuperior", - "osuperior", - "rsuperior", - "ssuperior", - "tsuperior", - "ff", - "ffi", - "ffl", - "parenleftinferior", - "parenrightinferior", - "Circumflexsmall", - "hyphensuperior", - "Gravesmall", - "Asmall", - "Bsmall", - "Csmall", - "Dsmall", - "Esmall", - "Fsmall", - "Gsmall", - "Hsmall", - "Ismall", - "Jsmall", - "Ksmall", - "Lsmall", - "Msmall", - "Nsmall", - "Osmall", - "Psmall", - "Qsmall", - "Rsmall", - "Ssmall", - "Tsmall", - "Usmall", - "Vsmall", - "Wsmall", - "Xsmall", - "Ysmall", - "Zsmall", - "colonmonetary", - "onefitted", - "rupiah", - "Tildesmall", - "exclamdownsmall", - "centoldstyle", - "Lslashsmall", - "Scaronsmall", - "Zcaronsmall", - "Dieresissmall", - "Brevesmall", - "Caronsmall", - "Dotaccentsmall", - "Macronsmall", - "figuredash", - "hypheninferior", - "Ogoneksmall", - "Ringsmall", - "Cedillasmall", - "questiondownsmall", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - "zerosuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "eightsuperior", - "ninesuperior", - "zeroinferior", - "oneinferior", - "twoinferior", - "threeinferior", - "fourinferior", - "fiveinferior", - "sixinferior", - "seveninferior", - "eightinferior", - "nineinferior", - "centinferior", - "dollarinferior", - "periodinferior", - "commainferior", - "Agravesmall", - "Aacutesmall", - "Acircumflexsmall", - "Atildesmall", - "Adieresissmall", - "Aringsmall", - "AEsmall", - "Ccedillasmall", - "Egravesmall", - "Eacutesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Igravesmall", - "Iacutesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ethsmall", - "Ntildesmall", - "Ogravesmall", - "Oacutesmall", - "Ocircumflexsmall", - "Otildesmall", - "Odieresissmall", - "OEsmall", - "Oslashsmall", - "Ugravesmall", - "Uacutesmall", - "Ucircumflexsmall", - "Udieresissmall", - "Yacutesmall", - "Thornsmall", - "Ydieresissmall", - "001.000", - "001.001", - "001.002", - "001.003", - "Black", - "Bold", - "Book", - "Light", - "Medium", - "Regular", - "Roman", - "Semibold" -}; - -Gushort fofiType1CISOAdobeCharset[229] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228 -}; - -Gushort fofiType1CExpertCharset[166] = { - 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, - 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, - 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, - 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, - 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, - 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378 -}; - -Gushort fofiType1CExpertSubsetCharset[87] = { - 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, - 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, - 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, - 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, - 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346 -}; diff --git a/xpdf/fofi/FoFiEncodings.h b/xpdf/fofi/FoFiEncodings.h deleted file mode 100644 index dd85458c0..000000000 --- a/xpdf/fofi/FoFiEncodings.h +++ /dev/null @@ -1,36 +0,0 @@ -//======================================================================== -// -// FoFiEncodings.h -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef FOFIENCODINGS_H -#define FOFIENCODINGS_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -//------------------------------------------------------------------------ -// Type 1 and 1C font data -//------------------------------------------------------------------------ - -extern const char *fofiType1StandardEncoding[256]; -extern const char *fofiType1ExpertEncoding[256]; - -//------------------------------------------------------------------------ -// Type 1C font data -//------------------------------------------------------------------------ - -extern const char *fofiType1CStdStrings[391]; -extern Gushort fofiType1CISOAdobeCharset[229]; -extern Gushort fofiType1CExpertCharset[166]; -extern Gushort fofiType1CExpertSubsetCharset[87]; - -#endif diff --git a/xpdf/fofi/FoFiTrueType.cc b/xpdf/fofi/FoFiTrueType.cc deleted file mode 100644 index 4165b8cad..000000000 --- a/xpdf/fofi/FoFiTrueType.cc +++ /dev/null @@ -1,1764 +0,0 @@ -//======================================================================== -// -// FoFiTrueType.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gtypes.h" -#include "gmem.h" -#include "GString.h" -#include "GHash.h" -#include "FoFiTrueType.h" - -// -// Terminology -// ----------- -// -// character code = number used as an element of a text string -// -// character name = glyph name = name for a particular glyph within a -// font -// -// glyph index = GID = position (within some internal table in the font) -// where the instructions to draw a particular glyph are -// stored -// -// Type 1 fonts -// ------------ -// -// Type 1 fonts contain: -// -// Encoding: array of glyph names, maps char codes to glyph names -// -// Encoding[charCode] = charName -// -// CharStrings: dictionary of instructions, keyed by character names, -// maps character name to glyph data -// -// CharStrings[charName] = glyphData -// -// TrueType fonts -// -------------- -// -// TrueType fonts contain: -// -// 'cmap' table: mapping from character code to glyph index; there may -// be multiple cmaps in a TrueType font -// -// cmap[charCode] = gid -// -// 'post' table: mapping from glyph index to glyph name -// -// post[gid] = glyphName -// -// Type 42 fonts -// ------------- -// -// Type 42 fonts contain: -// -// Encoding: array of glyph names, maps char codes to glyph names -// -// Encoding[charCode] = charName -// -// CharStrings: dictionary of glyph indexes, keyed by character names, -// maps character name to glyph index -// -// CharStrings[charName] = gid -// - -//------------------------------------------------------------------------ - -#define ttcfTag 0x74746366 - -//------------------------------------------------------------------------ - -struct TrueTypeTable { - Guint tag; - Guint checksum; - int offset; - int origOffset; - int len; -}; - -struct TrueTypeCmap { - int platform; - int encoding; - int offset; - int len; - int fmt; -}; - -struct TrueTypeLoca { - int idx; - int origOffset; - int newOffset; - int len; -}; - -#define cmapTag 0x636d6170 -#define glyfTag 0x676c7966 -#define headTag 0x68656164 -#define locaTag 0x6c6f6361 -#define nameTag 0x6e616d65 -#define postTag 0x706f7374 - -static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) { - TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; - TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; - - if (loca1->origOffset == loca2->origOffset) { - return loca1->idx - loca2->idx; - } - return loca1->origOffset - loca2->origOffset; -} - -static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) { - TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; - TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; - - return loca1->idx - loca2->idx; -} - -static int cmpTrueTypeTableTag(const void *p1, const void *p2) { - TrueTypeTable *tab1 = (TrueTypeTable *)p1; - TrueTypeTable *tab2 = (TrueTypeTable *)p2; - - return (int)tab1->tag - (int)tab2->tag; -} - -//------------------------------------------------------------------------ - -struct T42Table { - const char *tag; // 4-byte tag - GBool required; // required by the TrueType spec? -}; - -// TrueType tables to be embedded in Type 42 fonts. -// NB: the table names must be in alphabetical order here. -#define nT42Tables 11 -static T42Table t42Tables[nT42Tables] = { - { "cvt ", gTrue }, - { "fpgm", gTrue }, - { "glyf", gTrue }, - { "head", gTrue }, - { "hhea", gTrue }, - { "hmtx", gTrue }, - { "loca", gTrue }, - { "maxp", gTrue }, - { "prep", gTrue }, - { "vhea", gFalse }, - { "vmtx", gFalse } -}; -#define t42HeadTable 3 -#define t42LocaTable 6 -#define t42GlyfTable 2 -#define t42VheaTable 9 -#define t42VmtxTable 10 - -//------------------------------------------------------------------------ - -// Glyph names in some arbitrary standard order that Apple uses for -// their TrueType fonts. -static const char *macGlyphNames[258] = { - ".notdef", "null", "CR", "space", - "exclam", "quotedbl", "numbersign", "dollar", - "percent", "ampersand", "quotesingle", "parenleft", - "parenright", "asterisk", "plus", "comma", - "hyphen", "period", "slash", "zero", - "one", "two", "three", "four", - "five", "six", "seven", "eight", - "nine", "colon", "semicolon", "less", - "equal", "greater", "question", "at", - "A", "B", "C", "D", - "E", "F", "G", "H", - "I", "J", "K", "L", - "M", "N", "O", "P", - "Q", "R", "S", "T", - "U", "V", "W", "X", - "Y", "Z", "bracketleft", "backslash", - "bracketright", "asciicircum", "underscore", "grave", - "a", "b", "c", "d", - "e", "f", "g", "h", - "i", "j", "k", "l", - "m", "n", "o", "p", - "q", "r", "s", "t", - "u", "v", "w", "x", - "y", "z", "braceleft", "bar", - "braceright", "asciitilde", "Adieresis", "Aring", - "Ccedilla", "Eacute", "Ntilde", "Odieresis", - "Udieresis", "aacute", "agrave", "acircumflex", - "adieresis", "atilde", "aring", "ccedilla", - "eacute", "egrave", "ecircumflex", "edieresis", - "iacute", "igrave", "icircumflex", "idieresis", - "ntilde", "oacute", "ograve", "ocircumflex", - "odieresis", "otilde", "uacute", "ugrave", - "ucircumflex", "udieresis", "dagger", "degree", - "cent", "sterling", "section", "bullet", - "paragraph", "germandbls", "registered", "copyright", - "trademark", "acute", "dieresis", "notequal", - "AE", "Oslash", "infinity", "plusminus", - "lessequal", "greaterequal", "yen", "mu1", - "partialdiff", "summation", "product", "pi", - "integral", "ordfeminine", "ordmasculine", "Ohm", - "ae", "oslash", "questiondown", "exclamdown", - "logicalnot", "radical", "florin", "approxequal", - "increment", "guillemotleft", "guillemotright", "ellipsis", - "nbspace", "Agrave", "Atilde", "Otilde", - "OE", "oe", "endash", "emdash", - "quotedblleft", "quotedblright", "quoteleft", "quoteright", - "divide", "lozenge", "ydieresis", "Ydieresis", - "fraction", "currency", "guilsinglleft", "guilsinglright", - "fi", "fl", "daggerdbl", "periodcentered", - "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", - "Ecircumflex", "Aacute", "Edieresis", "Egrave", - "Iacute", "Icircumflex", "Idieresis", "Igrave", - "Oacute", "Ocircumflex", "applelogo", "Ograve", - "Uacute", "Ucircumflex", "Ugrave", "dotlessi", - "circumflex", "tilde", "overscore", "breve", - "dotaccent", "ring", "cedilla", "hungarumlaut", - "ogonek", "caron", "Lslash", "lslash", - "Scaron", "scaron", "Zcaron", "zcaron", - "brokenbar", "Eth", "eth", "Yacute", - "yacute", "Thorn", "thorn", "minus", - "multiply", "onesuperior", "twosuperior", "threesuperior", - "onehalf", "onequarter", "threequarters", "franc", - "Gbreve", "gbreve", "Idot", "Scedilla", - "scedilla", "Cacute", "cacute", "Ccaron", - "ccaron", "dmacron" -}; - -//------------------------------------------------------------------------ -// FoFiTrueType -//------------------------------------------------------------------------ - -FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int faceIndexA) { - FoFiTrueType *ff; - - ff = new FoFiTrueType(fileA, lenA, gFalse, faceIndexA); - if (!ff->parsedOk) { - delete ff; - return NULL; - } - return ff; -} - -FoFiTrueType *FoFiTrueType::load(char *fileName, int faceIndexA) { - FoFiTrueType *ff; - char *fileA; - int lenA; - - if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { - return NULL; - } - ff = new FoFiTrueType(fileA, lenA, gTrue, faceIndexA); - if (!ff->parsedOk) { - delete ff; - return NULL; - } - return ff; -} - -FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA): - FoFiBase(fileA, lenA, freeFileDataA) -{ - tables = NULL; - nTables = 0; - cmaps = NULL; - nCmaps = 0; - nameToGID = NULL; - parsedOk = gFalse; - faceIndex = faceIndexA; - - parse(); -} - -FoFiTrueType::~FoFiTrueType() { - gfree(tables); - gfree(cmaps); - if (nameToGID) { - delete nameToGID; - } -} - -int FoFiTrueType::getNumCmaps() { - return nCmaps; -} - -int FoFiTrueType::getCmapPlatform(int i) { - return cmaps[i].platform; -} - -int FoFiTrueType::getCmapEncoding(int i) { - return cmaps[i].encoding; -} - -int FoFiTrueType::findCmap(int platform, int encoding) { - int i; - - for (i = 0; i < nCmaps; ++i) { - if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) { - return i; - } - } - return -1; -} - -Gushort FoFiTrueType::mapCodeToGID(int i, int c) { - Gushort gid; - int segCnt, segEnd, segStart, segDelta, segOffset; - int cmapFirst, cmapLen; - int pos, a, b, m; - GBool ok; - - if (i < 0 || i >= nCmaps) { - return 0; - } - ok = gTrue; - pos = cmaps[i].offset; - switch (cmaps[i].fmt) { - case 0: - if (c < 0 || c >= cmaps[i].len - 6) { - return 0; - } - gid = getU8(cmaps[i].offset + 6 + c, &ok); - break; - case 4: - segCnt = getU16BE(pos + 6, &ok) / 2; - a = -1; - b = segCnt - 1; - segEnd = getU16BE(pos + 14 + 2*b, &ok); - if (c > segEnd) { - // malformed font -- the TrueType spec requires the last segEnd - // to be 0xffff - return 0; - } - // invariant: seg[a].end < code <= seg[b].end - while (b - a > 1 && ok) { - m = (a + b) / 2; - segEnd = getU16BE(pos + 14 + 2*m, &ok); - if (segEnd < c) { - a = m; - } else { - b = m; - } - } - segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok); - segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok); - segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok); - if (c < segStart) { - return 0; - } - if (segOffset == 0) { - gid = (c + segDelta) & 0xffff; - } else { - gid = getU16BE(pos + 16 + 6*segCnt + 2*b + - segOffset + 2 * (c - segStart), &ok); - if (gid != 0) { - gid = (gid + segDelta) & 0xffff; - } - } - break; - case 6: - cmapFirst = getU16BE(pos + 6, &ok); - cmapLen = getU16BE(pos + 8, &ok); - if (c < cmapFirst || c >= cmapFirst + cmapLen) { - return 0; - } - gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok); - break; - default: - return 0; - } - if (!ok) { - return 0; - } - return gid; -} - -int FoFiTrueType::mapNameToGID(const char *name) { - if (!nameToGID) { - return 0; - } - return nameToGID->lookupInt(name); -} - -int FoFiTrueType::getEmbeddingRights() { - int i, fsType; - GBool ok; - - if ((i = seekTable("OS/2")) < 0) { - return 4; - } - ok = gTrue; - fsType = getU16BE(tables[i].offset + 8, &ok); - if (!ok) { - return 4; - } - if (fsType & 0x0008) { - return 2; - } - if (fsType & 0x0004) { - return 1; - } - if (fsType & 0x0002) { - return 0; - } - return 3; -} - -void FoFiTrueType::convertToType42(char *psName, const char **encoding, - Gushort *codeToGID, - FoFiOutputFunc outputFunc, - void *outputStream) { - char buf[512]; - GBool ok; - - // write the header - ok = gTrue; - sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0); - (*outputFunc)(outputStream, buf, strlen(buf)); - - // begin the font dictionary - (*outputFunc)(outputStream, "10 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - - // write the guts of the dictionary - cvtEncoding(encoding, outputFunc, outputStream); - cvtCharStrings(encoding, codeToGID, outputFunc, outputStream); - cvtSfnts(outputFunc, outputStream, NULL, gFalse); - - // end the dictionary and define the font - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); -} - -void FoFiTrueType::convertToCIDType2(char *psName, - Gushort *cidMap, int nCIDs, - GBool needVerticalMetrics, - FoFiOutputFunc outputFunc, - void *outputStream) { - char buf[512]; - Gushort cid; - GBool ok; - int i, j, k; - - // write the header - ok = gTrue; - sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0); - (*outputFunc)(outputStream, buf, strlen(buf)); - - // begin the font dictionary - (*outputFunc)(outputStream, "20 dict begin\n", 14); - (*outputFunc)(outputStream, "/CIDFontName /", 14); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); - (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); - (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); - (*outputFunc)(outputStream, " /Supplement 0 def\n", 20); - (*outputFunc)(outputStream, " end def\n", 10); - (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15); - if (cidMap) { - sprintf(buf, "/CIDCount %d def\n", nCIDs); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (nCIDs > 32767) { - (*outputFunc)(outputStream, "/CIDMap [", 9); - for (i = 0; i < nCIDs; i += 32768 - 16) { - (*outputFunc)(outputStream, "<\n", 2); - for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) { - (*outputFunc)(outputStream, " ", 2); - for (k = 0; k < 16 && i+j+k < nCIDs; ++k) { - cid = cidMap[i+j+k]; - sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "\n", 1); - } - (*outputFunc)(outputStream, " >", 3); - } - (*outputFunc)(outputStream, "\n", 1); - (*outputFunc)(outputStream, "] def\n", 6); - } else { - (*outputFunc)(outputStream, "/CIDMap <\n", 10); - for (i = 0; i < nCIDs; i += 16) { - (*outputFunc)(outputStream, " ", 2); - for (j = 0; j < 16 && i+j < nCIDs; ++j) { - cid = cidMap[i+j]; - sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "\n", 1); - } - (*outputFunc)(outputStream, "> def\n", 6); - } - } else { - // direct mapping - just fill the string(s) with s[i]=i - sprintf(buf, "/CIDCount %d def\n", nGlyphs); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (nGlyphs > 32767) { - (*outputFunc)(outputStream, "/CIDMap [\n", 10); - for (i = 0; i < nGlyphs; i += 32767) { - j = nGlyphs - i < 32767 ? nGlyphs - i : 32767; - sprintf(buf, " %d string 0 1 %d {\n", 2 * j, j - 1); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 1 index exch dup 2 mul 1 add exch %d add" - " 255 and put\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, " } for\n", 8); - } - (*outputFunc)(outputStream, "] def\n", 6); - } else { - sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 0 1 %d {\n", nGlyphs - 1); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, - " 2 copy dup 2 mul exch -8 bitshift put\n", 42); - (*outputFunc)(outputStream, - " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50); - (*outputFunc)(outputStream, " } for\n", 8); - (*outputFunc)(outputStream, "def\n", 4); - } - } - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26); - (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30); - (*outputFunc)(outputStream, " /.notdef 0 def\n", 17); - (*outputFunc)(outputStream, " end readonly def\n", 19); - - // write the guts of the dictionary - cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics); - - // end the dictionary and define the font - (*outputFunc)(outputStream, - "CIDFontName currentdict end /CIDFont defineresource pop\n", - 56); -} - -void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, - GBool needVerticalMetrics, - FoFiOutputFunc outputFunc, - void *outputStream) { - char buf[512]; - GString *sfntsName; - int n, i, j; - - // write the Type 42 sfnts array - sfntsName = (new GString(psName))->append("_sfnts"); - cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics); - delete sfntsName; - - // write the descendant Type 42 fonts - n = cidMap ? nCIDs : nGlyphs; - for (i = 0; i < n; i += 256) { - (*outputFunc)(outputStream, "10 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - sprintf(buf, "_%02x def\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - (*outputFunc)(outputStream, "/sfnts ", 7); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, "_sfnts def\n", 11); - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - for (j = 0; j < 256 && i+j < n; ++j) { - sprintf(buf, "dup %d /c%02x put\n", j, j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "readonly def\n", 13); - (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32); - (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); - for (j = 0; j < 256 && i+j < n; ++j) { - sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "end readonly def\n", 17); - (*outputFunc)(outputStream, - "FontName currentdict end definefont pop\n", 40); - } - - // write the Type 0 parent font - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 0 def\n", 16); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); - (*outputFunc)(outputStream, "/Encoding [\n", 12); - for (i = 0; i < n; i += 256) { - sprintf(buf, "%d\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "/FDepVector [\n", 14); - for (i = 0; i < n; i += 256) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, psName, strlen(psName)); - sprintf(buf, "_%02x findfont\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); -} - -void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, - void *outputStream, char *name, - Gushort *codeToGID) { - // this substitute cmap table maps char codes 0000-ffff directly to - // glyphs 0000-ffff - static char cmapTab[36] = { - 0, 0, // table version number - 0, 1, // number of encoding tables - 0, 1, // platform ID - 0, 0, // encoding ID - 0, 0, 0, 12, // offset of subtable - 0, 4, // subtable format - 0, 24, // subtable length - 0, 0, // subtable version - 0, 2, // segment count * 2 - 0, 2, // 2 * 2 ^ floor(log2(segCount)) - 0, 0, // floor(log2(segCount)) - 0, 0, // 2*segCount - 2*2^floor(log2(segCount)) - (char)0xff, (char)0xff, // endCount[0] - 0, 0, // reserved - 0, 0, // startCount[0] - 0, 0, // idDelta[0] - 0, 0 // pad to a mulitple of four bytes - }; - static char nameTab[8] = { - 0, 0, // format - 0, 0, // number of name records - 0, 6, // offset to start of string storage - 0, 0 // pad to multiple of four bytes - }; - static char postTab[32] = { - 0, 1, 0, 0, // format - 0, 0, 0, 0, // italic angle - 0, 0, // underline position - 0, 0, // underline thickness - 0, 0, 0, 0, // fixed pitch - 0, 0, 0, 0, // min Type 42 memory - 0, 0, 0, 0, // max Type 42 memory - 0, 0, 0, 0, // min Type 1 memory - 0, 0, 0, 0 // max Type 1 memory - }; - GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen; - int nZeroLengthTables; - TrueTypeLoca *locaTable; - TrueTypeTable *newTables; - char *newNameTab, *newCmapTab; - int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next; - Guint locaChecksum, glyfChecksum, fileChecksum; - char *tableDir; - char locaBuf[4], checksumBuf[4]; - GBool ok; - Guint t; - int pos, i, j, k, n; - - // check for missing tables - missingCmap = (cmapIdx = seekTable("cmap")) < 0; - missingName = seekTable("name") < 0; - missingPost = seekTable("post") < 0; - - // read the loca table, check to see if it's sorted - locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); - unsortedLoca = gFalse; - i = seekTable("loca"); - pos = tables[i].offset; - ok = gTrue; - for (i = 0; i <= nGlyphs; ++i) { - if (locaFmt) { - locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); - } else { - locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); - } - if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) { - unsortedLoca = gTrue; - } - locaTable[i].idx = i; - } - - // check for zero-length tables - nZeroLengthTables = 0; - for (i = 0; i < nTables; ++i) { - if (tables[i].len == 0) { - ++nZeroLengthTables; - } - } - - // check for an incorrect cmap table length - badCmapLen = gFalse; - cmapLen = 0; // make gcc happy - if (!missingCmap) { - cmapLen = cmaps[0].offset + cmaps[0].len; - for (i = 1; i < nCmaps; ++i) { - if (cmaps[i].offset + cmaps[i].len > cmapLen) { - cmapLen = cmaps[i].offset + cmaps[i].len; - } - } - cmapLen -= tables[cmapIdx].offset; - if (cmapLen > tables[cmapIdx].len) { - badCmapLen = gTrue; - } - } - - // if nothing is broken, just write the TTF file as is - if (!missingCmap && !missingName && !missingPost && !unsortedLoca && - !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) { - (*outputFunc)(outputStream, (char *)file, len); - goto done1; - } - - // sort the 'loca' table: some (non-compliant) fonts have - // out-of-order loca tables; in order to correctly handle the case - // where (compliant) fonts have empty entries in the middle of the - // table, cmpTrueTypeLocaOffset uses offset as its primary sort key, - // and idx as its secondary key (ensuring that adjacent entries with - // the same pos value remain in the same order) - glyfLen = 0; // make gcc happy - if (unsortedLoca) { - qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), - &cmpTrueTypeLocaOffset); - for (i = 0; i < nGlyphs; ++i) { - locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; - } - locaTable[nGlyphs].len = 0; - qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), - &cmpTrueTypeLocaIdx); - pos = 0; - for (i = 0; i <= nGlyphs; ++i) { - locaTable[i].newOffset = pos; - pos += locaTable[i].len; - if (pos & 3) { - pos += 4 - (pos & 3); - } - } - glyfLen = pos; - } - - // compute checksums for the loca and glyf tables - locaChecksum = glyfChecksum = 0; - if (unsortedLoca) { - if (locaFmt) { - for (j = 0; j <= nGlyphs; ++j) { - locaChecksum += locaTable[j].newOffset; - } - } else { - for (j = 0; j <= nGlyphs; j += 2) { - locaChecksum += locaTable[j].newOffset << 16; - if (j + 1 <= nGlyphs) { - locaChecksum += locaTable[j+1].newOffset; - } - } - } - pos = tables[seekTable("glyf")].offset; - for (j = 0; j < nGlyphs; ++j) { - n = locaTable[j].len; - if (n > 0) { - k = locaTable[j].origOffset; - if (checkRegion(pos + k, n)) { - glyfChecksum += computeTableChecksum(file + pos + k, n); - } - } - } - } - - // construct the new name table - if (name) { - n = strlen(name); - newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3; - newNameTab = (char *)gmalloc(newNameLen); - memset(newNameTab, 0, newNameLen); - newNameTab[0] = 0; // format selector - newNameTab[1] = 0; - newNameTab[2] = 0; // number of name records - newNameTab[3] = 4; - newNameTab[4] = 0; // offset to start of string storage - newNameTab[5] = 6 + 4*12; - next = 0; - for (i = 0; i < 4; ++i) { - newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft - newNameTab[6 + i*12 + 1] = 3; - newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode - newNameTab[6 + i*12 + 3] = 1; - newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English - newNameTab[6 + i*12 + 5] = 0x09; - newNameTab[6 + i*12 + 6] = 0; // name ID - newNameTab[6 + i*12 + 7] = i + 1; - newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length - newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff); - newNameTab[6 + i*12 + 10] = next >> 8; // string offset - newNameTab[6 + i*12 + 11] = next & 0xff; - if (i+1 == 2) { - memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14); - next += 14; - } else { - for (j = 0; j < n; ++j) { - newNameTab[6 + 4*12 + next + 2*j] = 0; - newNameTab[6 + 4*12 + next + 2*j + 1] = name[j]; - } - next += 2*n; - } - } - } else { - newNameLen = 0; - newNameTab = NULL; - } - - // construct the new cmap table - if (codeToGID) { - newCmapLen = 44 + 256 * 2; - newCmapTab = (char *)gmalloc(newCmapLen); - newCmapTab[0] = 0; // table version number = 0 - newCmapTab[1] = 0; - newCmapTab[2] = 0; // number of encoding tables = 1 - newCmapTab[3] = 1; - newCmapTab[4] = 0; // platform ID = Microsoft - newCmapTab[5] = 3; - newCmapTab[6] = 0; // encoding ID = Unicode - newCmapTab[7] = 1; - newCmapTab[8] = 0; // offset of subtable - newCmapTab[9] = 0; - newCmapTab[10] = 0; - newCmapTab[11] = 12; - newCmapTab[12] = 0; // subtable format = 4 - newCmapTab[13] = 4; - newCmapTab[14] = 0x02; // subtable length - newCmapTab[15] = 0x20; - newCmapTab[16] = 0; // subtable version = 0 - newCmapTab[17] = 0; - newCmapTab[18] = 0; // segment count * 2 - newCmapTab[19] = 4; - newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount)) - newCmapTab[21] = 4; - newCmapTab[22] = 0; // floor(log2(segCount)) - newCmapTab[23] = 1; - newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount)) - newCmapTab[25] = 0; - newCmapTab[26] = 0x00; // endCount[0] - newCmapTab[27] = (char)0xff; - newCmapTab[28] = (char)0xff; // endCount[1] - newCmapTab[29] = (char)0xff; - newCmapTab[30] = 0; // reserved - newCmapTab[31] = 0; - newCmapTab[32] = 0x00; // startCount[0] - newCmapTab[33] = 0x00; - newCmapTab[34] = (char)0xff; // startCount[1] - newCmapTab[35] = (char)0xff; - newCmapTab[36] = 0; // idDelta[0] - newCmapTab[37] = 0; - newCmapTab[38] = 0; // idDelta[1] - newCmapTab[39] = 1; - newCmapTab[40] = 0; // idRangeOffset[0] - newCmapTab[41] = 4; - newCmapTab[42] = 0; // idRangeOffset[1] - newCmapTab[43] = 0; - for (i = 0; i < 256; ++i) { - newCmapTab[44 + 2*i] = codeToGID[i] >> 8; - newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff; - } - } else { - newCmapLen = 0; - newCmapTab = NULL; - } - - // construct the new table directory: - // - keep all original tables with non-zero length - // - fix the cmap table's length, if necessary - // - add missing tables - // - sort the table by tag - // - compute new table positions, including 4-byte alignment - // - (re)compute table checksums - nNewTables = nTables - nZeroLengthTables + - (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + - (missingPost ? 1 : 0); - newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); - j = 0; - for (i = 0; i < nTables; ++i) { - if (tables[i].len > 0) { - newTables[j] = tables[i]; - newTables[j].origOffset = tables[i].offset; - if (checkRegion(tables[i].offset, newTables[i].len)) { - newTables[j].checksum = - computeTableChecksum(file + tables[i].offset, tables[i].len); - if (tables[i].tag == headTag) { - // don't include the file checksum - newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); - } - } - if (newTables[j].tag == cmapTag && codeToGID) { - newTables[j].len = newCmapLen; - newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, - newCmapLen); - } else if (newTables[j].tag == cmapTag && badCmapLen) { - newTables[j].len = cmapLen; - } else if (newTables[j].tag == locaTag && unsortedLoca) { - newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); - newTables[j].checksum = locaChecksum; - } else if (newTables[j].tag == glyfTag && unsortedLoca) { - newTables[j].len = glyfLen; - newTables[j].checksum = glyfChecksum; - } else if (newTables[j].tag == nameTag && name) { - newTables[j].len = newNameLen; - newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, - newNameLen); - } - ++j; - } - } - if (missingCmap) { - newTables[j].tag = cmapTag; - if (codeToGID) { - newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, - newCmapLen); - newTables[j].len = newCmapLen; - } else { - newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, - sizeof(cmapTab)); - newTables[j].len = sizeof(cmapTab); - } - ++j; - } - if (missingName) { - newTables[j].tag = nameTag; - if (name) { - newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, - newNameLen); - newTables[j].len = newNameLen; - } else { - newTables[j].checksum = computeTableChecksum((Guchar *)nameTab, - sizeof(nameTab)); - newTables[j].len = sizeof(nameTab); - } - ++j; - } - if (missingPost) { - newTables[j].tag = postTag; - newTables[j].checksum = computeTableChecksum((Guchar *)postTab, - sizeof(postTab)); - newTables[j].len = sizeof(postTab); - ++j; - } - qsort(newTables, nNewTables, sizeof(TrueTypeTable), - &cmpTrueTypeTableTag); - pos = 12 + nNewTables * 16; - for (i = 0; i < nNewTables; ++i) { - newTables[i].offset = pos; - pos += newTables[i].len; - if (pos & 3) { - pos += 4 - (pos & 3); - } - } - - // write the table directory - tableDir = (char *)gmalloc(12 + nNewTables * 16); - tableDir[0] = 0x00; // sfnt version - tableDir[1] = 0x01; - tableDir[2] = 0x00; - tableDir[3] = 0x00; - tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables - tableDir[5] = (char)(nNewTables & 0xff); - for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ; - t = 1 << (4 + i); - tableDir[6] = (char)((t >> 8) & 0xff); // searchRange - tableDir[7] = (char)(t & 0xff); - tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector - tableDir[9] = (char)(i & 0xff); - t = nNewTables * 16 - t; - tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift - tableDir[11] = (char)(t & 0xff); - pos = 12; - for (i = 0; i < nNewTables; ++i) { - tableDir[pos ] = (char)(newTables[i].tag >> 24); - tableDir[pos+ 1] = (char)(newTables[i].tag >> 16); - tableDir[pos+ 2] = (char)(newTables[i].tag >> 8); - tableDir[pos+ 3] = (char) newTables[i].tag; - tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24); - tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16); - tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8); - tableDir[pos+ 7] = (char) newTables[i].checksum; - tableDir[pos+ 8] = (char)(newTables[i].offset >> 24); - tableDir[pos+ 9] = (char)(newTables[i].offset >> 16); - tableDir[pos+10] = (char)(newTables[i].offset >> 8); - tableDir[pos+11] = (char) newTables[i].offset; - tableDir[pos+12] = (char)(newTables[i].len >> 24); - tableDir[pos+13] = (char)(newTables[i].len >> 16); - tableDir[pos+14] = (char)(newTables[i].len >> 8); - tableDir[pos+15] = (char) newTables[i].len; - pos += 16; - } - (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16); - - // compute the file checksum - fileChecksum = computeTableChecksum((Guchar *)tableDir, - 12 + nNewTables * 16); - for (i = 0; i < nNewTables; ++i) { - fileChecksum += newTables[i].checksum; - } - fileChecksum = 0xb1b0afba - fileChecksum; - - // write the tables - for (i = 0; i < nNewTables; ++i) { - if (newTables[i].tag == headTag) { - if (checkRegion(newTables[i].origOffset, newTables[i].len)) { - (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8); - checksumBuf[0] = fileChecksum >> 24; - checksumBuf[1] = fileChecksum >> 16; - checksumBuf[2] = fileChecksum >> 8; - checksumBuf[3] = fileChecksum; - (*outputFunc)(outputStream, checksumBuf, 4); - (*outputFunc)(outputStream, - (char *)file + newTables[i].origOffset + 12, - newTables[i].len - 12); - } else { - for (j = 0; j < newTables[i].len; ++j) { - (*outputFunc)(outputStream, "\0", 1); - } - } - } else if (newTables[i].tag == cmapTag && codeToGID) { - (*outputFunc)(outputStream, newCmapTab, newTables[i].len); - } else if (newTables[i].tag == cmapTag && missingCmap) { - (*outputFunc)(outputStream, cmapTab, newTables[i].len); - } else if (newTables[i].tag == nameTag && name) { - (*outputFunc)(outputStream, newNameTab, newTables[i].len); - } else if (newTables[i].tag == nameTag && missingName) { - (*outputFunc)(outputStream, nameTab, newTables[i].len); - } else if (newTables[i].tag == postTag && missingPost) { - (*outputFunc)(outputStream, postTab, newTables[i].len); - } else if (newTables[i].tag == locaTag && unsortedLoca) { - for (j = 0; j <= nGlyphs; ++j) { - if (locaFmt) { - locaBuf[0] = (char)(locaTable[j].newOffset >> 24); - locaBuf[1] = (char)(locaTable[j].newOffset >> 16); - locaBuf[2] = (char)(locaTable[j].newOffset >> 8); - locaBuf[3] = (char) locaTable[j].newOffset; - (*outputFunc)(outputStream, locaBuf, 4); - } else { - locaBuf[0] = (char)(locaTable[j].newOffset >> 9); - locaBuf[1] = (char)(locaTable[j].newOffset >> 1); - (*outputFunc)(outputStream, locaBuf, 2); - } - } - } else if (newTables[i].tag == glyfTag && unsortedLoca) { - pos = tables[seekTable("glyf")].offset; - for (j = 0; j < nGlyphs; ++j) { - n = locaTable[j].len; - if (n > 0) { - k = locaTable[j].origOffset; - if (checkRegion(pos + k, n)) { - (*outputFunc)(outputStream, (char *)file + pos + k, n); - } else { - for (k = 0; k < n; ++k) { - (*outputFunc)(outputStream, "\0", 1); - } - } - if ((k = locaTable[j].len & 3)) { - (*outputFunc)(outputStream, "\0\0\0\0", 4 - k); - } - } - } - } else { - if (checkRegion(newTables[i].origOffset, newTables[i].len)) { - (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, - newTables[i].len); - } else { - for (j = 0; j < newTables[i].len; ++j) { - (*outputFunc)(outputStream, "\0", 1); - } - } - } - if (newTables[i].len & 3) { - (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3)); - } - } - - gfree(newCmapTab); - gfree(newNameTab); - gfree(tableDir); - gfree(newTables); - done1: - gfree(locaTable); -} - -void FoFiTrueType::cvtEncoding(const char **encoding, - FoFiOutputFunc outputFunc, - void *outputStream) { - const char *name; - char buf[64]; - int i; - - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - if (encoding) { - for (i = 0; i < 256; ++i) { - if (!(name = encoding[i])) { - name = ".notdef"; - } - sprintf(buf, "dup %d /", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, " put\n", 5); - } - } else { - for (i = 0; i < 256; ++i) { - sprintf(buf, "dup %d /c%02x put\n", i, i); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - (*outputFunc)(outputStream, "readonly def\n", 13); -} - -void FoFiTrueType::cvtCharStrings(const char **encoding, - Gushort *codeToGID, - FoFiOutputFunc outputFunc, - void *outputStream) { - const char *name; - char buf[64], buf2[16]; - int i, k; - - // always define '.notdef' - (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32); - (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); - - // if there's no 'cmap' table, punt - if (nCmaps == 0) { - goto err; - } - - // map char name to glyph index: - // 1. use encoding to map name to char code - // 2. use codeToGID to map char code to glyph index - // N.B. We do this in reverse order because font subsets can have - // weird encodings that use the same character name twice, and - // the first definition is probably the one we want. - k = 0; // make gcc happy - for (i = 255; i >= 0; --i) { - if (encoding) { - name = encoding[i]; - } else { - sprintf(buf2, "c%02x", i); - name = buf2; - } - if (name && strcmp(name, ".notdef")) { - k = codeToGID[i]; - // note: Distiller (maybe Adobe's PS interpreter in general) - // doesn't like TrueType fonts that have CharStrings entries - // which point to nonexistent glyphs, hence the (k < nGlyphs) - // test - if (k > 0 && k < nGlyphs) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, name, strlen(name)); - sprintf(buf, " %d def\n", k); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - } - - err: - (*outputFunc)(outputStream, "end readonly def\n", 17); -} - -void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, - void *outputStream, GString *name, - GBool needVerticalMetrics) { - Guchar headData[54]; - TrueTypeLoca *locaTable; - Guchar *locaData; - TrueTypeTable newTables[nT42Tables]; - Guchar tableDir[12 + nT42Tables*16]; - GBool ok; - Guint checksum; - int nNewTables; - int length, pos, glyfPos, i, j, k; - Guchar vheaTab[36] = { - 0, 1, 0, 0, // table version number - 0, 0, // ascent - 0, 0, // descent - 0, 0, // reserved - 0, 0, // max advance height - 0, 0, // min top side bearing - 0, 0, // min bottom side bearing - 0, 0, // y max extent - 0, 0, // caret slope rise - 0, 1, // caret slope run - 0, 0, // caret offset - 0, 0, // reserved - 0, 0, // reserved - 0, 0, // reserved - 0, 0, // reserved - 0, 0, // metric data format - 0, 1 // number of advance heights in vmtx table - }; - Guchar *vmtxTab; - GBool needVhea, needVmtx; - int advance; - - // construct the 'head' table, zero out the font checksum - i = seekTable("head"); - pos = tables[i].offset; - if (!checkRegion(pos, 54)) { - return; - } - memcpy(headData, file + pos, 54); - headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0; - - // read the original 'loca' table, pad entries out to 4 bytes, and - // sort it into proper order -- some (non-compliant) fonts have - // out-of-order loca tables; in order to correctly handle the case - // where (compliant) fonts have empty entries in the middle of the - // table, cmpTrueTypeLocaPos uses offset as its primary sort key, - // and idx as its secondary key (ensuring that adjacent entries with - // the same pos value remain in the same order) - locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); - i = seekTable("loca"); - pos = tables[i].offset; - ok = gTrue; - for (i = 0; i <= nGlyphs; ++i) { - locaTable[i].idx = i; - if (locaFmt) { - locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); - } else { - locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); - } - } - qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), - &cmpTrueTypeLocaOffset); - for (i = 0; i < nGlyphs; ++i) { - locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; - } - locaTable[nGlyphs].len = 0; - qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), - &cmpTrueTypeLocaIdx); - pos = 0; - for (i = 0; i <= nGlyphs; ++i) { - locaTable[i].newOffset = pos; - pos += locaTable[i].len; - if (pos & 3) { - pos += 4 - (pos & 3); - } - } - - // construct the new 'loca' table - locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2)); - for (i = 0; i <= nGlyphs; ++i) { - pos = locaTable[i].newOffset; - if (locaFmt) { - locaData[4*i ] = (Guchar)(pos >> 24); - locaData[4*i+1] = (Guchar)(pos >> 16); - locaData[4*i+2] = (Guchar)(pos >> 8); - locaData[4*i+3] = (Guchar) pos; - } else { - locaData[2*i ] = (Guchar)(pos >> 9); - locaData[2*i+1] = (Guchar)(pos >> 1); - } - } - - // count the number of tables - nNewTables = 0; - for (i = 0; i < nT42Tables; ++i) { - if (t42Tables[i].required || - seekTable(t42Tables[i].tag) >= 0) { - ++nNewTables; - } - } - vmtxTab = NULL; // make gcc happy - advance = 0; // make gcc happy - if (needVerticalMetrics) { - needVhea = seekTable("vhea") < 0; - needVmtx = seekTable("vmtx") < 0; - if (needVhea || needVmtx) { - i = seekTable("head"); - advance = getU16BE(tables[i].offset + 18, &ok); // units per em - if (needVhea) { - ++nNewTables; - } - if (needVmtx) { - ++nNewTables; - } - } - } - - // construct the new table headers, including table checksums - // (pad each table out to a multiple of 4 bytes) - pos = 12 + nNewTables*16; - k = 0; - for (i = 0; i < nT42Tables; ++i) { - length = -1; - checksum = 0; // make gcc happy - if (i == t42HeadTable) { - length = 54; - checksum = computeTableChecksum(headData, 54); - } else if (i == t42LocaTable) { - length = (nGlyphs + 1) * (locaFmt ? 4 : 2); - checksum = computeTableChecksum(locaData, length); - } else if (i == t42GlyfTable) { - length = 0; - checksum = 0; - glyfPos = tables[seekTable("glyf")].offset; - for (j = 0; j < nGlyphs; ++j) { - length += locaTable[j].len; - if (length & 3) { - length += 4 - (length & 3); - } - if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { - checksum += - computeTableChecksum(file + glyfPos + locaTable[j].origOffset, - locaTable[j].len); - } - } - } else { - if ((j = seekTable(t42Tables[i].tag)) >= 0) { - length = tables[j].len; - if (checkRegion(tables[j].offset, length)) { - checksum = computeTableChecksum(file + tables[j].offset, length); - } - } else if (needVerticalMetrics && i == t42VheaTable) { - vheaTab[10] = advance / 256; // max advance height - vheaTab[11] = advance % 256; - length = sizeof(vheaTab); - checksum = computeTableChecksum(vheaTab, length); - } else if (needVerticalMetrics && i == t42VmtxTable) { - length = 4 + (nGlyphs - 1) * 4; - vmtxTab = (Guchar *)gmalloc(length); - vmtxTab[0] = advance / 256; - vmtxTab[1] = advance % 256; - for (j = 2; j < length; j += 2) { - vmtxTab[j] = 0; - vmtxTab[j+1] = 0; - } - checksum = computeTableChecksum(vmtxTab, length); - } else if (t42Tables[i].required) { - //~ error(-1, "Embedded TrueType font is missing a required table ('%s')", - //~ t42Tables[i].tag); - length = 0; - checksum = 0; - } - } - if (length >= 0) { - newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) | - ((t42Tables[i].tag[1] & 0xff) << 16) | - ((t42Tables[i].tag[2] & 0xff) << 8) | - (t42Tables[i].tag[3] & 0xff); - newTables[k].checksum = checksum; - newTables[k].offset = pos; - newTables[k].len = length; - pos += length; - if (pos & 3) { - pos += 4 - (length & 3); - } - ++k; - } - } - - // construct the table directory - tableDir[0] = 0x00; // sfnt version - tableDir[1] = 0x01; - tableDir[2] = 0x00; - tableDir[3] = 0x00; - tableDir[4] = 0; // numTables - tableDir[5] = nNewTables; - tableDir[6] = 0; // searchRange - tableDir[7] = (Guchar)128; - tableDir[8] = 0; // entrySelector - tableDir[9] = 3; - tableDir[10] = 0; // rangeShift - tableDir[11] = (Guchar)(16 * nNewTables - 128); - pos = 12; - for (i = 0; i < nNewTables; ++i) { - tableDir[pos ] = (Guchar)(newTables[i].tag >> 24); - tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16); - tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8); - tableDir[pos+ 3] = (Guchar) newTables[i].tag; - tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24); - tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16); - tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8); - tableDir[pos+ 7] = (Guchar) newTables[i].checksum; - tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24); - tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16); - tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8); - tableDir[pos+11] = (Guchar) newTables[i].offset; - tableDir[pos+12] = (Guchar)(newTables[i].len >> 24); - tableDir[pos+13] = (Guchar)(newTables[i].len >> 16); - tableDir[pos+14] = (Guchar)(newTables[i].len >> 8); - tableDir[pos+15] = (Guchar) newTables[i].len; - pos += 16; - } - - // compute the font checksum and store it in the head table - checksum = computeTableChecksum(tableDir, 12 + nNewTables*16); - for (i = 0; i < nNewTables; ++i) { - checksum += newTables[i].checksum; - } - checksum = 0xb1b0afba - checksum; // because the TrueType spec says so - headData[ 8] = (Guchar)(checksum >> 24); - headData[ 9] = (Guchar)(checksum >> 16); - headData[10] = (Guchar)(checksum >> 8); - headData[11] = (Guchar) checksum; - - // start the sfnts array - if (name) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, name->getCString(), name->getLength()); - (*outputFunc)(outputStream, " [\n", 3); - } else { - (*outputFunc)(outputStream, "/sfnts [\n", 9); - } - - // write the table directory - dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream); - - // write the tables - for (i = 0; i < nNewTables; ++i) { - if (i == t42HeadTable) { - dumpString(headData, 54, outputFunc, outputStream); - } else if (i == t42LocaTable) { - length = (nGlyphs + 1) * (locaFmt ? 4 : 2); - dumpString(locaData, length, outputFunc, outputStream); - } else if (i == t42GlyfTable) { - glyfPos = tables[seekTable("glyf")].offset; - for (j = 0; j < nGlyphs; ++j) { - if (locaTable[j].len > 0 && - checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { - dumpString(file + glyfPos + locaTable[j].origOffset, - locaTable[j].len, outputFunc, outputStream); - } - } - } else { - // length == 0 means the table is missing and the error was - // already reported during the construction of the table - // headers - if ((length = newTables[i].len) > 0) { - if ((j = seekTable(t42Tables[i].tag)) >= 0 && - checkRegion(tables[j].offset, tables[j].len)) { - dumpString(file + tables[j].offset, tables[j].len, - outputFunc, outputStream); - } else if (needVerticalMetrics && i == t42VheaTable) { - dumpString(vheaTab, length, outputFunc, outputStream); - } else if (needVerticalMetrics && i == t42VmtxTable) { - dumpString(vmtxTab, length, outputFunc, outputStream); - gfree(vmtxTab); - } - } - } - } - - // end the sfnts array - (*outputFunc)(outputStream, "] def\n", 6); - - gfree(locaData); - gfree(locaTable); -} - -void FoFiTrueType::dumpString(Guchar *s, int length, - FoFiOutputFunc outputFunc, - void *outputStream) { - char buf[64]; - int pad, i, j; - - (*outputFunc)(outputStream, "<", 1); - for (i = 0; i < length; i += 32) { - for (j = 0; j < 32 && i+j < length; ++j) { - sprintf(buf, "%02X", s[i+j] & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (i % (65536 - 32) == 65536 - 64) { - (*outputFunc)(outputStream, ">\n<", 3); - } else if (i+32 < length) { - (*outputFunc)(outputStream, "\n", 1); - } - } - if (length & 3) { - pad = 4 - (length & 3); - for (i = 0; i < pad; ++i) { - (*outputFunc)(outputStream, "00", 2); - } - } - // add an extra zero byte because the Adobe Type 42 spec says so - (*outputFunc)(outputStream, "00>\n", 4); -} - -Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { - Guint checksum, word; - int i; - - checksum = 0; - for (i = 0; i+3 < length; i += 4) { - word = ((data[i ] & 0xff) << 24) + - ((data[i+1] & 0xff) << 16) + - ((data[i+2] & 0xff) << 8) + - (data[i+3] & 0xff); - checksum += word; - } - if (length & 3) { - word = 0; - i = length & ~3; - switch (length & 3) { - case 3: - word |= (data[i+2] & 0xff) << 8; - case 2: - word |= (data[i+1] & 0xff) << 16; - case 1: - word |= (data[i ] & 0xff) << 24; - break; - } - checksum += word; - } - return checksum; -} - -void FoFiTrueType::parse() { - Guint topTag; - int pos, i, j; - - parsedOk = true; - - // look for a collection (TTC) - topTag = getU32BE(0, &parsedOk); - if (! parsedOk) - return; - if (topTag == ttcfTag) { - int dircount; - - dircount = getU32BE(8, &parsedOk); - if (!parsedOk) - return; - if (! dircount) { - parsedOk = gFalse; - return; - } - - if (faceIndex >= dircount) - faceIndex = 0; - pos = getU32BE(12 + faceIndex * 4, &parsedOk); - if (! parsedOk) - return; - } else { - pos = 0; - } - - nTables = getU16BE(pos + 4, &parsedOk); - if (!parsedOk) { - return; - } - - tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable)); - pos += 12; - for (i = 0; i < nTables; ++i) { - tables[i].tag = getU32BE(pos, &parsedOk); - tables[i].checksum = getU32BE(pos + 4, &parsedOk); - tables[i].offset = (int)getU32BE(pos + 8, &parsedOk); - tables[i].len = (int)getU32BE(pos + 12, &parsedOk); - if (tables[i].offset + tables[i].len < tables[i].offset || - tables[i].offset + tables[i].len > len) { - parsedOk = gFalse; - } - pos += 16; - } - if (!parsedOk) { - return; - } - - // check for tables that are required by both the TrueType spec and - // the Type 42 spec - if (seekTable("head") < 0 || - seekTable("hhea") < 0 || - seekTable("loca") < 0 || - seekTable("maxp") < 0 || - seekTable("glyf") < 0 || - seekTable("hmtx") < 0) { - parsedOk = gFalse; - return; - } - - // read the cmaps - if ((i = seekTable("cmap")) >= 0) { - pos = tables[i].offset + 2; - nCmaps = getU16BE(pos, &parsedOk); - pos += 2; - if (!parsedOk) { - return; - } - cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap)); - for (j = 0; j < nCmaps; ++j) { - cmaps[j].platform = getU16BE(pos, &parsedOk); - cmaps[j].encoding = getU16BE(pos + 2, &parsedOk); - cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk); - pos += 8; - cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk); - cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk); - } - if (!parsedOk) { - return; - } - } else { - nCmaps = 0; - } - - // get the number of glyphs from the maxp table - i = seekTable("maxp"); - nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk); - if (!parsedOk) { - return; - } - - // get the bbox and loca table format from the head table - i = seekTable("head"); - bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk); - bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk); - bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk); - bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk); - locaFmt = getS16BE(tables[i].offset + 50, &parsedOk); - if (!parsedOk) { - return; - } - - // make sure the loca table is sane (correct length and entries are - // in bounds) - i = seekTable("loca"); - if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) { - parsedOk = gFalse; - return; - } - for (j = 0; j <= nGlyphs; ++j) { - if (locaFmt) { - pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk); - } else { - pos = getU16BE(tables[i].offset + j*2, &parsedOk); - } - if (pos < 0 || pos > len) { - parsedOk = gFalse; - } - } - if (!parsedOk) { - return; - } - - // read the post table - readPostTable(); -} - -void FoFiTrueType::readPostTable() { - GString *name; - int tablePos, postFmt, stringIdx, stringPos; - GBool ok; - int i, j, n, m; - - ok = gTrue; - if ((i = seekTable("post")) < 0) { - return; - } - tablePos = tables[i].offset; - postFmt = getU32BE(tablePos, &ok); - if (!ok) { - goto err; - } - if (postFmt == 0x00010000) { - nameToGID = new GHash(gTrue); - for (i = 0; i < 258; ++i) { - nameToGID->add(new GString(macGlyphNames[i]), i); - } - } else if (postFmt == 0x00020000) { - nameToGID = new GHash(gTrue); - n = getU16BE(tablePos + 32, &ok); - if (!ok) { - goto err; - } - if (n > nGlyphs) { - n = nGlyphs; - } - stringIdx = 0; - stringPos = tablePos + 34 + 2*n; - for (i = 0; i < n; ++i) { - j = getU16BE(tablePos + 34 + 2*i, &ok); - if (j < 258) { - nameToGID->removeInt(macGlyphNames[j]); - nameToGID->add(new GString(macGlyphNames[j]), i); - } else { - j -= 258; - if (j != stringIdx) { - for (stringIdx = 0, stringPos = tablePos + 34 + 2*n; - stringIdx < j; - ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ; - if (!ok) { - goto err; - } - } - m = getU8(stringPos, &ok); - if (!ok || !checkRegion(stringPos + 1, m)) { - goto err; - } - name = new GString((char *)&file[stringPos + 1], m); - nameToGID->removeInt(name); - nameToGID->add(name, i); - ++stringIdx; - stringPos += 1 + m; - } - } - } else if (postFmt == 0x00028000) { - nameToGID = new GHash(gTrue); - for (i = 0; i < nGlyphs; ++i) { - j = getU8(tablePos + 32 + i, &ok); - if (!ok) { - goto err; - } - if (j < 258) { - nameToGID->removeInt(macGlyphNames[j]); - nameToGID->add(new GString(macGlyphNames[j]), i); - } - } - } - - return; - -err: - if (nameToGID) { - delete nameToGID; - nameToGID = NULL; - } -} - -int FoFiTrueType::seekTable(const char *tag) { - Guint tagI; - int i; - - tagI = ((tag[0] & 0xff) << 24) | - ((tag[1] & 0xff) << 16) | - ((tag[2] & 0xff) << 8) | - (tag[3] & 0xff); - for (i = 0; i < nTables; ++i) { - if (tables[i].tag == tagI) { - return i; - } - } - return -1; -} diff --git a/xpdf/fofi/FoFiTrueType.h b/xpdf/fofi/FoFiTrueType.h deleted file mode 100644 index b1e0d979b..000000000 --- a/xpdf/fofi/FoFiTrueType.h +++ /dev/null @@ -1,141 +0,0 @@ -//======================================================================== -// -// FoFiTrueType.h -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef FOFITRUETYPE_H -#define FOFITRUETYPE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "FoFiBase.h" - -class GString; -class GHash; -struct TrueTypeTable; -struct TrueTypeCmap; - -//------------------------------------------------------------------------ -// FoFiTrueType -//------------------------------------------------------------------------ - -class FoFiTrueType: public FoFiBase { -public: - - // Create a FoFiTrueType object from a memory buffer. - static FoFiTrueType *make(char *fileA, int lenA, int faceIndexA=0); - - // Create a FoFiTrueType object from a file on disk. - static FoFiTrueType *load(char *fileName, int faceIndexA=0); - - FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA=0); - virtual ~FoFiTrueType(); - - // Return the number of cmaps defined by this font. - int getNumCmaps(); - - // Return the platform ID of the th cmap. - int getCmapPlatform(int i); - - // Return the encoding ID of the th cmap. - int getCmapEncoding(int i); - - // Return the index of the cmap for , . Returns - // -1 if there is no corresponding cmap. - int findCmap(int platform, int encoding); - - // Return the GID corresponding to according to the th cmap. - Gushort mapCodeToGID(int i, int c); - - // Returns the GID corresponding to according to the post - // table. Returns 0 if there is no mapping for or if the - // font does not have a post table. - int mapNameToGID(const char *name); - - // Returns the least restrictive embedding licensing right (as - // defined by the TrueType spec): - // * 4: OS/2 table is missing or invalid - // * 3: installable embedding - // * 2: editable embedding - // * 1: preview & print embedding - // * 0: restricted license embedding - int getEmbeddingRights(); - - // Convert to a Type 42 font, suitable for embedding in a PostScript - // file. will be used as the PostScript font name (so we - // don't need to depend on the 'name' table in the font). The - // array specifies the mapping from char codes to names. - // If is NULL, the encoding is unknown or undefined. The - // array specifies the mapping from char codes to GIDs. - void convertToType42(char *psName, const char **encoding, - Gushort *codeToGID, - FoFiOutputFunc outputFunc, void *outputStream); - - // Convert to a Type 2 CIDFont, suitable for embedding in a - // PostScript file. will be used as the PostScript font - // name (so we don't need to depend on the 'name' table in the - // font). The array maps CIDs to GIDs; it has - // entries. - void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs, - GBool needVerticalMetrics, - FoFiOutputFunc outputFunc, void *outputStream); - - // Convert to a Type 0 (but non-CID) composite font, suitable for - // embedding in a PostScript file. will be used as the - // PostScript font name (so we don't need to depend on the 'name' - // table in the font). The array maps CIDs to GIDs; it has - // entries. - void convertToType0(char *psName, Gushort *cidMap, int nCIDs, - GBool needVerticalMetrics, - FoFiOutputFunc outputFunc, void *outputStream); - - // Write a clean TTF file, filling in missing tables and correcting - // various other errors. If is non-NULL, the font is renamed - // to . If is non-NULL, the font is re-encoded, - // using a Windows Unicode cmap. If is NULL and the font is - // complete and correct, it will be written unmodified. - void writeTTF(FoFiOutputFunc outputFunc, void *outputStream, - char *name = NULL, Gushort *codeToGID = NULL); - -private: - - void cvtEncoding(const char **encoding, - FoFiOutputFunc outputFunc, - void *outputStream); - void cvtCharStrings(const char **encoding, - Gushort *codeToGID, - FoFiOutputFunc outputFunc, - void *outputStream); - void cvtSfnts(FoFiOutputFunc outputFunc, - void *outputStream, GString *name, - GBool needVerticalMetrics); - void dumpString(Guchar *s, int length, - FoFiOutputFunc outputFunc, - void *outputStream); - Guint computeTableChecksum(Guchar *data, int length); - void parse(); - void readPostTable(); - int seekTable(const char *tag); - - TrueTypeTable *tables; - int nTables; - TrueTypeCmap *cmaps; - int nCmaps; - int nGlyphs; - int locaFmt; - int bbox[4]; - GHash *nameToGID; - - GBool parsedOk; - int faceIndex; -}; - -#endif diff --git a/xpdf/fofi/FoFiType1.cc b/xpdf/fofi/FoFiType1.cc deleted file mode 100644 index a1ef85e55..000000000 --- a/xpdf/fofi/FoFiType1.cc +++ /dev/null @@ -1,208 +0,0 @@ -//======================================================================== -// -// FoFiType1.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "FoFiEncodings.h" -#include "FoFiType1.h" - -//------------------------------------------------------------------------ -// FoFiType1 -//------------------------------------------------------------------------ - -FoFiType1 *FoFiType1::make(char *fileA, int lenA) { - return new FoFiType1(fileA, lenA, gFalse); -} - -FoFiType1 *FoFiType1::load(char *fileName) { - char *fileA; - int lenA; - - if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { - return NULL; - } - return new FoFiType1(fileA, lenA, gTrue); -} - -FoFiType1::FoFiType1(char *fileA, int lenA, GBool freeFileDataA): - FoFiBase(fileA, lenA, freeFileDataA) -{ - name = NULL; - encoding = NULL; - parsed = gFalse; -} - -FoFiType1::~FoFiType1() { - int i; - - if (name) { - gfree((void*)name); - } - if (encoding && encoding != fofiType1StandardEncoding) { - for (i = 0; i < 256; ++i) { - gfree((void*)encoding[i]); - } - gfree(encoding); - } -} - -const char *FoFiType1::getName() { - if (!parsed) { - parse(); - } - return name; -} - -const char **FoFiType1::getEncoding() { - if (!parsed) { - parse(); - } - return encoding; -} - -void FoFiType1::writeEncoded(char **newEncoding, - FoFiOutputFunc outputFunc, void *outputStream) { - char buf[512]; - char *line; - int i; - - // copy everything up to the encoding - for (line = (char *)file; - line && strncmp(line, "/Encoding", 9); - line = getNextLine(line)) ; - if (!line) { - // no encoding - just copy the whole font file - (*outputFunc)(outputStream, (char *)file, len); - return; - } - (*outputFunc)(outputStream, (char *)file, line - (char *)file); - - // write the new encoding - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - (*outputFunc)(outputStream, - "0 1 255 {1 index exch /.notdef put} for\n", 40); - for (i = 0; i < 256; ++i) { - if (newEncoding[i]) { - sprintf(buf, "dup %d /%s put\n", i, newEncoding[i]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - (*outputFunc)(outputStream, "readonly def\n", 13); - - // copy everything after the encoding - if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { - line = getNextLine(line); - } else { - for (line = getNextLine(line); - line && strncmp(line, "readonly def", 12); - line = getNextLine(line)) ; - if (line) { - line = getNextLine(line); - } - } - if (line) { - (*outputFunc)(outputStream, line, ((char *)file + len) - line); - } -} - -char *FoFiType1::getNextLine(char *line) { - while (line < (char *)file + len && *line != '\x0a' && *line != '\x0d') { - ++line; - } - if (line < (char *)file + len && *line == '\x0d') { - ++line; - } - if (line < (char *)file + len && *line == '\x0a') { - ++line; - } - if (line >= (char *)file + len) { - return NULL; - } - return line; -} - -void FoFiType1::parse() { - char *line, *line1, *p, *p2; - char buf[256]; - char c; - int n, code, i, j; - - for (i = 1, line = (char *)file; - i <= 100 && line && (!name || !encoding); - ++i) { - - // get font name - if (!name && !strncmp(line, "/FontName", 9)) { - strncpy(buf, line, 255); - buf[255] = '\0'; - if ((p = strchr(buf+9, '/')) && - (p = strtok(p+1, " \t\n\r"))) { - name = copyString(p); - } - line = getNextLine(line); - - // get encoding - } else if (!encoding && - !strncmp(line, "/Encoding StandardEncoding def", 30)) { - encoding = fofiType1StandardEncoding; - } else if (!encoding && - !strncmp(line, "/Encoding 256 array", 19)) { - encoding = (const char **)gmallocn(256, sizeof(char *)); - for (j = 0; j < 256; ++j) { - encoding[j] = NULL; - } - for (j = 0, line = getNextLine(line); - j < 300 && line && (line1 = getNextLine(line)); - ++j, line = line1) { - line1 = getNextLine(line); - if ((n = line1 - line) > 255) { - n = 255; - } - strncpy(buf, line, n); - buf[n] = '\0'; - for (p = buf; *p == ' ' || *p == '\t'; ++p) ; - if (!strncmp(p, "dup", 3)) { - for (p += 3; *p == ' ' || *p == '\t'; ++p) ; - for (p2 = p; *p2 >= '0' && *p2 <= '9'; ++p2) ; - if (*p2) { - c = *p2; - *p2 = '\0'; - if ((code = atoi(p)) < 256) { - *p2 = c; - for (p = p2; *p == ' ' || *p == '\t'; ++p) ; - if (*p == '/') { - ++p; - for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; - *p2 = '\0'; - encoding[code] = copyString(p); - } - } - } - } else { - if (strtok(buf, " \t") && - (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { - break; - } - } - } - //~ check for getinterval/putinterval junk - - } else { - line = getNextLine(line); - } - } - - parsed = gTrue; -} diff --git a/xpdf/fofi/FoFiType1.h b/xpdf/fofi/FoFiType1.h deleted file mode 100644 index 80cccf78f..000000000 --- a/xpdf/fofi/FoFiType1.h +++ /dev/null @@ -1,59 +0,0 @@ -//======================================================================== -// -// FoFiType1.h -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef FOFITYPE1_H -#define FOFITYPE1_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "FoFiBase.h" - -//------------------------------------------------------------------------ -// FoFiType1 -//------------------------------------------------------------------------ - -class FoFiType1: public FoFiBase { -public: - - // Create a FoFiType1 object from a memory buffer. - static FoFiType1 *make(char *fileA, int lenA); - - // Create a FoFiType1 object from a file on disk. - static FoFiType1 *load(char *fileName); - - virtual ~FoFiType1(); - - // Return the font name. - const char *getName(); - - // Return the encoding, as an array of 256 names (any of which may - // be NULL). - const char **getEncoding(); - - // Write a version of the Type 1 font file with a new encoding. - void writeEncoded(char **newEncoding, - FoFiOutputFunc outputFunc, void *outputStream); - -private: - - FoFiType1(char *fileA, int lenA, GBool freeFileDataA); - - char *getNextLine(char *line); - void parse(); - - const char *name; - const char **encoding; - GBool parsed; -}; - -#endif diff --git a/xpdf/fofi/FoFiType1C.cc b/xpdf/fofi/FoFiType1C.cc deleted file mode 100644 index 67b36a208..000000000 --- a/xpdf/fofi/FoFiType1C.cc +++ /dev/null @@ -1,2481 +0,0 @@ -//======================================================================== -// -// FoFiType1C.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include "gmem.h" -#include "GString.h" -#include "FoFiEncodings.h" -#include "FoFiType1C.h" - -//------------------------------------------------------------------------ - -static char hexChars[17] = "0123456789ABCDEF"; - -//------------------------------------------------------------------------ -// FoFiType1C -//------------------------------------------------------------------------ - -FoFiType1C *FoFiType1C::make(char *fileA, int lenA) { - FoFiType1C *ff; - - ff = new FoFiType1C(fileA, lenA, gFalse); - if (!ff->parse()) { - delete ff; - return NULL; - } - return ff; -} - -FoFiType1C *FoFiType1C::load(char *fileName) { - FoFiType1C *ff; - char *fileA; - int lenA; - - if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { - return NULL; - } - ff = new FoFiType1C(fileA, lenA, gTrue); - if (!ff->parse()) { - delete ff; - return NULL; - } - return ff; -} - -FoFiType1C::FoFiType1C(char *fileA, int lenA, GBool freeFileDataA): - FoFiBase(fileA, lenA, freeFileDataA) -{ - name = NULL; - encoding = NULL; - privateDicts = NULL; - fdSelect = NULL; - charset = NULL; -} - -FoFiType1C::~FoFiType1C() { - int i; - - if (name) { - delete name; - } - if (encoding && - encoding != fofiType1StandardEncoding && - encoding != fofiType1ExpertEncoding) { - for (i = 0; i < 256; ++i) { - gfree((void*)encoding[i]); - } - gfree(encoding); - } - if (privateDicts) { - gfree(privateDicts); - } - if (fdSelect) { - gfree(fdSelect); - } - if (charset && - charset != fofiType1CISOAdobeCharset && - charset != fofiType1CExpertCharset && - charset != fofiType1CExpertSubsetCharset) { - gfree(charset); - } -} - -char *FoFiType1C::getName() { - return name ? name->getCString() : (char *)NULL; -} - -const char **FoFiType1C::getEncoding() { - return encoding; -} - -Gushort *FoFiType1C::getCIDToGIDMap(int *nCIDs) { - Gushort *map; - int n, i; - - // a CID font's top dict has ROS as the first operator - if (topDict.firstOp != 0x0c1e) { - *nCIDs = 0; - return NULL; - } - - // in a CID font, the charset data is the GID-to-CID mapping, so all - // we have to do is reverse it - n = 0; - for (i = 0; i < nGlyphs; ++i) { - if (charset[i] > n) { - n = charset[i]; - } - } - ++n; - map = (Gushort *)gmallocn(n, sizeof(Gushort)); - memset(map, 0, n * sizeof(Gushort)); - for (i = 0; i < nGlyphs; ++i) { - map[charset[i]] = i; - } - *nCIDs = n; - return map; -} - -void FoFiType1C::convertToType1(const char **newEncoding, GBool ascii, - FoFiOutputFunc outputFunc, - void *outputStream) { - Type1CEexecBuf eb; - Type1CIndex subrIdx; - Type1CIndexVal val; - char buf[512]; - const char **enc; - GBool ok; - int i; - - // write header and font dictionary, up to encoding - ok = gTrue; - (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); - (*outputFunc)(outputStream, name->getCString(), name->getLength()); - if (topDict.versionSID != 0) { - getString(topDict.versionSID, buf, &ok); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "\n", 1); - // the dictionary needs room for 12 entries: the following 9, plus - // Private and CharStrings (in the eexec section) and FID (which is - // added by definefont) - (*outputFunc)(outputStream, "12 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28); - if (topDict.versionSID != 0) { - (*outputFunc)(outputStream, "/version (", 10); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.noticeSID != 0) { - getString(topDict.noticeSID, buf, &ok); - (*outputFunc)(outputStream, "/Notice (", 9); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.copyrightSID != 0) { - getString(topDict.copyrightSID, buf, &ok); - (*outputFunc)(outputStream, "/Copyright (", 12); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.fullNameSID != 0) { - getString(topDict.fullNameSID, buf, &ok); - (*outputFunc)(outputStream, "/FullName (", 11); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.familyNameSID != 0) { - getString(topDict.familyNameSID, buf, &ok); - (*outputFunc)(outputStream, "/FamilyName (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.weightSID != 0) { - getString(topDict.weightSID, buf, &ok); - (*outputFunc)(outputStream, "/Weight (", 9); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.isFixedPitch) { - (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23); - } else { - (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24); - } - sprintf(buf, "/ItalicAngle %g def\n", topDict.italicAngle); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/UnderlinePosition %g def\n", topDict.underlinePosition); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/UnderlineThickness %g def\n", topDict.underlineThickness); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "end readonly def\n", 17); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, name->getCString(), name->getLength()); - (*outputFunc)(outputStream, " def\n", 5); - sprintf(buf, "/PaintType %d def\n", topDict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] readonly def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], - topDict.fontMatrix[3], topDict.fontMatrix[4], topDict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/FontBBox [%g %g %g %g] readonly def\n", - topDict.fontBBox[0], topDict.fontBBox[1], - topDict.fontBBox[2], topDict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (topDict.uniqueID != 0) { - sprintf(buf, "/UniqueID %d def\n", topDict.uniqueID); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - - // write the encoding - (*outputFunc)(outputStream, "/Encoding ", 10); - if (!newEncoding && encoding == fofiType1StandardEncoding) { - (*outputFunc)(outputStream, "StandardEncoding def\n", 21); - } else { - (*outputFunc)(outputStream, "256 array\n", 10); - (*outputFunc)(outputStream, - "0 1 255 {1 index exch /.notdef put} for\n", 40); - enc = newEncoding ? newEncoding : encoding; - for (i = 0; i < 256; ++i) { - if (enc[i]) { - sprintf(buf, "dup %d /%s put\n", i, enc[i]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - (*outputFunc)(outputStream, "readonly def\n", 13); - } - (*outputFunc)(outputStream, "currentdict end\n", 16); - - // start the binary section - (*outputFunc)(outputStream, "currentfile eexec\n", 18); - eb.outputFunc = outputFunc; - eb.outputStream = outputStream; - eb.ascii = ascii; - eb.r1 = 55665; - eb.line = 0; - - // write the private dictionary - eexecWrite(&eb, "\x83\xca\x73\xd5"); - eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); - eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" - " executeonly def\n"); - eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); - eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); - eexecWrite(&eb, "/MinFeature {16 16} def\n"); - eexecWrite(&eb, "/password 5839 def\n"); - if (privateDicts[0].nBlueValues) { - eexecWrite(&eb, "/BlueValues ["); - for (i = 0; i < privateDicts[0].nBlueValues; ++i) { - sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].blueValues[i]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].nOtherBlues) { - eexecWrite(&eb, "/OtherBlues ["); - for (i = 0; i < privateDicts[0].nOtherBlues; ++i) { - sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].otherBlues[i]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].nFamilyBlues) { - eexecWrite(&eb, "/FamilyBlues ["); - for (i = 0; i < privateDicts[0].nFamilyBlues; ++i) { - sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].familyBlues[i]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].nFamilyOtherBlues) { - eexecWrite(&eb, "/FamilyOtherBlues ["); - for (i = 0; i < privateDicts[0].nFamilyOtherBlues; ++i) { - sprintf(buf, "%s%d", i > 0 ? " " : "", - privateDicts[0].familyOtherBlues[i]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].blueScale != 0.039625) { - sprintf(buf, "/BlueScale %g def\n", privateDicts[0].blueScale); - eexecWrite(&eb, buf); - } - if (privateDicts[0].blueShift != 7) { - sprintf(buf, "/BlueShift %d def\n", privateDicts[0].blueShift); - eexecWrite(&eb, buf); - } - if (privateDicts[0].blueFuzz != 1) { - sprintf(buf, "/BlueFuzz %d def\n", privateDicts[0].blueFuzz); - eexecWrite(&eb, buf); - } - if (privateDicts[0].hasStdHW) { - sprintf(buf, "/StdHW [%g] def\n", privateDicts[0].stdHW); - eexecWrite(&eb, buf); - } - if (privateDicts[0].hasStdVW) { - sprintf(buf, "/StdVW [%g] def\n", privateDicts[0].stdVW); - eexecWrite(&eb, buf); - } - if (privateDicts[0].nStemSnapH) { - eexecWrite(&eb, "/StemSnapH ["); - for (i = 0; i < privateDicts[0].nStemSnapH; ++i) { - sprintf(buf, "%s%g", i > 0 ? " " : "", privateDicts[0].stemSnapH[i]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].nStemSnapV) { - eexecWrite(&eb, "/StemSnapV ["); - for (i = 0; i < privateDicts[0].nStemSnapV; ++i) { - sprintf(buf, "%s%g", i > 0 ? " " : "", privateDicts[0].stemSnapV[i]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].hasForceBold) { - sprintf(buf, "/ForceBold %s def\n", - privateDicts[0].forceBold ? "true" : "false"); - eexecWrite(&eb, buf); - } - if (privateDicts[0].forceBoldThreshold != 0) { - sprintf(buf, "/ForceBoldThreshold %g def\n", - privateDicts[0].forceBoldThreshold); - eexecWrite(&eb, buf); - } - if (privateDicts[0].languageGroup != 0) { - sprintf(buf, "/LanguageGroup %d def\n", privateDicts[0].languageGroup); - eexecWrite(&eb, buf); - } - if (privateDicts[0].expansionFactor != 0.06) { - sprintf(buf, "/ExpansionFactor %g def\n", privateDicts[0].expansionFactor); - eexecWrite(&eb, buf); - } - - // set up subroutines - ok = gTrue; - getIndex(privateDicts[0].subrsOffset, &subrIdx, &ok); - if (!ok) { - subrIdx.pos = -1; - } - - // write the CharStrings - sprintf(buf, "2 index /CharStrings %d dict dup begin\n", nGlyphs); - eexecWrite(&eb, buf); - for (i = 0; i < nGlyphs; ++i) { - ok = gTrue; - getIndexVal(&charStringsIdx, i, &val, &ok); - if (ok) { - getString(charset[i], buf, &ok); - if (ok) { - eexecCvtGlyph(&eb, buf, val.pos, val.len, &subrIdx, &privateDicts[0]); - } - } - } - eexecWrite(&eb, "end\n"); - eexecWrite(&eb, "end\n"); - eexecWrite(&eb, "readonly put\n"); - eexecWrite(&eb, "noaccess put\n"); - eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); - eexecWrite(&eb, "mark currentfile closefile\n"); - - // trailer - if (ascii && eb.line > 0) { - (*outputFunc)(outputStream, "\n", 1); - } - for (i = 0; i < 8; ++i) { - (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); - } - (*outputFunc)(outputStream, "cleartomark\n", 12); -} - -void FoFiType1C::convertToCIDType0(char *psName, - FoFiOutputFunc outputFunc, - void *outputStream) { - int *cidMap; - GString *charStrings; - int *charStringOffsets; - Type1CIndex subrIdx; - Type1CIndexVal val; - int nCIDs, gdBytes; - char buf[512], buf2[512]; - GBool ok; - int gid, offset, n, i, j, k; - - // compute the CID count and build the CID-to-GID mapping - nCIDs = 0; - for (i = 0; i < nGlyphs; ++i) { - if (charset[i] >= nCIDs) { - nCIDs = charset[i] + 1; - } - } - cidMap = (int *)gmallocn(nCIDs, sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - cidMap[i] = -1; - } - for (i = 0; i < nGlyphs; ++i) { - cidMap[charset[i]] = i; - } - - // build the charstrings - charStrings = new GString(); - charStringOffsets = (int *)gmallocn(nCIDs + 1, sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - charStringOffsets[i] = charStrings->getLength(); - if ((gid = cidMap[i]) >= 0) { - ok = gTrue; - getIndexVal(&charStringsIdx, gid, &val, &ok); - if (ok) { - getIndex(privateDicts[fdSelect[gid]].subrsOffset, &subrIdx, &ok); - if (!ok) { - subrIdx.pos = -1; - } - cvtGlyph(val.pos, val.len, charStrings, - &subrIdx, &privateDicts[fdSelect[gid]], gTrue); - } - } - } - charStringOffsets[nCIDs] = charStrings->getLength(); - - // compute gdBytes = number of bytes needed for charstring offsets - // (offset size needs to account for the charstring offset table, - // with a worst case of five bytes per entry, plus the charstrings - // themselves) - i = (nCIDs + 1) * 5 + charStrings->getLength(); - if (i < 0x100) { - gdBytes = 1; - } else if (i < 0x10000) { - gdBytes = 2; - } else if (i < 0x1000000) { - gdBytes = 3; - } else { - gdBytes = 4; - } - - // begin the font dictionary - (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37); - (*outputFunc)(outputStream, "20 dict begin\n", 14); - (*outputFunc)(outputStream, "/CIDFontName /", 14); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19); - (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); - if (topDict.registrySID > 0 && topDict.orderingSID > 0) { - ok = gTrue; - getString(topDict.registrySID, buf, &ok); - if (ok) { - (*outputFunc)(outputStream, " /Registry (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") def\n", 6); - } - ok = gTrue; - getString(topDict.orderingSID, buf, &ok); - if (ok) { - (*outputFunc)(outputStream, " /Ordering (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") def\n", 6); - } - } else { - (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); - (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); - } - sprintf(buf, " /Supplement %d def\n", topDict.supplement); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "end def\n", 8); - if (topDict.hasFontMatrix) { - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], - topDict.fontMatrix[2], topDict.fontMatrix[3], - topDict.fontMatrix[4], topDict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } else if (privateDicts[0].hasFontMatrix) { - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - } else { - (*outputFunc)(outputStream, - "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); - } - sprintf(buf, "/FontBBox [%g %g %g %g] def\n", - topDict.fontBBox[0], topDict.fontBBox[1], - topDict.fontBBox[2], topDict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27); - (*outputFunc)(outputStream, " /FSType 8 def\n", 16); - (*outputFunc)(outputStream, "end def\n", 8); - - // CIDFont-specific entries - sprintf(buf, "/CIDCount %d def\n", nCIDs); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); - sprintf(buf, "/GDBytes %d def\n", gdBytes); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20); - if (topDict.paintType != 0) { - sprintf(buf, "/PaintType %d def\n", topDict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - - // FDArray entry - sprintf(buf, "/FDArray %d array\n", nFDs); - (*outputFunc)(outputStream, buf, strlen(buf)); - for (i = 0; i < nFDs; ++i) { - sprintf(buf, "dup %d 10 dict begin\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - if (privateDicts[i].hasFontMatrix) { - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - privateDicts[i].fontMatrix[0], - privateDicts[i].fontMatrix[1], - privateDicts[i].fontMatrix[2], - privateDicts[i].fontMatrix[3], - privateDicts[i].fontMatrix[4], - privateDicts[i].fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } else { - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - } - sprintf(buf, "/PaintType %d def\n", topDict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); - if (privateDicts[i].nBlueValues) { - (*outputFunc)(outputStream, "/BlueValues [", 13); - for (j = 0; j < privateDicts[i].nBlueValues; ++j) { - sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].blueValues[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].nOtherBlues) { - (*outputFunc)(outputStream, "/OtherBlues [", 13); - for (j = 0; j < privateDicts[i].nOtherBlues; ++j) { - sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].otherBlues[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].nFamilyBlues) { - (*outputFunc)(outputStream, "/FamilyBlues [", 14); - for (j = 0; j < privateDicts[i].nFamilyBlues; ++j) { - sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].familyBlues[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].nFamilyOtherBlues) { - (*outputFunc)(outputStream, "/FamilyOtherBlues [", 19); - for (j = 0; j < privateDicts[i].nFamilyOtherBlues; ++j) { - sprintf(buf, "%s%d", j > 0 ? " " : "", - privateDicts[i].familyOtherBlues[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].blueScale != 0.039625) { - sprintf(buf, "/BlueScale %g def\n", privateDicts[i].blueScale); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (privateDicts[i].blueShift != 7) { - sprintf(buf, "/BlueShift %d def\n", privateDicts[i].blueShift); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (privateDicts[i].blueFuzz != 1) { - sprintf(buf, "/BlueFuzz %d def\n", privateDicts[i].blueFuzz); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (privateDicts[i].hasStdHW) { - sprintf(buf, "/StdHW [%g] def\n", privateDicts[i].stdHW); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (privateDicts[i].hasStdVW) { - sprintf(buf, "/StdVW [%g] def\n", privateDicts[i].stdVW); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (privateDicts[i].nStemSnapH) { - (*outputFunc)(outputStream, "/StemSnapH [", 12); - for (j = 0; j < privateDicts[i].nStemSnapH; ++j) { - sprintf(buf, "%s%g", j > 0 ? " " : "", privateDicts[i].stemSnapH[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].nStemSnapV) { - (*outputFunc)(outputStream, "/StemSnapV [", 12); - for (j = 0; j < privateDicts[i].nStemSnapV; ++j) { - sprintf(buf, "%s%g", j > 0 ? " " : "", privateDicts[i].stemSnapV[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].hasForceBold) { - sprintf(buf, "/ForceBold %s def\n", - privateDicts[i].forceBold ? "true" : "false"); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (privateDicts[i].forceBoldThreshold != 0) { - sprintf(buf, "/ForceBoldThreshold %g def\n", - privateDicts[i].forceBoldThreshold); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (privateDicts[i].languageGroup != 0) { - sprintf(buf, "/LanguageGroup %d def\n", privateDicts[i].languageGroup); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (privateDicts[i].expansionFactor != 0.06) { - sprintf(buf, "/ExpansionFactor %g def\n", - privateDicts[i].expansionFactor); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "currentdict end def\n", 20); - (*outputFunc)(outputStream, "currentdict end put\n", 20); - } - (*outputFunc)(outputStream, "def\n", 4); - - // start the binary section - offset = (nCIDs + 1) * (1 + gdBytes); - sprintf(buf, "(Hex) %d StartData\n", - offset + charStrings->getLength()); - (*outputFunc)(outputStream, buf, strlen(buf)); - - // write the charstring offset (CIDMap) table - for (i = 0; i <= nCIDs; i += 6) { - for (j = 0; j < 6 && i+j <= nCIDs; ++j) { - if (i+j < nCIDs && cidMap[i+j] >= 0) { - buf[0] = (char)fdSelect[cidMap[i+j]]; - } else { - buf[0] = (char)0; - } - n = offset + charStringOffsets[i+j]; - for (k = gdBytes; k >= 1; --k) { - buf[k] = (char)(n & 0xff); - n >>= 8; - } - for (k = 0; k <= gdBytes; ++k) { - sprintf(buf2, "%02x", buf[k] & 0xff); - (*outputFunc)(outputStream, buf2, 2); - } - } - (*outputFunc)(outputStream, "\n", 1); - } - - // write the charstring data - n = charStrings->getLength(); - for (i = 0; i < n; i += 32) { - for (j = 0; j < 32 && i+j < n; ++j) { - sprintf(buf, "%02x", charStrings->getChar(i+j) & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (i + 32 >= n) { - (*outputFunc)(outputStream, ">", 1); - } - (*outputFunc)(outputStream, "\n", 1); - } - - gfree(charStringOffsets); - delete charStrings; - gfree(cidMap); -} - -void FoFiType1C::convertToType0(char *psName, - FoFiOutputFunc outputFunc, - void *outputStream) { - int *cidMap; - Type1CIndex subrIdx; - Type1CIndexVal val; - int nCIDs; - char buf[512]; - Type1CEexecBuf eb; - GBool ok; - int fd, i, j, k; - - // compute the CID count and build the CID-to-GID mapping - nCIDs = 0; - for (i = 0; i < nGlyphs; ++i) { - if (charset[i] >= nCIDs) { - nCIDs = charset[i] + 1; - } - } - cidMap = (int *)gmallocn(nCIDs, sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - cidMap[i] = -1; - } - for (i = 0; i < nGlyphs; ++i) { - cidMap[charset[i]] = i; - } - - // write the descendant Type 1 fonts - for (i = 0; i < nCIDs; i += 256) { - - //~ this assumes that all CIDs in this block have the same FD -- - //~ to handle multiple FDs correctly, need to somehow divide the - //~ font up by FD - fd = 0; - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - if (cidMap[i+j] >= 0) { - fd = fdSelect[cidMap[i+j]]; - break; - } - } - - // font dictionary (unencrypted section) - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - sprintf(buf, "_%02x def\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - if (privateDicts[fd].hasFontMatrix) { - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - privateDicts[fd].fontMatrix[0], - privateDicts[fd].fontMatrix[1], - privateDicts[fd].fontMatrix[2], - privateDicts[fd].fontMatrix[3], - privateDicts[fd].fontMatrix[4], - privateDicts[fd].fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } else if (topDict.hasFontMatrix) { - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - } else { - (*outputFunc)(outputStream, - "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); - } - sprintf(buf, "/FontBBox [%g %g %g %g] def\n", - topDict.fontBBox[0], topDict.fontBBox[1], - topDict.fontBBox[2], topDict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/PaintType %d def\n", topDict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (topDict.paintType != 0) { - sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - sprintf(buf, "dup %d /c%02x put\n", j, j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (j < 256) { - sprintf(buf, "%d 1 255 { 1 index exch /.notdef put } for\n", j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "readonly def\n", 13); - (*outputFunc)(outputStream, "currentdict end\n", 16); - - // start the binary section - (*outputFunc)(outputStream, "currentfile eexec\n", 18); - eb.outputFunc = outputFunc; - eb.outputStream = outputStream; - eb.ascii = gTrue; - eb.r1 = 55665; - eb.line = 0; - - // start the private dictionary - eexecWrite(&eb, "\x83\xca\x73\xd5"); - eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); - eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" - " executeonly def\n"); - eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); - eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); - eexecWrite(&eb, "/MinFeature {16 16} def\n"); - eexecWrite(&eb, "/password 5839 def\n"); - if (privateDicts[fd].nBlueValues) { - eexecWrite(&eb, "/BlueValues ["); - for (k = 0; k < privateDicts[fd].nBlueValues; ++k) { - sprintf(buf, "%s%d", k > 0 ? " " : "", privateDicts[fd].blueValues[k]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].nOtherBlues) { - eexecWrite(&eb, "/OtherBlues ["); - for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) { - sprintf(buf, "%s%d", k > 0 ? " " : "", privateDicts[fd].otherBlues[k]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].nFamilyBlues) { - eexecWrite(&eb, "/FamilyBlues ["); - for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) { - sprintf(buf, "%s%d", k > 0 ? " " : "", - privateDicts[fd].familyBlues[k]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].nFamilyOtherBlues) { - eexecWrite(&eb, "/FamilyOtherBlues ["); - for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) { - sprintf(buf, "%s%d", k > 0 ? " " : "", - privateDicts[fd].familyOtherBlues[k]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].blueScale != 0.039625) { - sprintf(buf, "/BlueScale %g def\n", privateDicts[fd].blueScale); - eexecWrite(&eb, buf); - } - if (privateDicts[fd].blueShift != 7) { - sprintf(buf, "/BlueShift %d def\n", privateDicts[fd].blueShift); - eexecWrite(&eb, buf); - } - if (privateDicts[fd].blueFuzz != 1) { - sprintf(buf, "/BlueFuzz %d def\n", privateDicts[fd].blueFuzz); - eexecWrite(&eb, buf); - } - if (privateDicts[fd].hasStdHW) { - sprintf(buf, "/StdHW [%g] def\n", privateDicts[fd].stdHW); - eexecWrite(&eb, buf); - } - if (privateDicts[fd].hasStdVW) { - sprintf(buf, "/StdVW [%g] def\n", privateDicts[fd].stdVW); - eexecWrite(&eb, buf); - } - if (privateDicts[fd].nStemSnapH) { - eexecWrite(&eb, "/StemSnapH ["); - for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) { - sprintf(buf, "%s%g", k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].nStemSnapV) { - eexecWrite(&eb, "/StemSnapV ["); - for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) { - sprintf(buf, "%s%g", k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]); - eexecWrite(&eb, buf); - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].hasForceBold) { - sprintf(buf, "/ForceBold %s def\n", - privateDicts[fd].forceBold ? "true" : "false"); - eexecWrite(&eb, buf); - } - if (privateDicts[fd].forceBoldThreshold != 0) { - sprintf(buf, "/ForceBoldThreshold %g def\n", - privateDicts[fd].forceBoldThreshold); - eexecWrite(&eb, buf); - } - if (privateDicts[fd].languageGroup != 0) { - sprintf(buf, "/LanguageGroup %d def\n", privateDicts[fd].languageGroup); - eexecWrite(&eb, buf); - } - if (privateDicts[fd].expansionFactor != 0.06) { - sprintf(buf, "/ExpansionFactor %g def\n", - privateDicts[fd].expansionFactor); - eexecWrite(&eb, buf); - } - - // set up the subroutines - ok = gTrue; - getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok); - if (!ok) { - subrIdx.pos = -1; - } - - // start the CharStrings - sprintf(buf, "2 index /CharStrings 256 dict dup begin\n"); - eexecWrite(&eb, buf); - - // write the .notdef CharString - ok = gTrue; - getIndexVal(&charStringsIdx, 0, &val, &ok); - if (ok) { - eexecCvtGlyph(&eb, ".notdef", val.pos, val.len, - &subrIdx, &privateDicts[fd]); - } - - // write the CharStrings - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - if (cidMap[i+j] >= 0) { - ok = gTrue; - getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok); - if (ok) { - sprintf(buf, "c%02x", j); - eexecCvtGlyph(&eb, buf, val.pos, val.len, - &subrIdx, &privateDicts[fd]); - } - } - } - eexecWrite(&eb, "end\n"); - eexecWrite(&eb, "end\n"); - eexecWrite(&eb, "readonly put\n"); - eexecWrite(&eb, "noaccess put\n"); - eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); - eexecWrite(&eb, "mark currentfile closefile\n"); - - // trailer - if (eb.line > 0) { - (*outputFunc)(outputStream, "\n", 1); - } - for (j = 0; j < 8; ++j) { - (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); - } - (*outputFunc)(outputStream, "cleartomark\n", 12); - } - - // write the Type 0 parent font - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 0 def\n", 16); - if (topDict.hasFontMatrix) { - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], - topDict.fontMatrix[2], topDict.fontMatrix[3], - topDict.fontMatrix[4], topDict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } else { - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - } - (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); - (*outputFunc)(outputStream, "/Encoding [\n", 12); - for (i = 0; i < nCIDs; i += 256) { - sprintf(buf, "%d\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "/FDepVector [\n", 14); - for (i = 0; i < nCIDs; i += 256) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, psName, strlen(psName)); - sprintf(buf, "_%02x findfont\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); - - gfree(cidMap); -} - -void FoFiType1C::eexecCvtGlyph(Type1CEexecBuf *eb, const char *glyphName, - int offset, int nBytes, - Type1CIndex *subrIdx, - Type1CPrivateDict *pDict) { - char buf[512]; - GString *charBuf; - - // generate the charstring - charBuf = new GString(); - cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue); - - sprintf(buf, "/%s %d RD ", glyphName, charBuf->getLength()); - eexecWrite(eb, buf); - eexecWriteCharstring(eb, (Guchar *)charBuf->getCString(), - charBuf->getLength()); - eexecWrite(eb, " ND\n"); - - delete charBuf; -} - -void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, - Type1CIndex *subrIdx, Type1CPrivateDict *pDict, - GBool top) { - Type1CIndexVal val; - GBool ok, dFP; - double d, dx, dy; - Gushort r2; - Guchar byte; - int pos, subrBias, start, i, k; - - start = charBuf->getLength(); - if (top) { - charBuf->append((char)73); - charBuf->append((char)58); - charBuf->append((char)147); - charBuf->append((char)134); - nOps = 0; - nHints = 0; - firstOp = gTrue; - openPath = gFalse; - } - - pos = offset; - while (pos < offset + nBytes) { - ok = gTrue; - pos = getOp(pos, gTrue, &ok); - if (!ok) { - break; - } - if (!ops[nOps - 1].isNum) { - --nOps; // drop the operator - switch (ops[nOps].op) { - case 0x0001: // hstem - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); - } - d = 0; - dFP = gFalse; - for (k = 0; k < nOps; k += 2) { - // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints - if (ops[k+1].num < 0) { - d += ops[k].num + ops[k+1].num; - dFP |= ops[k].isFP | ops[k+1].isFP; - cvtNum(d, dFP, charBuf); - cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); - } else { - d += ops[k].num; - dFP |= ops[k].isFP; - cvtNum(d, dFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - d += ops[k+1].num; - dFP |= ops[k+1].isFP; - } - charBuf->append((char)1); - } - nHints += nOps / 2; - nOps = 0; - break; - case 0x0003: // vstem - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); - } - d = 0; - dFP = gFalse; - for (k = 0; k < nOps; k += 2) { - // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints - if (ops[k+1].num < 0) { - d += ops[k].num + ops[k+1].num; - dFP |= ops[k].isFP | ops[k+1].isFP; - cvtNum(d, dFP, charBuf); - cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); - } else { - d += ops[k].num; - dFP |= ops[k].isFP; - cvtNum(d, dFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - d += ops[k+1].num; - dFP |= ops[k+1].isFP; - } - charBuf->append((char)3); - } - nHints += nOps / 2; - nOps = 0; - break; - case 0x0004: // vmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 2, charBuf, pDict); - firstOp = gFalse; - } - if (openPath) { - charBuf->append((char)9); - openPath = gFalse; - } - if (nOps != 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - charBuf->append((char)4); - nOps = 0; - break; - case 0x0005: // rlineto - if (nOps < 2 || nOps % 2 != 0) { - //~ error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); - } - for (k = 0; k < nOps; k += 2) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - charBuf->append((char)5); - } - nOps = 0; - openPath = gTrue; - break; - case 0x0006: // hlineto - if (nOps < 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); - } - for (k = 0; k < nOps; ++k) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - charBuf->append((char)((k & 1) ? 7 : 6)); - } - nOps = 0; - openPath = gTrue; - break; - case 0x0007: // vlineto - if (nOps < 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); - } - for (k = 0; k < nOps; ++k) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - charBuf->append((char)((k & 1) ? 6 : 7)); - } - nOps = 0; - openPath = gTrue; - break; - case 0x0008: // rrcurveto - if (nOps < 6 || nOps % 6 != 0) { - //~ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); - } - for (k = 0; k < nOps; k += 6) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); - charBuf->append((char)8); - } - nOps = 0; - openPath = gTrue; - break; - case 0x000a: // callsubr - if (nOps >= 1) { - subrBias = (subrIdx->len < 1240) - ? 107 : (subrIdx->len < 33900) ? 1131 : 32768; - k = subrBias + (int)ops[nOps - 1].num; - --nOps; - ok = gTrue; - getIndexVal(subrIdx, k, &val, &ok); - if (ok) { - cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); - } - } else { - //~ error(-1, "Too few args to Type 2 callsubr"); - } - // don't clear the stack - break; - case 0x000b: // return - // don't clear the stack - break; - case 0x000e: // endchar / seac - if (firstOp) { - cvtGlyphWidth(nOps == 1 || nOps == 5, charBuf, pDict); - firstOp = gFalse; - } - if (openPath) { - charBuf->append((char)9); - openPath = gFalse; - } - if (nOps == 4) { - cvtNum(0, gFalse, charBuf); - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - charBuf->append((char)12)->append((char)6); - } else if (nOps == 0) { - charBuf->append((char)14); - } else { - //~ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); - } - nOps = 0; - break; - case 0x000f: // (obsolete) - // this op is ignored, but we need the glyph width - if (firstOp) { - cvtGlyphWidth(nOps > 0, charBuf, pDict); - firstOp = gFalse; - } - nOps = 0; - break; - case 0x0010: // blend - //~ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); - nOps = 0; - break; - case 0x0012: // hstemhm - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); - } - nHints += nOps / 2; - nOps = 0; - break; - case 0x0013: // hintmask - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps > 0) { - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", - //~ nOps); - } - nHints += nOps / 2; - } - pos += (nHints + 7) >> 3; - nOps = 0; - break; - case 0x0014: // cntrmask - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps > 0) { - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", - //~ nOps); - } - nHints += nOps / 2; - } - pos += (nHints + 7) >> 3; - nOps = 0; - break; - case 0x0015: // rmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 3, charBuf, pDict); - firstOp = gFalse; - } - if (openPath) { - charBuf->append((char)9); - openPath = gFalse; - } - if (nOps != 2) { - //~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - charBuf->append((char)21); - nOps = 0; - break; - case 0x0016: // hmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 2, charBuf, pDict); - firstOp = gFalse; - } - if (openPath) { - charBuf->append((char)9); - openPath = gFalse; - } - if (nOps != 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - charBuf->append((char)22); - nOps = 0; - break; - case 0x0017: // vstemhm - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); - } - nHints += nOps / 2; - nOps = 0; - break; - case 0x0018: // rcurveline - if (nOps < 8 || (nOps - 2) % 6 != 0) { - //~ error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps); - } - for (k = 0; k < nOps - 2; k += 6) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); - charBuf->append((char)8); - } - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k].isFP, charBuf); - charBuf->append((char)5); - nOps = 0; - openPath = gTrue; - break; - case 0x0019: // rlinecurve - if (nOps < 8 || (nOps - 6) % 2 != 0) { - //~ error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps); - } - for (k = 0; k < nOps - 6; k += 2) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k].isFP, charBuf); - charBuf->append((char)5); - } - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); - charBuf->append((char)8); - nOps = 0; - openPath = gTrue; - break; - case 0x001a: // vvcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps); - } - if (nOps % 2 == 1) { - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - charBuf->append((char)8); - k = 5; - } else { - k = 0; - } - for (; k < nOps; k += 4) { - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - charBuf->append((char)8); - } - nOps = 0; - openPath = gTrue; - break; - case 0x001b: // hhcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps); - } - if (nOps % 2 == 1) { - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - charBuf->append((char)8); - k = 5; - } else { - k = 0; - } - for (; k < nOps; k += 4) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - charBuf->append((char)8); - } - nOps = 0; - openPath = gTrue; - break; - case 0x001d: // callgsubr - if (nOps >= 1) { - k = gsubrBias + (int)ops[nOps - 1].num; - --nOps; - ok = gTrue; - getIndexVal(&gsubrIdx, k, &val, &ok); - if (ok) { - cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); - } - } else { - //~ error(-1, "Too few args to Type 2 callgsubr"); - } - // don't clear the stack - break; - case 0x001e: // vhcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps); - } - for (k = 0; k < nOps && k != nOps-5; k += 4) { - if (k % 8 == 0) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - charBuf->append((char)30); - } else { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - charBuf->append((char)31); - } - } - if (k == nOps-5) { - if (k % 8 == 0) { - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - } else { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - } - charBuf->append((char)8); - } - nOps = 0; - openPath = gTrue; - break; - case 0x001f: // hvcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps); - } - for (k = 0; k < nOps && k != nOps-5; k += 4) { - if (k % 8 == 0) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - charBuf->append((char)31); - } else { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - charBuf->append((char)30); - } - } - if (k == nOps-5) { - if (k % 8 == 0) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - } else { - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - } - charBuf->append((char)8); - } - nOps = 0; - openPath = gTrue; - break; - case 0x0c00: // dotsection (should be Type 1 only?) - // ignored - nOps = 0; - break; - case 0x0c03: // and - case 0x0c04: // or - case 0x0c05: // not - case 0x0c08: // store - case 0x0c09: // abs - case 0x0c0a: // add - case 0x0c0b: // sub - case 0x0c0c: // div - case 0x0c0d: // load - case 0x0c0e: // neg - case 0x0c0f: // eq - case 0x0c12: // drop - case 0x0c14: // put - case 0x0c15: // get - case 0x0c16: // ifelse - case 0x0c17: // random - case 0x0c18: // mul - case 0x0c1a: // sqrt - case 0x0c1b: // dup - case 0x0c1c: // exch - case 0x0c1d: // index - case 0x0c1e: // roll - //~ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); - nOps = 0; - break; - case 0x0c22: // hflex - if (nOps != 7) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - charBuf->append((char)8); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[5].num, ops[5].isFP, charBuf); - cvtNum(-ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[6].num, ops[6].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - charBuf->append((char)8); - nOps = 0; - openPath = gTrue; - break; - case 0x0c23: // flex - if (nOps != 13) { - //~ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - cvtNum(ops[5].num, ops[5].isFP, charBuf); - charBuf->append((char)8); - cvtNum(ops[6].num, ops[6].isFP, charBuf); - cvtNum(ops[7].num, ops[7].isFP, charBuf); - cvtNum(ops[8].num, ops[8].isFP, charBuf); - cvtNum(ops[9].num, ops[9].isFP, charBuf); - cvtNum(ops[10].num, ops[10].isFP, charBuf); - cvtNum(ops[11].num, ops[11].isFP, charBuf); - charBuf->append((char)8); - nOps = 0; - openPath = gTrue; - break; - case 0x0c24: // hflex1 - if (nOps != 9) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - charBuf->append((char)8); - cvtNum(ops[5].num, ops[5].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[6].num, ops[6].isFP, charBuf); - cvtNum(ops[7].num, ops[7].isFP, charBuf); - cvtNum(ops[8].num, ops[8].isFP, charBuf); - cvtNum(-(ops[1].num + ops[3].num + ops[7].num), - ops[1].isFP | ops[3].isFP | ops[7].isFP, charBuf); - charBuf->append((char)8); - nOps = 0; - openPath = gTrue; - break; - case 0x0c25: // flex1 - if (nOps != 11) { - //~ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - cvtNum(ops[5].num, ops[5].isFP, charBuf); - charBuf->append((char)8); - cvtNum(ops[6].num, ops[6].isFP, charBuf); - cvtNum(ops[7].num, ops[7].isFP, charBuf); - cvtNum(ops[8].num, ops[8].isFP, charBuf); - cvtNum(ops[9].num, ops[9].isFP, charBuf); - dx = ops[0].num + ops[2].num + ops[4].num + ops[6].num + ops[8].num; - dy = ops[1].num + ops[3].num + ops[5].num + ops[7].num + ops[9].num; - if (fabs(dx) > fabs(dy)) { - cvtNum(ops[10].num, ops[10].isFP, charBuf); - cvtNum(-dy, ops[1].isFP | ops[3].isFP | ops[5].isFP | - ops[7].isFP | ops[9].isFP, charBuf); - } else { - cvtNum(-dx, ops[0].isFP | ops[2].isFP | ops[4].isFP | - ops[6].isFP | ops[8].isFP, charBuf); - cvtNum(ops[10].num, ops[10].isFP, charBuf); - } - charBuf->append((char)8); - nOps = 0; - openPath = gTrue; - break; - default: - //~ error(-1, "Illegal Type 2 charstring op: %04x", - //~ ops[nOps].op); - nOps = 0; - break; - } - } - } - - // charstring encryption - if (top) { - r2 = 4330; - for (i = start; i < charBuf->getLength(); ++i) { - byte = charBuf->getChar(i) ^ (r2 >> 8); - charBuf->setChar(i, byte); - r2 = (byte + r2) * 52845 + 22719; - } - } -} - -void FoFiType1C::cvtGlyphWidth(GBool useOp, GString *charBuf, - Type1CPrivateDict *pDict) { - double w; - GBool wFP; - int i; - - if (useOp) { - w = pDict->nominalWidthX + ops[0].num; - wFP = pDict->nominalWidthXFP | ops[0].isFP; - for (i = 1; i < nOps; ++i) { - ops[i-1] = ops[i]; - } - --nOps; - } else { - w = pDict->defaultWidthX; - wFP = pDict->defaultWidthXFP; - } - cvtNum(0, gFalse, charBuf); - cvtNum(w, wFP, charBuf); - charBuf->append((char)13); -} - -void FoFiType1C::cvtNum(double x, GBool isFP, GString *charBuf) { - Guchar buf[12]; - int y, n; - - n = 0; - if (isFP) { - if (x >= -32768 && x < 32768) { - y = (int)(x * 256.0); - buf[0] = 255; - buf[1] = (Guchar)(y >> 24); - buf[2] = (Guchar)(y >> 16); - buf[3] = (Guchar)(y >> 8); - buf[4] = (Guchar)y; - buf[5] = 255; - buf[6] = 0; - buf[7] = 0; - buf[8] = 1; - buf[9] = 0; - buf[10] = 12; - buf[11] = 12; - n = 12; - } else { - //~ error(-1, "Type 2 fixed point constant out of range"); - } - } else { - y = (int)x; - if (y >= -107 && y <= 107) { - buf[0] = (Guchar)(y + 139); - n = 1; - } else if (y > 107 && y <= 1131) { - y -= 108; - buf[0] = (Guchar)((y >> 8) + 247); - buf[1] = (Guchar)(y & 0xff); - n = 2; - } else if (y < -107 && y >= -1131) { - y = -y - 108; - buf[0] = (Guchar)((y >> 8) + 251); - buf[1] = (Guchar)(y & 0xff); - n = 2; - } else { - buf[0] = 255; - buf[1] = (Guchar)(y >> 24); - buf[2] = (Guchar)(y >> 16); - buf[3] = (Guchar)(y >> 8); - buf[4] = (Guchar)y; - n = 5; - } - } - charBuf->append((char *)buf, n); -} - -void FoFiType1C::eexecWrite(Type1CEexecBuf *eb, const char *s) { - Guchar *p; - Guchar x; - - for (p = (Guchar *)s; *p; ++p) { - x = *p ^ (eb->r1 >> 8); - eb->r1 = (x + eb->r1) * 52845 + 22719; - if (eb->ascii) { - (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); - (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); - eb->line += 2; - if (eb->line == 64) { - (*eb->outputFunc)(eb->outputStream, "\n", 1); - eb->line = 0; - } - } else { - (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); - } - } -} - -void FoFiType1C::eexecWriteCharstring(Type1CEexecBuf *eb, - Guchar *s, int n) { - Guchar x; - int i; - - // eexec encryption - for (i = 0; i < n; ++i) { - x = s[i] ^ (eb->r1 >> 8); - eb->r1 = (x + eb->r1) * 52845 + 22719; - if (eb->ascii) { - (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); - (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); - eb->line += 2; - if (eb->line == 64) { - (*eb->outputFunc)(eb->outputStream, "\n", 1); - eb->line = 0; - } - } else { - (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); - } - } -} - -GBool FoFiType1C::parse() { - Type1CIndex fdIdx; - Type1CIndexVal val; - int i; - - parsedOk = gTrue; - - // some tools embed Type 1C fonts with an extra whitespace char at - // the beginning - if (len > 0 && file[0] != '\x01') { - ++file; - --len; - } - - // find the indexes - getIndex(getU8(2, &parsedOk), &nameIdx, &parsedOk); - getIndex(nameIdx.endPos, &topDictIdx, &parsedOk); - getIndex(topDictIdx.endPos, &stringIdx, &parsedOk); - getIndex(stringIdx.endPos, &gsubrIdx, &parsedOk); - if (!parsedOk) { - return gFalse; - } - gsubrBias = (gsubrIdx.len < 1240) ? 107 - : (gsubrIdx.len < 33900) ? 1131 : 32768; - - // read the first font name - getIndexVal(&nameIdx, 0, &val, &parsedOk); - if (!parsedOk) { - return gFalse; - } - name = new GString((char *)&file[val.pos], val.len); - - // read the top dict for the first font - readTopDict(); - - // for CID fonts: read the FDArray dicts and private dicts - if (topDict.firstOp == 0x0c1e) { - if (topDict.fdArrayOffset == 0) { - nFDs = 1; - privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); - readPrivateDict(0, 0, &privateDicts[0]); - } else { - getIndex(topDict.fdArrayOffset, &fdIdx, &parsedOk); - if (!parsedOk) { - return gFalse; - } - nFDs = fdIdx.len; - privateDicts = (Type1CPrivateDict *) - gmallocn(nFDs, sizeof(Type1CPrivateDict)); - for (i = 0; i < nFDs; ++i) { - getIndexVal(&fdIdx, i, &val, &parsedOk); - if (!parsedOk) { - return gFalse; - } - readFD(val.pos, val.len, &privateDicts[i]); - } - } - - // for 8-bit fonts: read the private dict - } else { - privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); - readPrivateDict(topDict.privateOffset, topDict.privateSize, - &privateDicts[0]); - } - - // check for parse errors in the private dict(s) - if (!parsedOk) { - return gFalse; - } - - // get the charstrings index - if (topDict.charStringsOffset <= 0) { - parsedOk = gFalse; - return gFalse; - } - getIndex(topDict.charStringsOffset, &charStringsIdx, &parsedOk); - if (!parsedOk) { - return gFalse; - } - nGlyphs = charStringsIdx.len; - - // for CID fonts: read the FDSelect table - if (topDict.firstOp == 0x0c1e) { - readFDSelect(); - if (!parsedOk) { - return gFalse; - } - } - - // read the charset - if (!readCharset()) { - parsedOk = gFalse; - return gFalse; - } - - // for 8-bit fonts: build the encoding - if (topDict.firstOp != 0x0c14 && topDict.firstOp != 0x0c1e) { - buildEncoding(); - if (!parsedOk) { - return gFalse; - } - } - - return parsedOk; -} - -void FoFiType1C::readTopDict() { - Type1CIndexVal topDictPtr; - int pos; - - topDict.firstOp = -1; - topDict.versionSID = 0; - topDict.noticeSID = 0; - topDict.copyrightSID = 0; - topDict.fullNameSID = 0; - topDict.familyNameSID = 0; - topDict.weightSID = 0; - topDict.isFixedPitch = 0; - topDict.italicAngle = 0; - topDict.underlinePosition = -100; - topDict.underlineThickness = 50; - topDict.paintType = 0; - topDict.charstringType = 2; - topDict.fontMatrix[0] = 0.001; - topDict.fontMatrix[1] = 0; - topDict.fontMatrix[2] = 0; - topDict.fontMatrix[3] = 0.001; - topDict.fontMatrix[4] = 0; - topDict.fontMatrix[5] = 0; - topDict.hasFontMatrix = gFalse; - topDict.uniqueID = 0; - topDict.fontBBox[0] = 0; - topDict.fontBBox[1] = 0; - topDict.fontBBox[2] = 0; - topDict.fontBBox[3] = 0; - topDict.strokeWidth = 0; - topDict.charsetOffset = 0; - topDict.encodingOffset = 0; - topDict.charStringsOffset = 0; - topDict.privateSize = 0; - topDict.privateOffset = 0; - topDict.registrySID = 0; - topDict.orderingSID = 0; - topDict.supplement = 0; - topDict.fdArrayOffset = 0; - topDict.fdSelectOffset = 0; - - getIndexVal(&topDictIdx, 0, &topDictPtr, &parsedOk); - pos = topDictPtr.pos; - nOps = 0; - while (pos < topDictPtr.pos + topDictPtr.len) { - pos = getOp(pos, gFalse, &parsedOk); - if (!parsedOk) { - break; - } - if (!ops[nOps - 1].isNum) { - --nOps; // drop the operator - if (topDict.firstOp < 0) { - topDict.firstOp = ops[nOps].op; - } - switch (ops[nOps].op) { - case 0x0000: topDict.versionSID = (int)ops[0].num; break; - case 0x0001: topDict.noticeSID = (int)ops[0].num; break; - case 0x0c00: topDict.copyrightSID = (int)ops[0].num; break; - case 0x0002: topDict.fullNameSID = (int)ops[0].num; break; - case 0x0003: topDict.familyNameSID = (int)ops[0].num; break; - case 0x0004: topDict.weightSID = (int)ops[0].num; break; - case 0x0c01: topDict.isFixedPitch = (int)ops[0].num; break; - case 0x0c02: topDict.italicAngle = ops[0].num; break; - case 0x0c03: topDict.underlinePosition = ops[0].num; break; - case 0x0c04: topDict.underlineThickness = ops[0].num; break; - case 0x0c05: topDict.paintType = (int)ops[0].num; break; - case 0x0c06: topDict.charstringType = (int)ops[0].num; break; - case 0x0c07: topDict.fontMatrix[0] = ops[0].num; - topDict.fontMatrix[1] = ops[1].num; - topDict.fontMatrix[2] = ops[2].num; - topDict.fontMatrix[3] = ops[3].num; - topDict.fontMatrix[4] = ops[4].num; - topDict.fontMatrix[5] = ops[5].num; - topDict.hasFontMatrix = gTrue; break; - case 0x000d: topDict.uniqueID = (int)ops[0].num; break; - case 0x0005: topDict.fontBBox[0] = ops[0].num; - topDict.fontBBox[1] = ops[1].num; - topDict.fontBBox[2] = ops[2].num; - topDict.fontBBox[3] = ops[3].num; break; - case 0x0c08: topDict.strokeWidth = ops[0].num; break; - case 0x000f: topDict.charsetOffset = (int)ops[0].num; break; - case 0x0010: topDict.encodingOffset = (int)ops[0].num; break; - case 0x0011: topDict.charStringsOffset = (int)ops[0].num; break; - case 0x0012: topDict.privateSize = (int)ops[0].num; - topDict.privateOffset = (int)ops[1].num; break; - case 0x0c1e: topDict.registrySID = (int)ops[0].num; - topDict.orderingSID = (int)ops[1].num; - topDict.supplement = (int)ops[2].num; break; - case 0x0c24: topDict.fdArrayOffset = (int)ops[0].num; break; - case 0x0c25: topDict.fdSelectOffset = (int)ops[0].num; break; - } - nOps = 0; - } - } -} - -// Read a CID font dict (FD) - this pulls out the private dict -// pointer, and reads the private dict. It also pulls the FontMatrix -// (if any) out of the FD. -void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) { - int pos, pSize, pOffset; - double fontMatrix[6]; - GBool hasFontMatrix; - - hasFontMatrix = gFalse; - pSize = pOffset = 0; - pos = offset; - nOps = 0; - while (pos < offset + length) { - pos = getOp(pos, gFalse, &parsedOk); - if (!parsedOk) { - return; - } - if (!ops[nOps - 1].isNum) { - if (ops[nOps - 1].op == 0x0012) { - if (nOps < 3) { - parsedOk = gFalse; - return; - } - pSize = (int)ops[0].num; - pOffset = (int)ops[1].num; - break; - } else if (ops[nOps - 1].op == 0x0c07) { - fontMatrix[0] = ops[0].num; - fontMatrix[1] = ops[1].num; - fontMatrix[2] = ops[2].num; - fontMatrix[3] = ops[3].num; - fontMatrix[4] = ops[4].num; - fontMatrix[5] = ops[5].num; - hasFontMatrix = gTrue; - } - nOps = 0; - } - } - readPrivateDict(pOffset, pSize, pDict); - if (hasFontMatrix) { - pDict->fontMatrix[0] = fontMatrix[0]; - pDict->fontMatrix[1] = fontMatrix[1]; - pDict->fontMatrix[2] = fontMatrix[2]; - pDict->fontMatrix[3] = fontMatrix[3]; - pDict->fontMatrix[4] = fontMatrix[4]; - pDict->fontMatrix[5] = fontMatrix[5]; - pDict->hasFontMatrix = gTrue; - } -} - -void FoFiType1C::readPrivateDict(int offset, int length, - Type1CPrivateDict *pDict) { - int pos; - - pDict->hasFontMatrix = gFalse; - pDict->nBlueValues = 0; - pDict->nOtherBlues = 0; - pDict->nFamilyBlues = 0; - pDict->nFamilyOtherBlues = 0; - pDict->blueScale = 0.039625; - pDict->blueShift = 7; - pDict->blueFuzz = 1; - pDict->hasStdHW = gFalse; - pDict->hasStdVW = gFalse; - pDict->nStemSnapH = 0; - pDict->nStemSnapV = 0; - pDict->hasForceBold = gFalse; - pDict->forceBoldThreshold = 0; - pDict->languageGroup = 0; - pDict->expansionFactor = 0.06; - pDict->initialRandomSeed = 0; - pDict->subrsOffset = 0; - pDict->defaultWidthX = 0; - pDict->defaultWidthXFP = gFalse; - pDict->nominalWidthX = 0; - pDict->nominalWidthXFP = gFalse; - - // no dictionary - if (offset == 0 || length == 0) { - return; - } - - pos = offset; - nOps = 0; - while (pos < offset + length) { - pos = getOp(pos, gFalse, &parsedOk); - if (!parsedOk) { - break; - } - if (!ops[nOps - 1].isNum) { - --nOps; // drop the operator - switch (ops[nOps].op) { - case 0x0006: - pDict->nBlueValues = getDeltaIntArray(pDict->blueValues, - type1CMaxBlueValues); - break; - case 0x0007: - pDict->nOtherBlues = getDeltaIntArray(pDict->otherBlues, - type1CMaxOtherBlues); - break; - case 0x0008: - pDict->nFamilyBlues = getDeltaIntArray(pDict->familyBlues, - type1CMaxBlueValues); - break; - case 0x0009: - pDict->nFamilyOtherBlues = getDeltaIntArray(pDict->familyOtherBlues, - type1CMaxOtherBlues); - break; - case 0x0c09: - pDict->blueScale = ops[0].num; - break; - case 0x0c0a: - pDict->blueShift = (int)ops[0].num; - break; - case 0x0c0b: - pDict->blueFuzz = (int)ops[0].num; - break; - case 0x000a: - pDict->stdHW = ops[0].num; - pDict->hasStdHW = gTrue; - break; - case 0x000b: - pDict->stdVW = ops[0].num; - pDict->hasStdVW = gTrue; - break; - case 0x0c0c: - pDict->nStemSnapH = getDeltaFPArray(pDict->stemSnapH, - type1CMaxStemSnap); - break; - case 0x0c0d: - pDict->nStemSnapV = getDeltaFPArray(pDict->stemSnapV, - type1CMaxStemSnap); - break; - case 0x0c0e: - pDict->forceBold = ops[0].num != 0; - pDict->hasForceBold = gTrue; - break; - case 0x0c0f: - pDict->forceBoldThreshold = ops[0].num; - break; - case 0x0c11: - pDict->languageGroup = (int)ops[0].num; - break; - case 0x0c12: - pDict->expansionFactor = ops[0].num; - break; - case 0x0c13: - pDict->initialRandomSeed = (int)ops[0].num; - break; - case 0x0013: - pDict->subrsOffset = offset + (int)ops[0].num; - break; - case 0x0014: - pDict->defaultWidthX = ops[0].num; - pDict->defaultWidthXFP = ops[0].isFP; - break; - case 0x0015: - pDict->nominalWidthX = ops[0].num; - pDict->nominalWidthXFP = ops[0].isFP; - break; - } - nOps = 0; - } - } -} - -void FoFiType1C::readFDSelect() { - int fdSelectFmt, pos, nRanges, gid0, gid1, fd, i, j; - - fdSelect = (Guchar *)gmalloc(nGlyphs); - if (topDict.fdSelectOffset == 0) { - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } else { - pos = topDict.fdSelectOffset; - fdSelectFmt = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - if (fdSelectFmt == 0) { - if (!checkRegion(pos, nGlyphs)) { - parsedOk = gFalse; - return; - } - memcpy(fdSelect, file + pos, nGlyphs); - } else if (fdSelectFmt == 3) { - nRanges = getU16BE(pos, &parsedOk); - pos += 2; - gid0 = getU16BE(pos, &parsedOk); - pos += 2; - for (i = 1; i <= nRanges; ++i) { - fd = getU8(pos++, &parsedOk); - gid1 = getU16BE(pos, &parsedOk); - if (!parsedOk) { - return; - } - pos += 2; - if (gid0 > gid1 || gid1 > nGlyphs) { - //~ error(-1, "Bad FDSelect table in CID font"); - parsedOk = gFalse; - return; - } - for (j = gid0; j < gid1; ++j) { - fdSelect[j] = fd; - } - gid0 = gid1; - } - } else { - //~ error(-1, "Unknown FDSelect table format in CID font"); - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } - } -} - -void FoFiType1C::buildEncoding() { - char buf[256]; - int nCodes, nRanges, encFormat; - int pos, c, sid, nLeft, nSups, i, j; - - if (topDict.encodingOffset == 0) { - encoding = fofiType1StandardEncoding; - - } else if (topDict.encodingOffset == 1) { - encoding = fofiType1ExpertEncoding; - - } else { - encoding = (const char **)gmallocn(256, sizeof(char *)); - for (i = 0; i < 256; ++i) { - encoding[i] = NULL; - } - pos = topDict.encodingOffset; - encFormat = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - if ((encFormat & 0x7f) == 0) { - nCodes = 1 + getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - if (nCodes > nGlyphs) { - nCodes = nGlyphs; - } - for (i = 1; i < nCodes; ++i) { - c = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - if (encoding[c]) { - gfree((void*)encoding[c]); - } - encoding[c] = copyString(getString(charset[i], buf, &parsedOk)); - } - } else if ((encFormat & 0x7f) == 1) { - nRanges = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - nCodes = 1; - for (i = 0; i < nRanges; ++i) { - c = getU8(pos++, &parsedOk); - nLeft = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { - if (c < 256) { - if (encoding[c]) { - gfree((void*)encoding[c]); - } - encoding[c] = copyString(getString(charset[nCodes], buf, - &parsedOk)); - } - ++nCodes; - ++c; - } - } - } - if (encFormat & 0x80) { - nSups = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - for (i = 0; i < nSups; ++i) { - c = getU8(pos++, &parsedOk);; - if (!parsedOk) { - return;; - } - sid = getU16BE(pos, &parsedOk); - pos += 2; - if (!parsedOk) { - return; - } - if (encoding[c]) { - gfree((void*)encoding[c]); - } - encoding[c] = copyString(getString(sid, buf, &parsedOk)); - } - } - } -} - -GBool FoFiType1C::readCharset() { - int charsetFormat, c, pos; - int nLeft, i, j; - - if (topDict.charsetOffset == 0) { - charset = fofiType1CISOAdobeCharset; - } else if (topDict.charsetOffset == 1) { - charset = fofiType1CExpertCharset; - } else if (topDict.charsetOffset == 2) { - charset = fofiType1CExpertSubsetCharset; - } else { - charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort)); - for (i = 0; i < nGlyphs; ++i) { - charset[i] = 0; - } - pos = topDict.charsetOffset; - charsetFormat = getU8(pos++, &parsedOk); - if (charsetFormat == 0) { - for (i = 1; i < nGlyphs; ++i) { - charset[i] = (Gushort)getU16BE(pos, &parsedOk); - pos += 2; - if (!parsedOk) { - break; - } - } - } else if (charsetFormat == 1) { - i = 1; - while (i < nGlyphs) { - c = getU16BE(pos, &parsedOk); - pos += 2; - nLeft = getU8(pos++, &parsedOk); - if (!parsedOk) { - break; - } - for (j = 0; j <= nLeft && i < nGlyphs; ++j) { - charset[i++] = (Gushort)c++; - } - } - } else if (charsetFormat == 2) { - i = 1; - while (i < nGlyphs) { - c = getU16BE(pos, &parsedOk); - pos += 2; - nLeft = getU16BE(pos, &parsedOk); - pos += 2; - if (!parsedOk) { - break; - } - for (j = 0; j <= nLeft && i < nGlyphs; ++j) { - charset[i++] = (Gushort)c++; - } - } - } - if (!parsedOk) { - gfree(charset); - charset = NULL; - return gFalse; - } - } - return gTrue; -} - -int FoFiType1C::getOp(int pos, GBool charstring, GBool *ok) { - static char nybChars[16] = "0123456789.ee -"; - Type1COp op; - char buf[65]; - int b0, b1, nyb0, nyb1, x, i; - - b0 = getU8(pos++, ok); - op.isNum = gTrue; - op.isFP = gFalse; - - if (b0 == 28) { - x = getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - if (x & 0x8000) { - x |= ~0xffff; - } - op.num = x; - - } else if (!charstring && b0 == 29) { - x = getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - if (x & 0x80000000) { - x |= ~0xffffffff; - } - op.num = x; - - } else if (!charstring && b0 == 30) { - i = 0; - do { - b1 = getU8(pos++, ok); - nyb0 = b1 >> 4; - nyb1 = b1 & 0x0f; - if (nyb0 == 0xf) { - break; - } - buf[i++] = nybChars[nyb0]; - if (i == 64) { - break; - } - if (nyb0 == 0xc) { - buf[i++] = '-'; - } - if (i == 64) { - break; - } - if (nyb1 == 0xf) { - break; - } - buf[i++] = nybChars[nyb1]; - if (i == 64) { - break; - } - if (nyb1 == 0xc) { - buf[i++] = '-'; - } - } while (i < 64); - buf[i] = '\0'; - op.num = atof(buf); - op.isFP = gTrue; - - } else if (b0 >= 32 && b0 <= 246) { - op.num = b0 - 139; - - } else if (b0 >= 247 && b0 <= 250) { - op.num = ((b0 - 247) << 8) + getU8(pos++, ok) + 108; - - } else if (b0 >= 251 && b0 <= 254) { - op.num = -((b0 - 251) << 8) - getU8(pos++, ok) - 108; - - } else if (charstring && b0 == 255) { - x = getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - if (x & 0x80000000) { - x |= ~0xffffffff; - } - op.num = (double)x / 65536.0; - op.isFP = gTrue; - - } else if (b0 == 12) { - op.isNum = gFalse; - op.op = 0x0c00 + getU8(pos++, ok); - - } else { - op.isNum = gFalse; - op.op = b0; - } - - if (nOps < 49) { - ops[nOps++] = op; - } - - return pos; -} - -// Convert the delta-encoded ops array to an array of ints. -int FoFiType1C::getDeltaIntArray(int *arr, int maxLen) { - int x; - int n, i; - - if ((n = nOps) > maxLen) { - n = maxLen; - } - x = 0; - for (i = 0; i < n; ++i) { - x += (int)ops[i].num; - arr[i] = x; - } - return n; -} - -// Convert the delta-encoded ops array to an array of doubles. -int FoFiType1C::getDeltaFPArray(double *arr, int maxLen) { - double x; - int n, i; - - if ((n = nOps) > maxLen) { - n = maxLen; - } - x = 0; - for (i = 0; i < n; ++i) { - x += ops[i].num; - arr[i] = x; - } - return n; -} - -void FoFiType1C::getIndex(int pos, Type1CIndex *idx, GBool *ok) { - idx->pos = pos; - idx->len = getU16BE(pos, ok); - if (idx->len == 0) { - // empty indexes are legal and contain just the length field - idx->offSize = 0; - idx->startPos = idx->endPos = pos + 2; - } else { - idx->offSize = getU8(pos + 2, ok); - if (idx->offSize < 1 || idx->offSize > 4) { - *ok = gFalse; - } - idx->startPos = pos + 3 + (idx->len + 1) * idx->offSize - 1; - if (idx->startPos < 0 || idx->startPos >= len) { - *ok = gFalse; - } - idx->endPos = idx->startPos + getUVarBE(pos + 3 + idx->len * idx->offSize, - idx->offSize, ok); - if (idx->endPos < idx->startPos || idx->endPos > len) { - *ok = gFalse; - } - } -} - -void FoFiType1C::getIndexVal(Type1CIndex *idx, int i, - Type1CIndexVal *val, GBool *ok) { - int pos0, pos1; - - if (i < 0 || i >= idx->len) { - *ok = gFalse; - return; - } - pos0 = idx->startPos + getUVarBE(idx->pos + 3 + i * idx->offSize, - idx->offSize, ok); - pos1 = idx->startPos + getUVarBE(idx->pos + 3 + (i + 1) * idx->offSize, - idx->offSize, ok); - if (pos0 < idx->startPos || pos0 > idx->endPos || - pos1 <= idx->startPos || pos1 > idx->endPos || - pos1 < pos0) { - *ok = gFalse; - } - val->pos = pos0; - val->len = pos1 - pos0; -} - -char *FoFiType1C::getString(int sid, char *buf, GBool *ok) { - Type1CIndexVal val; - int n; - - if (sid < 391) { - strcpy(buf, fofiType1CStdStrings[sid]); - } else { - sid -= 391; - getIndexVal(&stringIdx, sid, &val, ok); - if (*ok) { - if ((n = val.len) > 255) { - n = 255; - } - strncpy(buf, (char *)&file[val.pos], n); - buf[n] = '\0'; - } else { - buf[0] = '\0'; - } - } - return buf; -} diff --git a/xpdf/fofi/FoFiType1C.h b/xpdf/fofi/FoFiType1C.h deleted file mode 100644 index a6c027388..000000000 --- a/xpdf/fofi/FoFiType1C.h +++ /dev/null @@ -1,232 +0,0 @@ -//======================================================================== -// -// FoFiType1C.h -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef FOFITYPE1C_H -#define FOFITYPE1C_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "FoFiBase.h" - -class GString; - -//------------------------------------------------------------------------ - -struct Type1CIndex { - int pos; // absolute position in file - int len; // length (number of entries) - int offSize; // offset size - int startPos; // position of start of index data - 1 - int endPos; // position one byte past end of the index -}; - -struct Type1CIndexVal { - int pos; // absolute position in file - int len; // length, in bytes -}; - -struct Type1CTopDict { - int firstOp; - - int versionSID; - int noticeSID; - int copyrightSID; - int fullNameSID; - int familyNameSID; - int weightSID; - int isFixedPitch; - double italicAngle; - double underlinePosition; - double underlineThickness; - int paintType; - int charstringType; - double fontMatrix[6]; - GBool hasFontMatrix; // CID fonts are allowed to put their - // FontMatrix in the FD instead of the - // top dict - int uniqueID; - double fontBBox[4]; - double strokeWidth; - int charsetOffset; - int encodingOffset; - int charStringsOffset; - int privateSize; - int privateOffset; - - // CIDFont entries - int registrySID; - int orderingSID; - int supplement; - int fdArrayOffset; - int fdSelectOffset; -}; - -#define type1CMaxBlueValues 14 -#define type1CMaxOtherBlues 10 -#define type1CMaxStemSnap 12 - -struct Type1CPrivateDict { - double fontMatrix[6]; - GBool hasFontMatrix; - int blueValues[type1CMaxBlueValues]; - int nBlueValues; - int otherBlues[type1CMaxOtherBlues]; - int nOtherBlues; - int familyBlues[type1CMaxBlueValues]; - int nFamilyBlues; - int familyOtherBlues[type1CMaxOtherBlues]; - int nFamilyOtherBlues; - double blueScale; - int blueShift; - int blueFuzz; - double stdHW; - GBool hasStdHW; - double stdVW; - GBool hasStdVW; - double stemSnapH[type1CMaxStemSnap]; - int nStemSnapH; - double stemSnapV[type1CMaxStemSnap]; - int nStemSnapV; - GBool forceBold; - GBool hasForceBold; - double forceBoldThreshold; - int languageGroup; - double expansionFactor; - int initialRandomSeed; - int subrsOffset; - double defaultWidthX; - GBool defaultWidthXFP; - double nominalWidthX; - GBool nominalWidthXFP; -}; - -struct Type1COp { - GBool isNum; // true -> number, false -> operator - GBool isFP; // true -> floating point number, false -> int - union { - double num; // if num is true - int op; // if num is false - }; -}; - -struct Type1CEexecBuf { - FoFiOutputFunc outputFunc; - void *outputStream; - GBool ascii; // ASCII encoding? - Gushort r1; // eexec encryption key - int line; // number of eexec chars left on current line -}; - -//------------------------------------------------------------------------ -// FoFiType1C -//------------------------------------------------------------------------ - -class FoFiType1C: public FoFiBase { -public: - - // Create a FoFiType1C object from a memory buffer. - static FoFiType1C *make(char *fileA, int lenA); - - // Create a FoFiType1C object from a file on disk. - static FoFiType1C *load(char *fileName); - - FoFiType1C(char *fileA, int lenA, GBool freeFileDataA); - virtual ~FoFiType1C(); - - // Return the font name. - char *getName(); - - // Return the encoding, as an array of 256 names (any of which may - // be NULL). This is only useful with 8-bit fonts. - const char **getEncoding(); - - // Return the mapping from CIDs to GIDs, and return the number of - // CIDs in *. This is only useful for CID fonts. - Gushort *getCIDToGIDMap(int *nCIDs); - - // Convert to a Type 1 font, suitable for embedding in a PostScript - // file. This is only useful with 8-bit fonts. If is - // not NULL, it will be used in place of the encoding in the Type 1C - // font. If is true the eexec section will be hex-encoded, - // otherwise it will be left as binary data. - void convertToType1(const char **newEncoding, GBool ascii, - FoFiOutputFunc outputFunc, void *outputStream); - - // Convert to a Type 0 CIDFont, suitable for embedding in a - // PostScript file. will be used as the PostScript font - // name. - void convertToCIDType0(char *psName, - FoFiOutputFunc outputFunc, void *outputStream); - - // Convert to a Type 0 (but non-CID) composite font, suitable for - // embedding in a PostScript file. will be used as the - // PostScript font name. - void convertToType0(char *psName, - FoFiOutputFunc outputFunc, void *outputStream); - -private: - - void eexecCvtGlyph(Type1CEexecBuf *eb, const char *glyphName, - int offset, int nBytes, - Type1CIndex *subrIdx, - Type1CPrivateDict *pDict); - void cvtGlyph(int offset, int nBytes, GString *charBuf, - Type1CIndex *subrIdx, Type1CPrivateDict *pDict, - GBool top); - void cvtGlyphWidth(GBool useOp, GString *charBuf, - Type1CPrivateDict *pDict); - void cvtNum(double x, GBool isFP, GString *charBuf); - void eexecWrite(Type1CEexecBuf *eb, const char *s); - void eexecWriteCharstring(Type1CEexecBuf *eb, Guchar *s, int n); - GBool parse(); - void readTopDict(); - void readFD(int offset, int length, Type1CPrivateDict *pDict); - void readPrivateDict(int offset, int length, Type1CPrivateDict *pDict); - void readFDSelect(); - void buildEncoding(); - GBool readCharset(); - int getOp(int pos, GBool charstring, GBool *ok); - int getDeltaIntArray(int *arr, int maxLen); - int getDeltaFPArray(double *arr, int maxLen); - void getIndex(int pos, Type1CIndex *idx, GBool *ok); - void getIndexVal(Type1CIndex *idx, int i, Type1CIndexVal *val, GBool *ok); - char *getString(int sid, char *buf, GBool *ok); - - GString *name; - const char **encoding; - - Type1CIndex nameIdx; - Type1CIndex topDictIdx; - Type1CIndex stringIdx; - Type1CIndex gsubrIdx; - Type1CIndex charStringsIdx; - - Type1CTopDict topDict; - Type1CPrivateDict *privateDicts; - - int nGlyphs; - int nFDs; - Guchar *fdSelect; - Gushort *charset; - int gsubrBias; - - GBool parsedOk; - - Type1COp ops[49]; // operands and operator - int nOps; // number of operands - int nHints; // number of hints for the current glyph - GBool firstOp; // true if we haven't hit the first op yet - GBool openPath; // true if there is an unclosed path -}; - -#endif diff --git a/xpdf/fofi/Makefile.am b/xpdf/fofi/Makefile.am deleted file mode 100644 index 7ca939225..000000000 --- a/xpdf/fofi/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../goo $(all_includes) - -libfofi_la_LDFLAGS = $(all_libraries) -libfofi_la_SOURCES = FoFiBase.cc FoFiEncodings.cc FoFiTrueType.cc \ - FoFiType1.cc FoFiType1C.cc - -METASOURCES = AUTO - -noinst_LTLIBRARIES = libfofi.la diff --git a/xpdf/goo/GHash.cc b/xpdf/goo/GHash.cc deleted file mode 100644 index 1a88f4e21..000000000 --- a/xpdf/goo/GHash.cc +++ /dev/null @@ -1,380 +0,0 @@ -//======================================================================== -// -// GHash.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "gmem.h" -#include "GString.h" -#include "GHash.h" - -//------------------------------------------------------------------------ - -struct GHashBucket { - GString *key; - union { - void *p; - int i; - } val; - GHashBucket *next; -}; - -struct GHashIter { - int h; - GHashBucket *p; -}; - -//------------------------------------------------------------------------ - -GHash::GHash(GBool deleteKeysA) { - int h; - - deleteKeys = deleteKeysA; - size = 7; - tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); - for (h = 0; h < size; ++h) { - tab[h] = NULL; - } - len = 0; -} - -GHash::~GHash() { - GHashBucket *p; - int h; - - for (h = 0; h < size; ++h) { - while (tab[h]) { - p = tab[h]; - tab[h] = p->next; - if (deleteKeys) { - delete p->key; - } - delete p; - } - } - gfree(tab); -} - -void GHash::add(GString *key, void *val) { - GHashBucket *p; - int h; - - // expand the table if necessary - if (len >= size) { - expand(); - } - - // add the new symbol - p = new GHashBucket; - p->key = key; - p->val.p = val; - h = hash(key); - p->next = tab[h]; - tab[h] = p; - ++len; -} - -void GHash::add(GString *key, int val) { - GHashBucket *p; - int h; - - // expand the table if necessary - if (len >= size) { - expand(); - } - - // add the new symbol - p = new GHashBucket; - p->key = key; - p->val.i = val; - h = hash(key); - p->next = tab[h]; - tab[h] = p; - ++len; -} - -void GHash::replace(GString *key, void *val) { - GHashBucket *p; - int h; - - if ((p = find(key, &h))) { - p->val.p = val; - delete key; - } else { - add(key, val); - } -} - -void GHash::replace(GString *key, int val) { - GHashBucket *p; - int h; - - if ((p = find(key, &h))) { - p->val.i = val; - delete key; - } else { - add(key, val); - } -} - -void *GHash::lookup(GString *key) { - GHashBucket *p; - int h; - - if (!(p = find(key, &h))) { - return NULL; - } - return p->val.p; -} - -int GHash::lookupInt(GString *key) { - GHashBucket *p; - int h; - - if (!(p = find(key, &h))) { - return 0; - } - return p->val.i; -} - -void *GHash::lookup(char *key) { - GHashBucket *p; - int h; - - if (!(p = find(key, &h))) { - return NULL; - } - return p->val.p; -} - -int GHash::lookupInt(const char *key) { - GHashBucket *p; - int h; - - if (!(p = find(key, &h))) { - return 0; - } - return p->val.i; -} - -void *GHash::remove(GString *key) { - GHashBucket *p; - GHashBucket **q; - void *val; - int h; - - if (!(p = find(key, &h))) { - return NULL; - } - q = &tab[h]; - while (*q != p) { - q = &((*q)->next); - } - *q = p->next; - if (deleteKeys) { - delete p->key; - } - val = p->val.p; - delete p; - --len; - return val; -} - -int GHash::removeInt(GString *key) { - GHashBucket *p; - GHashBucket **q; - int val; - int h; - - if (!(p = find(key, &h))) { - return 0; - } - q = &tab[h]; - while (*q != p) { - q = &((*q)->next); - } - *q = p->next; - if (deleteKeys) { - delete p->key; - } - val = p->val.i; - delete p; - --len; - return val; -} - -void *GHash::remove(char *key) { - GHashBucket *p; - GHashBucket **q; - void *val; - int h; - - if (!(p = find(key, &h))) { - return NULL; - } - q = &tab[h]; - while (*q != p) { - q = &((*q)->next); - } - *q = p->next; - if (deleteKeys) { - delete p->key; - } - val = p->val.p; - delete p; - --len; - return val; -} - -int GHash::removeInt(const char *key) { - GHashBucket *p; - GHashBucket **q; - int val; - int h; - - if (!(p = find(key, &h))) { - return 0; - } - q = &tab[h]; - while (*q != p) { - q = &((*q)->next); - } - *q = p->next; - if (deleteKeys) { - delete p->key; - } - val = p->val.i; - delete p; - --len; - return val; -} - -void GHash::startIter(GHashIter **iter) { - *iter = new GHashIter; - (*iter)->h = -1; - (*iter)->p = NULL; -} - -GBool GHash::getNext(GHashIter **iter, GString **key, void **val) { - if (!*iter) { - return gFalse; - } - if ((*iter)->p) { - (*iter)->p = (*iter)->p->next; - } - while (!(*iter)->p) { - if (++(*iter)->h == size) { - delete *iter; - *iter = NULL; - return gFalse; - } - (*iter)->p = tab[(*iter)->h]; - } - *key = (*iter)->p->key; - *val = (*iter)->p->val.p; - return gTrue; -} - -GBool GHash::getNext(GHashIter **iter, GString **key, int *val) { - if (!*iter) { - return gFalse; - } - if ((*iter)->p) { - (*iter)->p = (*iter)->p->next; - } - while (!(*iter)->p) { - if (++(*iter)->h == size) { - delete *iter; - *iter = NULL; - return gFalse; - } - (*iter)->p = tab[(*iter)->h]; - } - *key = (*iter)->p->key; - *val = (*iter)->p->val.i; - return gTrue; -} - -void GHash::killIter(GHashIter **iter) { - delete *iter; - *iter = NULL; -} - -void GHash::expand() { - GHashBucket **oldTab; - GHashBucket *p; - int oldSize, h, i; - - oldSize = size; - oldTab = tab; - size = 2*size + 1; - tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); - for (h = 0; h < size; ++h) { - tab[h] = NULL; - } - for (i = 0; i < oldSize; ++i) { - while (oldTab[i]) { - p = oldTab[i]; - oldTab[i] = oldTab[i]->next; - h = hash(p->key); - p->next = tab[h]; - tab[h] = p; - } - } - gfree(oldTab); -} - -GHashBucket *GHash::find(GString *key, int *h) { - GHashBucket *p; - - *h = hash(key); - for (p = tab[*h]; p; p = p->next) { - if (!p->key->cmp(key)) { - return p; - } - } - return NULL; -} - -GHashBucket *GHash::find(const char *key, int *h) { - GHashBucket *p; - - *h = hash(key); - for (p = tab[*h]; p; p = p->next) { - if (!p->key->cmp(key)) { - return p; - } - } - return NULL; -} - -int GHash::hash(GString *key) { - char *p; - unsigned int h; - int i; - - h = 0; - for (p = key->getCString(), i = 0; i < key->getLength(); ++p, ++i) { - h = 17 * h + (int)(*p & 0xff); - } - return (int)(h % size); -} - -int GHash::hash(const char *key) { - const char *p; - unsigned int h; - - h = 0; - for (p = key; *p; ++p) { - h = 17 * h + (int)(*p & 0xff); - } - return (int)(h % size); -} diff --git a/xpdf/goo/GHash.h b/xpdf/goo/GHash.h deleted file mode 100644 index f64a13a51..000000000 --- a/xpdf/goo/GHash.h +++ /dev/null @@ -1,78 +0,0 @@ -//======================================================================== -// -// GHash.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef GHASH_H -#define GHASH_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -class GString; -struct GHashBucket; -struct GHashIter; - -//------------------------------------------------------------------------ - -class GHash { -public: - - GHash(GBool deleteKeysA = gFalse); - ~GHash(); - void add(GString *key, void *val); - void add(GString *key, int val); - void replace(GString *key, void *val); - void replace(GString *key, int val); - void *lookup(GString *key); - int lookupInt(GString *key); - void *lookup(char *key); - int lookupInt(const char *key); - void *remove(GString *key); - int removeInt(GString *key); - void *remove(char *key); - int removeInt(const char *key); - int getLength() { return len; } - void startIter(GHashIter **iter); - GBool getNext(GHashIter **iter, GString **key, void **val); - GBool getNext(GHashIter **iter, GString **key, int *val); - void killIter(GHashIter **iter); - -private: - - void expand(); - GHashBucket *find(GString *key, int *h); - GHashBucket *find(const char *key, int *h); - int hash(GString *key); - int hash(const char *key); - - GBool deleteKeys; // set if key strings should be deleted - int size; // number of buckets - int len; // number of entries - GHashBucket **tab; -}; - -#define deleteGHash(hash, T) \ - do { \ - GHash *_hash = (hash); \ - { \ - GHashIter *_iter; \ - GString *_key; \ - void *_p; \ - _hash->startIter(&_iter); \ - while (_hash->getNext(&_iter, &_key, &_p)) { \ - delete (T*)_p; \ - } \ - delete _hash; \ - } \ - } while(0) - -#endif diff --git a/xpdf/goo/GList.cc b/xpdf/goo/GList.cc deleted file mode 100644 index fb5fd6284..000000000 --- a/xpdf/goo/GList.cc +++ /dev/null @@ -1,97 +0,0 @@ -//======================================================================== -// -// GList.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "GList.h" - -//------------------------------------------------------------------------ -// GList -//------------------------------------------------------------------------ - -GList::GList() { - size = 8; - data = (void **)gmallocn(size, sizeof(void*)); - length = 0; - inc = 0; -} - -GList::GList(int sizeA) { - size = sizeA; - data = (void **)gmallocn(size, sizeof(void*)); - length = 0; - inc = 0; -} - -GList::~GList() { - gfree(data); -} - -void GList::append(void *p) { - if (length >= size) { - expand(); - } - data[length++] = p; -} - -void GList::append(GList *list) { - int i; - - while (length + list->length > size) { - expand(); - } - for (i = 0; i < list->length; ++i) { - data[length++] = list->data[i]; - } -} - -void GList::insert(int i, void *p) { - if (length >= size) { - expand(); - } - if (i < length) { - memmove(data+i+1, data+i, (length - i) * sizeof(void *)); - } - data[i] = p; - ++length; -} - -void *GList::del(int i) { - void *p; - - p = data[i]; - if (i < length - 1) { - memmove(data+i, data+i+1, (length - i - 1) * sizeof(void *)); - } - --length; - if (size - length >= ((inc > 0) ? inc : size/2)) { - shrink(); - } - return p; -} - -void GList::sort(int (*cmp)(const void *obj1, const void *obj2)) { - qsort(data, length, sizeof(void *), cmp); -} - -void GList::expand() { - size += (inc > 0) ? inc : size; - data = (void **)greallocn(data, size, sizeof(void*)); -} - -void GList::shrink() { - size -= (inc > 0) ? inc : size/2; - data = (void **)greallocn(data, size, sizeof(void*)); -} diff --git a/xpdf/goo/GList.h b/xpdf/goo/GList.h deleted file mode 100644 index e4d8ff8f1..000000000 --- a/xpdf/goo/GList.h +++ /dev/null @@ -1,96 +0,0 @@ -//======================================================================== -// -// GList.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef GLIST_H -#define GLIST_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -//------------------------------------------------------------------------ -// GList -//------------------------------------------------------------------------ - -class GList { -public: - - // Create an empty list. - GList(); - - // Create an empty list with space for elements. - GList(int sizeA); - - // Destructor - does not free pointed-to objects. - ~GList(); - - //----- general - - // Get the number of elements. - int getLength() { return length; } - - //----- ordered list support - - // Return the th element. - // Assumes 0 <= i < length. - void *get(int i) { return data[i]; } - - // Append an element to the end of the list. - void append(void *p); - - // Append another list to the end of this one. - void append(GList *list); - - // Insert an element at index . - // Assumes 0 <= i <= length. - void insert(int i, void *p); - - // Deletes and returns the element at index . - // Assumes 0 <= i < length. - void *del(int i); - - // Sort the list accoring to the given comparison function. - // NB: this sorts an array of pointers, so the pointer args need to - // be double-dereferenced. - void sort(int (*cmp)(const void *ptr1, const void *ptr2)); - - //----- control - - // Set allocation increment to . If inc > 0, that many - // elements will be allocated every time the list is expanded. - // If inc <= 0, the list will be doubled in size. - void setAllocIncr(int incA) { inc = incA; } - -private: - - void expand(); - void shrink(); - - void **data; // the list elements - int size; // size of data array - int length; // number of elements on list - int inc; // allocation increment -}; - -#define deleteGList(list, T) \ - do { \ - GList *_list = (list); \ - { \ - int _i; \ - for (_i = 0; _i < _list->getLength(); ++_i) { \ - delete (T*)_list->get(_i); \ - } \ - delete _list; \ - } \ - } while (0) - -#endif diff --git a/xpdf/goo/GMutex.h b/xpdf/goo/GMutex.h deleted file mode 100644 index 7fa93d85e..000000000 --- a/xpdf/goo/GMutex.h +++ /dev/null @@ -1,49 +0,0 @@ -//======================================================================== -// -// GMutex.h -// -// Portable mutex macros. -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef GMUTEX_H -#define GMUTEX_H - -// Usage: -// -// GMutex m; -// gInitMutex(&m); -// ... -// gLockMutex(&m); -// ... critical section ... -// gUnlockMutex(&m); -// ... -// gDestroyMutex(&m); - -#ifdef WIN32 - -#include - -typedef CRITICAL_SECTION GMutex; - -#define gInitMutex(m) InitializeCriticalSection(m) -#define gDestroyMutex(m) DeleteCriticalSection(m) -#define gLockMutex(m) EnterCriticalSection(m) -#define gUnlockMutex(m) LeaveCriticalSection(m) - -#else // assume pthreads - -#include - -typedef pthread_mutex_t GMutex; - -#define gInitMutex(m) pthread_mutex_init(m, NULL) -#define gDestroyMutex(m) pthread_mutex_destroy(m) -#define gLockMutex(m) pthread_mutex_lock(m) -#define gUnlockMutex(m) pthread_mutex_unlock(m) - -#endif - -#endif diff --git a/xpdf/goo/GString.cc b/xpdf/goo/GString.cc deleted file mode 100644 index 049dcf38d..000000000 --- a/xpdf/goo/GString.cc +++ /dev/null @@ -1,319 +0,0 @@ -//======================================================================== -// -// GString.cc -// -// Simple variable-length string type. -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include "gtypes.h" -#include "GString.h" - -static inline int size(int len) { - int delta; - - delta = len < 256 ? 7 : 255; - return ((len + 1) + delta) & ~delta; -} - -inline void GString::resize(int length1) { - char *s1; - - if (!s) { - s = new char[size(length1)]; - } else if (size(length1) != size(length)) { - s1 = new char[size(length1)]; - if (length1 < length) { - memcpy(s1, s, length1); - s1[length1] = '\0'; - } else { - memcpy(s1, s, length + 1); - } - delete[] s; - s = s1; - } -} - -GString::GString() { - s = NULL; - resize(length = 0); - s[0] = '\0'; -} - -GString::GString(const char *sA) { - int n = strlen(sA); - - s = NULL; - resize(length = n); - memcpy(s, sA, n + 1); -} - -GString::GString(const char *sA, int lengthA) { - s = NULL; - resize(length = lengthA); - memcpy(s, sA, length * sizeof(char)); - s[length] = '\0'; -} - -GString::GString(GString *str, int idx, int lengthA) { - s = NULL; - resize(length = lengthA); - memcpy(s, str->getCString() + idx, length); - s[length] = '\0'; -} - -GString::GString(GString *str) { - s = NULL; - resize(length = str->getLength()); - memcpy(s, str->getCString(), length + 1); -} - -GString::GString(GString *str1, GString *str2) { - int n1 = str1->getLength(); - int n2 = str2->getLength(); - - s = NULL; - resize(length = n1 + n2); - memcpy(s, str1->getCString(), n1); - memcpy(s + n1, str2->getCString(), n2 + 1); -} - -GString *GString::fromInt(int x) { - char buf[24]; // enough space for 64-bit ints plus a little extra - GBool neg; - Guint y; - int i; - - i = 24; - if (x == 0) { - buf[--i] = '0'; - } else { - if ((neg = x < 0)) { - y = (Guint)-x; - } else { - y = (Guint)x; - } - while (i > 0 && y > 0) { - buf[--i] = '0' + y % 10; - y /= 10; - } - if (neg && i > 0) { - buf[--i] = '-'; - } - } - return new GString(buf + i, 24 - i); -} - -GString::~GString() { - delete[] s; -} - -GString *GString::clear() { - s[length = 0] = '\0'; - resize(0); - return this; -} - -GString *GString::append(char c) { - resize(length + 1); - s[length++] = c; - s[length] = '\0'; - return this; -} - -GString *GString::append(GString *str) { - int n = str->getLength(); - - resize(length + n); - memcpy(s + length, str->getCString(), n + 1); - length += n; - return this; -} - -GString *GString::append(const char *str) { - int n = strlen(str); - - resize(length + n); - memcpy(s + length, str, n + 1); - length += n; - return this; -} - -GString *GString::append(const char *str, int lengthA) { - resize(length + lengthA); - memcpy(s + length, str, lengthA); - length += lengthA; - s[length] = '\0'; - return this; -} - -GString *GString::insert(int i, char c) { - int j; - - resize(length + 1); - for (j = length + 1; j > i; --j) - s[j] = s[j-1]; - s[i] = c; - ++length; - return this; -} - -GString *GString::insert(int i, GString *str) { - int n = str->getLength(); - int j; - - resize(length + n); - for (j = length; j >= i; --j) - s[j+n] = s[j]; - memcpy(s+i, str->getCString(), n); - length += n; - return this; -} - -GString *GString::insert(int i, const char *str) { - int n = strlen(str); - int j; - - resize(length + n); - for (j = length; j >= i; --j) - s[j+n] = s[j]; - memcpy(s+i, str, n); - length += n; - return this; -} - -GString *GString::insert(int i, const char *str, int lengthA) { - int j; - - resize(length + lengthA); - for (j = length; j >= i; --j) - s[j+lengthA] = s[j]; - memcpy(s+i, str, lengthA); - length += lengthA; - return this; -} - -GString *GString::del(int i, int n) { - int j; - - if (n > 0) { - if (i + n > length) { - n = length - i; - } - for (j = i; j <= length - n; ++j) { - s[j] = s[j + n]; - } - resize(length -= n); - } - return this; -} - -GString *GString::upperCase() { - int i; - - for (i = 0; i < length; ++i) { - if (islower(s[i])) - s[i] = toupper(s[i]); - } - return this; -} - -GString *GString::lowerCase() { - int i; - - for (i = 0; i < length; ++i) { - if (isupper(s[i])) - s[i] = tolower(s[i]); - } - return this; -} - -int GString::cmp(GString *str) { - int n1, n2, i, x; - char *p1, *p2; - - n1 = length; - n2 = str->length; - for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) { - x = *p1 - *p2; - if (x != 0) { - return x; - } - } - return n1 - n2; -} - -int GString::cmpN(GString *str, int n) { - int n1, n2, i, x; - char *p1, *p2; - - n1 = length; - n2 = str->length; - for (i = 0, p1 = s, p2 = str->s; - i < n1 && i < n2 && i < n; - ++i, ++p1, ++p2) { - x = *p1 - *p2; - if (x != 0) { - return x; - } - } - if (i == n) { - return 0; - } - return n1 - n2; -} - -int GString::cmp(const char *sA) { - int n1, i, x; - const char *p1, *p2; - - n1 = length; - for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) { - x = *p1 - *p2; - if (x != 0) { - return x; - } - } - if (i < n1) { - return 1; - } - if (*p2) { - return -1; - } - return 0; -} - -int GString::cmpN(const char *sA, int n) { - int n1, i, x; - const char *p1, *p2; - - n1 = length; - for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) { - x = *p1 - *p2; - if (x != 0) { - return x; - } - } - if (i == n) { - return 0; - } - if (i < n1) { - return 1; - } - if (*p2) { - return -1; - } - return 0; -} diff --git a/xpdf/goo/GString.h b/xpdf/goo/GString.h deleted file mode 100644 index f4ff7c6a9..000000000 --- a/xpdf/goo/GString.h +++ /dev/null @@ -1,97 +0,0 @@ -//======================================================================== -// -// GString.h -// -// Simple variable-length string type. -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef GSTRING_H -#define GSTRING_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -class GString { -public: - - // Create an empty string. - GString(); - - // Create a string from a C string. - GString(const char *sA); - - // Create a string from chars at . This string - // can contain null characters. - GString(const char *sA, int lengthA); - - // Create a string from chars at in . - GString(GString *str, int idx, int lengthA); - - // Copy a string. - GString(GString *str); - GString *copy() { return new GString(this); } - - // Concatenate two strings. - GString(GString *str1, GString *str2); - - // Convert an integer to a string. - static GString *fromInt(int x); - - // Destructor. - ~GString(); - - // Get length. - int getLength() { return length; } - - // Get C string. - char *getCString() { return s; } - - // Get th character. - char getChar(int i) { return s[i]; } - - // Change th character. - void setChar(int i, char c) { s[i] = c; } - - // Clear string to zero length. - GString *clear(); - - // Append a character or string. - GString *append(char c); - GString *append(GString *str); - GString *append(const char *str); - GString *append(const char *str, int lengthA); - - // Insert a character or string. - GString *insert(int i, char c); - GString *insert(int i, GString *str); - GString *insert(int i, const char *str); - GString *insert(int i, const char *str, int lengthA); - - // Delete a character or range of characters. - GString *del(int i, int n = 1); - - // Convert string to all-upper/all-lower case. - GString *upperCase(); - GString *lowerCase(); - - // Compare two strings: -1:< 0:= +1:> - int cmp(GString *str); - int cmpN(GString *str, int n); - int cmp(const char *sA); - int cmpN(const char *sA, int n); - -private: - - int length; - char *s; - - void resize(int length1); -}; - -#endif diff --git a/xpdf/goo/Makefile.am b/xpdf/goo/Makefile.am deleted file mode 100644 index 81349957a..000000000 --- a/xpdf/goo/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -INCLUDES = -I$(srcdir)/.. - -libgoo_la_SOURCES = GHash.cc GList.cc GString.cc gfile.cc gmem.c gmempp.cc - -noinst_LTLIBRARIES = libgoo.la diff --git a/xpdf/goo/gfile.cc b/xpdf/goo/gfile.cc deleted file mode 100644 index 470b2bf90..000000000 --- a/xpdf/goo/gfile.cc +++ /dev/null @@ -1,705 +0,0 @@ -//======================================================================== -// -// gfile.cc -// -// Miscellaneous file and directory name manipulation. -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifndef WIN32 -# if defined(MACOS) -# include -# elif !defined(ACORN) -# include -# include -# include -# endif -# include -# include -# if !defined(VMS) && !defined(ACORN) && !defined(MACOS) -# include -# endif -# if defined(VMS) && (__DECCXX_VER < 50200000) -# include -# endif -#endif // WIN32 -#include "GString.h" -#include "gfile.h" - -// Some systems don't define this, so just make it something reasonably -// large. -#ifndef PATH_MAX -#define PATH_MAX 1024 -#endif - -//------------------------------------------------------------------------ - -GString *getHomeDir() { -#ifdef VMS - //---------- VMS ---------- - return new GString("SYS$LOGIN:"); - -#elif defined(__EMX__) || defined(WIN32) - //---------- OS/2+EMX and Win32 ---------- - char *s; - GString *ret; - - if ((s = getenv("HOME"))) - ret = new GString(s); - else - ret = new GString("."); - return ret; - -#elif defined(ACORN) - //---------- RISCOS ---------- - return new GString("@"); - -#elif defined(MACOS) - //---------- MacOS ---------- - return new GString(":"); - -#else - //---------- Unix ---------- - char *s; - struct passwd *pw; - GString *ret; - - if ((s = getenv("HOME"))) { - ret = new GString(s); - } else { - if ((s = getenv("USER"))) - pw = getpwnam(s); - else - pw = getpwuid(getuid()); - if (pw) - ret = new GString(pw->pw_dir); - else - ret = new GString("."); - } - return ret; -#endif -} - -GString *getCurrentDir() { - char buf[PATH_MAX+1]; - -#if defined(__EMX__) - if (_getcwd2(buf, sizeof(buf))) -#elif defined(WIN32) - if (GetCurrentDirectory(sizeof(buf), buf)) -#elif defined(ACORN) - if (strcpy(buf, "@")) -#elif defined(MACOS) - if (strcpy(buf, ":")) -#else - if (getcwd(buf, sizeof(buf))) -#endif - return new GString(buf); - return new GString(); -} - -GString *appendToPath(GString *path, const char *fileName) { -#if defined(VMS) - //---------- VMS ---------- - //~ this should handle everything necessary for file - //~ requesters, but it's certainly not complete - char *p0, *p1, *p2; - char *q1; - - p0 = path->getCString(); - p1 = p0 + path->getLength() - 1; - if (!strcmp(fileName, "-")) { - if (*p1 == ']') { - for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ; - if (*p2 == '[') - ++p2; - path->del(p2 - p0, p1 - p2); - } else if (*p1 == ':') { - path->append("[-]"); - } else { - path->clear(); - path->append("[-]"); - } - } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) { - if (*p1 == ']') { - path->insert(p1 - p0, '.'); - path->insert(p1 - p0 + 1, fileName, q1 - fileName); - } else if (*p1 == ':') { - path->append('['); - path->append(']'); - path->append(fileName, q1 - fileName); - } else { - path->clear(); - path->append(fileName, q1 - fileName); - } - } else { - if (*p1 != ']' && *p1 != ':') - path->clear(); - path->append(fileName); - } - return path; - -#elif defined(WIN32) - //---------- Win32 ---------- - GString *tmp; - char buf[256]; - char *fp; - - tmp = new GString(path); - tmp->append('/'); - tmp->append(fileName); - GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp); - delete tmp; - path->clear(); - path->append(buf); - return path; - -#elif defined(ACORN) - //---------- RISCOS ---------- - char *p; - int i; - - path->append("."); - i = path->getLength(); - path->append(fileName); - for (p = path->getCString() + i; *p; ++p) { - if (*p == '/') { - *p = '.'; - } else if (*p == '.') { - *p = '/'; - } - } - return path; - -#elif defined(MACOS) - //---------- MacOS ---------- - char *p; - int i; - - path->append(":"); - i = path->getLength(); - path->append(fileName); - for (p = path->getCString() + i; *p; ++p) { - if (*p == '/') { - *p = ':'; - } else if (*p == '.') { - *p = ':'; - } - } - return path; - -#elif defined(__EMX__) - //---------- OS/2+EMX ---------- - int i; - - // appending "." does nothing - if (!strcmp(fileName, ".")) - return path; - - // appending ".." goes up one directory - if (!strcmp(fileName, "..")) { - for (i = path->getLength() - 2; i >= 0; --i) { - if (path->getChar(i) == '/' || path->getChar(i) == '\\' || - path->getChar(i) == ':') - break; - } - if (i <= 0) { - if (path->getChar(0) == '/' || path->getChar(0) == '\\') { - path->del(1, path->getLength() - 1); - } else if (path->getLength() >= 2 && path->getChar(1) == ':') { - path->del(2, path->getLength() - 2); - } else { - path->clear(); - path->append(".."); - } - } else { - if (path->getChar(i-1) == ':') - ++i; - path->del(i, path->getLength() - i); - } - return path; - } - - // otherwise, append "/" and new path component - if (path->getLength() > 0 && - path->getChar(path->getLength() - 1) != '/' && - path->getChar(path->getLength() - 1) != '\\') - path->append('/'); - path->append(fileName); - return path; - -#else - //---------- Unix ---------- - int i; - - // appending "." does nothing - if (!strcmp(fileName, ".")) - return path; - - // appending ".." goes up one directory - if (!strcmp(fileName, "..")) { - for (i = path->getLength() - 2; i >= 0; --i) { - if (path->getChar(i) == '/') - break; - } - if (i <= 0) { - if (path->getChar(0) == '/') { - path->del(1, path->getLength() - 1); - } else { - path->clear(); - path->append(".."); - } - } else { - path->del(i, path->getLength() - i); - } - return path; - } - - // otherwise, append "/" and new path component - if (path->getLength() > 0 && - path->getChar(path->getLength() - 1) != '/') - path->append('/'); - path->append(fileName); - return path; -#endif -} - -GString *grabPath(char *fileName) { -#ifdef VMS - //---------- VMS ---------- - char *p; - - if ((p = strrchr(fileName, ']'))) - return new GString(fileName, p + 1 - fileName); - if ((p = strrchr(fileName, ':'))) - return new GString(fileName, p + 1 - fileName); - return new GString(); - -#elif defined(__EMX__) || defined(WIN32) - //---------- OS/2+EMX and Win32 ---------- - char *p; - - if ((p = strrchr(fileName, '/'))) - return new GString(fileName, p - fileName); - if ((p = strrchr(fileName, '\\'))) - return new GString(fileName, p - fileName); - if ((p = strrchr(fileName, ':'))) - return new GString(fileName, p + 1 - fileName); - return new GString(); - -#elif defined(ACORN) - //---------- RISCOS ---------- - char *p; - - if ((p = strrchr(fileName, '.'))) - return new GString(fileName, p - fileName); - return new GString(); - -#elif defined(MACOS) - //---------- MacOS ---------- - char *p; - - if ((p = strrchr(fileName, ':'))) - return new GString(fileName, p - fileName); - return new GString(); - -#else - //---------- Unix ---------- - char *p; - - if ((p = strrchr(fileName, '/'))) - return new GString(fileName, p - fileName); - return new GString(); -#endif -} - -GBool isAbsolutePath(char *path) { -#ifdef VMS - //---------- VMS ---------- - return strchr(path, ':') || - (path[0] == '[' && path[1] != '.' && path[1] != '-'); - -#elif defined(__EMX__) || defined(WIN32) - //---------- OS/2+EMX and Win32 ---------- - return path[0] == '/' || path[0] == '\\' || path[1] == ':'; - -#elif defined(ACORN) - //---------- RISCOS ---------- - return path[0] == '$'; - -#elif defined(MACOS) - //---------- MacOS ---------- - return path[0] != ':'; - -#else - //---------- Unix ---------- - return path[0] == '/'; -#endif -} - -GString *makePathAbsolute(GString *path) { -#ifdef VMS - //---------- VMS ---------- - char buf[PATH_MAX+1]; - - if (!isAbsolutePath(path->getCString())) { - if (getcwd(buf, sizeof(buf))) { - path->insert(0, buf); - } - } - return path; - -#elif defined(WIN32) - //---------- Win32 ---------- - char buf[_MAX_PATH]; - char *fp; - - buf[0] = '\0'; - if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) { - path->clear(); - return path; - } - path->clear(); - path->append(buf); - return path; - -#elif defined(ACORN) - //---------- RISCOS ---------- - path->insert(0, '@'); - return path; - -#elif defined(MACOS) - //---------- MacOS ---------- - path->del(0, 1); - return path; - -#else - //---------- Unix and OS/2+EMX ---------- - struct passwd *pw; - char buf[PATH_MAX+1]; - GString *s; - char *p1, *p2; - int n; - - if (path->getChar(0) == '~') { - if (path->getChar(1) == '/' || -#ifdef __EMX__ - path->getChar(1) == '\\' || -#endif - path->getLength() == 1) { - path->del(0, 1); - s = getHomeDir(); - path->insert(0, s); - delete s; - } else { - p1 = path->getCString() + 1; -#ifdef __EMX__ - for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ; -#else - for (p2 = p1; *p2 && *p2 != '/'; ++p2) ; -#endif - if ((n = p2 - p1) > PATH_MAX) - n = PATH_MAX; - strncpy(buf, p1, n); - buf[n] = '\0'; - if ((pw = getpwnam(buf))) { - path->del(0, p2 - p1 + 1); - path->insert(0, pw->pw_dir); - } - } - } else if (!isAbsolutePath(path->getCString())) { - if (getcwd(buf, sizeof(buf))) { -#ifndef __EMX__ - path->insert(0, '/'); -#endif - path->insert(0, buf); - } - } - return path; -#endif -} - -time_t getModTime(char *fileName) { -#ifdef WIN32 - //~ should implement this, but it's (currently) only used in xpdf - return 0; -#else - struct stat statBuf; - - if (stat(fileName, &statBuf)) { - return 0; - } - return statBuf.st_mtime; -#endif -} - -GBool openTempFile(GString **name, FILE **f, const char *mode, char *ext) { -#if defined(WIN32) - //---------- Win32 ---------- - char *s; - - if (!(s = _tempnam(getenv("TEMP"), NULL))) { - return gFalse; - } - *name = new GString(s); - free(s); - if (ext) { - (*name)->append(ext); - } - if (!(*f = fopen((*name)->getCString(), mode))) { - delete (*name); - return gFalse; - } - return gTrue; -#elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS) - //---------- non-Unix ---------- - char *s; - - // There is a security hole here: an attacker can create a symlink - // with this file name after the tmpnam call and before the fopen - // call. I will happily accept fixes to this function for non-Unix - // OSs. - if (!(s = tmpnam(NULL))) { - return gFalse; - } - *name = new GString(s); - if (ext) { - (*name)->append(ext); - } - if (!(*f = fopen((*name)->getCString(), mode))) { - delete (*name); - return gFalse; - } - return gTrue; -#else - //---------- Unix ---------- - char *s; - int fd; - - if (ext) { -#if HAVE_MKSTEMPS - if ((s = getenv("TMPDIR"))) { - *name = new GString(s); - } else { - *name = new GString("/tmp"); - } - (*name)->append("/XXXXXX")->append(ext); - fd = mkstemps((*name)->getCString(), strlen(ext)); -#else - if (!(s = tmpnam(NULL))) { - return gFalse; - } - *name = new GString(s); - (*name)->append(ext); - fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); -#endif - } else { -#if HAVE_MKSTEMP - if ((s = getenv("TMPDIR"))) { - *name = new GString(s); - } else { - *name = new GString("/tmp"); - } - (*name)->append("/XXXXXX"); - fd = mkstemp((*name)->getCString()); -#else // HAVE_MKSTEMP - if (!(s = tmpnam(NULL))) { - return gFalse; - } - *name = new GString(s); - fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); -#endif // HAVE_MKSTEMP - } - if (fd < 0 || !(*f = fdopen(fd, mode))) { - delete *name; - return gFalse; - } - return gTrue; -#endif -} - -GBool executeCommand(char *cmd) { -#ifdef VMS - return system(cmd) ? gTrue : gFalse; -#else - return system(cmd) ? gFalse : gTrue; -#endif -} - -char *getLine(char *buf, int size, FILE *f) { - int c, i; - - i = 0; - while (i < size - 1) { - if ((c = fgetc(f)) == EOF) { - break; - } - buf[i++] = (char)c; - if (c == '\x0a') { - break; - } - if (c == '\x0d') { - c = fgetc(f); - if (c == '\x0a' && i < size - 1) { - buf[i++] = (char)c; - } else if (c != EOF) { - ungetc(c, f); - } - break; - } - } - buf[i] = '\0'; - if (i == 0) { - return NULL; - } - return buf; -} - -//------------------------------------------------------------------------ -// GDir and GDirEntry -//------------------------------------------------------------------------ - -GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) { -#ifdef VMS - char *p; -#elif defined(WIN32) - int fa; - GString *s; -#elif defined(ACORN) -#else - struct stat st; - GString *s; -#endif - - name = new GString(nameA); - dir = gFalse; - if (doStat) { -#ifdef VMS - if (!strcmp(nameA, "-") || - ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5))) - dir = gTrue; -#elif defined(ACORN) -#else - s = new GString(dirPath); - appendToPath(s, nameA); -#ifdef WIN32 - fa = GetFileAttributes(s->getCString()); - dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY)); -#else - if (stat(s->getCString(), &st) == 0) - dir = S_ISDIR(st.st_mode); -#endif - delete s; -#endif - } -} - -GDirEntry::~GDirEntry() { - delete name; -} - -GDir::GDir(char *name, GBool doStatA) { - path = new GString(name); - doStat = doStatA; -#if defined(WIN32) - GString *tmp; - - tmp = path->copy(); - tmp->append("/*.*"); - hnd = FindFirstFile(tmp->getCString(), &ffd); - delete tmp; -#elif defined(ACORN) -#elif defined(MACOS) -#else - dir = opendir(name); -#ifdef VMS - needParent = strchr(name, '[') != NULL; -#endif -#endif -} - -GDir::~GDir() { - delete path; -#if defined(WIN32) - if (hnd) { - FindClose(hnd); - hnd = NULL; - } -#elif defined(ACORN) -#elif defined(MACOS) -#else - if (dir) - closedir(dir); -#endif -} - -GDirEntry *GDir::getNextEntry() { - GDirEntry *e; - -#if defined(WIN32) - if (hnd) { - e = new GDirEntry(path->getCString(), ffd.cFileName, doStat); - if (hnd && !FindNextFile(hnd, &ffd)) { - FindClose(hnd); - hnd = NULL; - } - } else { - e = NULL; - } -#elif defined(ACORN) -#elif defined(MACOS) -#elif defined(VMS) - struct dirent *ent; - e = NULL; - if (dir) { - if (needParent) { - e = new GDirEntry(path->getCString(), "-", doStat); - needParent = gFalse; - return e; - } - ent = readdir(dir); - if (ent) { - e = new GDirEntry(path->getCString(), ent->d_name, doStat); - } - } -#else - struct dirent *ent; - e = NULL; - if (dir) { - ent = readdir(dir); - if (ent && !strcmp(ent->d_name, ".")) { - ent = readdir(dir); - } - if (ent) { - e = new GDirEntry(path->getCString(), ent->d_name, doStat); - } - } -#endif - - return e; -} - -void GDir::rewind() { -#ifdef WIN32 - GString *tmp; - - if (hnd) - FindClose(hnd); - tmp = path->copy(); - tmp->append("/*.*"); - hnd = FindFirstFile(tmp->getCString(), &ffd); - delete tmp; -#elif defined(ACORN) -#elif defined(MACOS) -#else - if (dir) - rewinddir(dir); -#ifdef VMS - needParent = strchr(path->getCString(), '[') != NULL; -#endif -#endif -} diff --git a/xpdf/goo/gfile.h b/xpdf/goo/gfile.h deleted file mode 100644 index 2a8c4759d..000000000 --- a/xpdf/goo/gfile.h +++ /dev/null @@ -1,138 +0,0 @@ -//======================================================================== -// -// gfile.h -// -// Miscellaneous file and directory name manipulation. -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef GFILE_H -#define GFILE_H - -#include -#include -#include -#if defined(WIN32) -# include -# ifdef FPTEX -# include -# else -# include -# endif -#elif defined(ACORN) -#elif defined(MACOS) -# include -#else -# include -# include -# ifdef VMS -# include "vms_dirent.h" -# elif HAVE_DIRENT_H -# include -# define NAMLEN(d) strlen((d)->d_name) -# else -# define dirent direct -# define NAMLEN(d) (d)->d_namlen -# if HAVE_SYS_NDIR_H -# include -# endif -# if HAVE_SYS_DIR_H -# include -# endif -# if HAVE_NDIR_H -# include -# endif -# endif -#endif -#include "gtypes.h" - -class GString; - -//------------------------------------------------------------------------ - -// Get home directory path. -extern GString *getHomeDir(); - -// Get current directory. -extern GString *getCurrentDir(); - -// Append a file name to a path string. may be an empty -// string, denoting the current directory). Returns . -extern GString *appendToPath(GString *path, const char *fileName); - -// Grab the path from the front of the file name. If there is no -// directory component in , returns an empty string. -extern GString *grabPath(char *fileName); - -// Is this an absolute path or file name? -extern GBool isAbsolutePath(char *path); - -// Make this path absolute by prepending current directory (if path is -// relative) or prepending user's directory (if path starts with '~'). -extern GString *makePathAbsolute(GString *path); - -// Get the modification time for . Returns 0 if there is an -// error. -extern time_t getModTime(char *fileName); - -// Create a temporary file and open it for writing. If is not -// NULL, it will be used as the file name extension. Returns both the -// name and the file pointer. For security reasons, all writing -// should be done to the returned file pointer; the file may be -// reopened later for reading, but not for writing. The string -// should be "w" or "wb". Returns true on success. -extern GBool openTempFile(GString **name, FILE **f, const char *mode, char *ext); - -// Execute . Returns true on success. -extern GBool executeCommand(char *cmd); - -// Just like fgets, but handles Unix, Mac, and/or DOS end-of-line -// conventions. -extern char *getLine(char *buf, int size, FILE *f); - -//------------------------------------------------------------------------ -// GDir and GDirEntry -//------------------------------------------------------------------------ - -class GDirEntry { -public: - - GDirEntry(char *dirPath, char *nameA, GBool doStat); - ~GDirEntry(); - GString *getName() { return name; } - GBool isDir() { return dir; } - -private: - - GString *name; // dir/file name - GBool dir; // is it a directory? -}; - -class GDir { -public: - - GDir(char *name, GBool doStatA = gTrue); - ~GDir(); - GDirEntry *getNextEntry(); - void rewind(); - -private: - - GString *path; // directory path - GBool doStat; // call stat() for each entry? -#if defined(WIN32) - WIN32_FIND_DATA ffd; - HANDLE hnd; -#elif defined(ACORN) -#elif defined(MACOS) -#else - DIR *dir; // the DIR structure from opendir() -#ifdef VMS - GBool needParent; // need to return an entry for [-] -#endif -#endif -}; - -#endif diff --git a/xpdf/goo/gmem.c b/xpdf/goo/gmem.c deleted file mode 100644 index 1a9c4f008..000000000 --- a/xpdf/goo/gmem.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * gmem.c - * - * Memory routines with out-of-memory checking. - * - * Copyright 1996-2003 Glyph & Cog, LLC - */ - -#include -#include -#include -#include -#include -#include -#include "gmem.h" - -#ifdef DEBUG_MEM - -typedef struct _GMemHdr { - int size; - int index; - struct _GMemHdr *next; -} GMemHdr; - -#define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7) -#define gMemTrlSize (sizeof(long)) - -#if gmemTrlSize==8 -#define gMemDeadVal 0xdeadbeefdeadbeefUL -#else -#define gMemDeadVal 0xdeadbeefUL -#endif - -/* round data size so trailer will be aligned */ -#define gMemDataSize(size) \ - ((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize) - -#define gMemNLists 64 -#define gMemListShift 4 -#define gMemListMask (gMemNLists - 1) -static GMemHdr *gMemList[gMemNLists] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -static int gMemIndex = 0; -static int gMemAlloc = 0; -static int gMemInUse = 0; - -#endif /* DEBUG_MEM */ - -void *gmalloc(size_t size) { -#ifdef DEBUG_MEM - size_t size1; - char *mem; - GMemHdr *hdr; - void *data; - int lst; - unsigned long *trl, *p; - - if (size == 0) - return NULL; - size1 = gMemDataSize(size); - if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - hdr = (GMemHdr *)mem; - data = (void *)(mem + gMemHdrSize); - trl = (unsigned long *)(mem + gMemHdrSize + size1); - hdr->size = size; - hdr->index = gMemIndex++; - lst = ((int)hdr >> gMemListShift) & gMemListMask; - hdr->next = gMemList[lst]; - gMemList[lst] = hdr; - ++gMemAlloc; - gMemInUse += size; - for (p = (unsigned long *)data; p <= trl; ++p) - *p = gMemDeadVal; - return data; -#else - void *p; - - if (size == 0) - return NULL; - if (!(p = malloc(size))) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - return p; -#endif -} - -void *grealloc(void *p, size_t size) { -#ifdef DEBUG_MEM - GMemHdr *hdr; - void *q; - size_t oldSize; - - if (size == 0) { - if (p) - gfree(p); - return NULL; - } - if (p) { - hdr = (GMemHdr *)((char *)p - gMemHdrSize); - oldSize = hdr->size; - q = gmalloc(size); - memcpy(q, p, size < oldSize ? size : oldSize); - gfree(p); - } else { - q = gmalloc(size); - } - return q; -#else - void *q; - - if (size == 0) { - if (p) - free(p); - return NULL; - } - if (p) - q = realloc(p, size); - else - q = malloc(size); - if (!q) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - return q; -#endif -} - -void *gmallocn(int nObjs, int objSize) { - int n; - - n = nObjs * objSize; - if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { - fprintf(stderr, "Bogus memory allocation size\n"); - exit(1); - } - return gmalloc(n); -} - -void *greallocn(void *p, int nObjs, int objSize) { - int n; - - n = nObjs * objSize; - if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { - fprintf(stderr, "Bogus memory allocation size\n"); - exit(1); - } - return grealloc(p, n); -} - -void gfree(void *p) { -#ifdef DEBUG_MEM - size_t size; - GMemHdr *hdr; - GMemHdr *prevHdr, *q; - int lst; - unsigned long *trl, *clr; - - if (p) { - hdr = (GMemHdr *)((char *)p - gMemHdrSize); - lst = ((int)hdr >> gMemListShift) & gMemListMask; - for (prevHdr = NULL, q = gMemList[lst]; q; prevHdr = q, q = q->next) { - if (q == hdr) - break; - } - if (q) { - if (prevHdr) - prevHdr->next = hdr->next; - else - gMemList[lst] = hdr->next; - --gMemAlloc; - gMemInUse -= hdr->size; - size = gMemDataSize(hdr->size); - trl = (unsigned long *)((char *)hdr + gMemHdrSize + size); - if (*trl != gMemDeadVal) { - fprintf(stderr, "Overwrite past end of block %d at address %p\n", - hdr->index, p); - } - for (clr = (unsigned long *)hdr; clr <= trl; ++clr) - *clr = gMemDeadVal; - free(hdr); - } else { - fprintf(stderr, "Attempted to free bad address %p\n", p); - } - } -#else - if (p) - free(p); -#endif -} - -#ifdef DEBUG_MEM -void gMemReport(FILE *f) { - GMemHdr *p; - int lst; - - fprintf(f, "%d memory allocations in all\n", gMemIndex); - if (gMemAlloc > 0) { - fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc); - fprintf(f, " index size\n"); - fprintf(f, "-------- --------\n"); - for (lst = 0; lst < gMemNLists; ++lst) { - for (p = gMemList[lst]; p; p = p->next) - fprintf(f, "%8d %8d\n", p->index, p->size); - } - } else { - fprintf(f, "No memory blocks left allocated\n"); - } -} -#endif - -const char *copyString(const char *s) { - char *s1; - - s1 = (char *)gmalloc(strlen(s) + 1); - strcpy(s1, s); - return s1; -} diff --git a/xpdf/goo/gmem.h b/xpdf/goo/gmem.h deleted file mode 100644 index e853b4739..000000000 --- a/xpdf/goo/gmem.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * gmem.h - * - * Memory routines with out-of-memory checking. - * - * Copyright 1996-2003 Glyph & Cog, LLC - */ - -#ifndef GMEM_H -#define GMEM_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Same as malloc, but prints error message and exits if malloc() - * returns NULL. - */ -extern void *gmalloc(size_t size); - -/* - * Same as realloc, but prints error message and exits if realloc() - * returns NULL. If

is NULL, calls malloc instead of realloc(). - */ -extern void *grealloc(void *p, size_t size); - -/* - * These are similar to gmalloc and grealloc, but take an object count - * and size. The result is similar to allocating nObjs * objSize - * bytes, but there is an additional error check that the total size - * doesn't overflow an int. - */ -extern void *gmallocn(int nObjs, int objSize); -extern void *greallocn(void *p, int nObjs, int objSize); - -/* - * Same as free, but checks for and ignores NULL pointers. - */ -extern void gfree(void *p); - -#ifdef DEBUG_MEM -/* - * Report on unfreed memory. - */ -extern void gMemReport(FILE *f); -#else -#define gMemReport(f) -#endif - -/* - * Allocate memory and copy a string into it. - */ -extern const char *copyString(const char *s); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/xpdf/goo/gmempp.cc b/xpdf/goo/gmempp.cc deleted file mode 100644 index b1ee970d3..000000000 --- a/xpdf/goo/gmempp.cc +++ /dev/null @@ -1,32 +0,0 @@ -//======================================================================== -// -// gmempp.cc -// -// Use gmalloc/gfree for C++ new/delete operators. -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include -#include "gmem.h" - -#ifdef DEBUG_MEM - -void *operator new(size_t size) { - return gmalloc((int)size); -} - -void *operator new[](size_t size) { - return gmalloc((int)size); -} - -void operator delete(void *p) { - gfree(p); -} - -void operator delete[](void *p) { - gfree(p); -} - -#endif diff --git a/xpdf/goo/gtypes.h b/xpdf/goo/gtypes.h deleted file mode 100644 index 9f64f57d4..000000000 --- a/xpdf/goo/gtypes.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * gtypes.h - * - * Some useful simple types. - * - * Copyright 1996-2003 Glyph & Cog, LLC - */ - -#ifndef GTYPES_H -#define GTYPES_H - -/* - * These have stupid names to avoid conflicts with some (but not all) - * C++ compilers which define them. - */ -typedef int GBool; -#define gTrue 1 -#define gFalse 0 - -/* - * These have stupid names to avoid conflicts with , - * which on various systems defines some random subset of these. - */ -typedef unsigned char Guchar; -typedef unsigned short Gushort; -typedef unsigned int Guint; -typedef unsigned long Gulong; - -#endif diff --git a/xpdf/splash/Makefile.am b/xpdf/splash/Makefile.am deleted file mode 100644 index 34d41419d..000000000 --- a/xpdf/splash/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../fofi -I$(srcdir)/../goo $(LIBFREETYPE_CFLAGS) $(USER_INCLUDES) - -libsplash_la_SOURCES = Splash.cc SplashBitmap.cc SplashClip.cc SplashFTFont.cc SplashFTFontEngine.cc \ - SplashFTFontFile.cc SplashFont.cc SplashFontEngine.cc SplashFontFile.cc SplashFontFileID.cc \ - SplashPath.cc SplashPattern.cc SplashScreen.cc SplashState.cc SplashT1Font.cc \ - SplashT1FontEngine.cc SplashT1FontFile.cc SplashXPath.cc SplashXPathScanner.cc - -noinst_LTLIBRARIES = libsplash.la diff --git a/xpdf/splash/Splash.cc b/xpdf/splash/Splash.cc deleted file mode 100644 index a1a609477..000000000 --- a/xpdf/splash/Splash.cc +++ /dev/null @@ -1,3191 +0,0 @@ -//======================================================================== -// -// Splash.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "SplashErrorCodes.h" -#include "SplashMath.h" -#include "SplashBitmap.h" -#include "SplashState.h" -#include "SplashPath.h" -#include "SplashXPath.h" -#include "SplashXPathScanner.h" -#include "SplashPattern.h" -#include "SplashScreen.h" -#include "SplashFont.h" -#include "SplashGlyphBitmap.h" -#include "Splash.h" - -//------------------------------------------------------------------------ - -static void blendNormal(SplashColorPtr src, SplashColorPtr /*dest*/, - SplashColorPtr blend, SplashColorMode cm) { - int i; - - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = src[i]; - } -} - -//------------------------------------------------------------------------ -// Splash -//------------------------------------------------------------------------ - -Splash::Splash(SplashBitmap *bitmapA) { - bitmap = bitmapA; - state = new SplashState(bitmap->width, bitmap->height); - softMask = NULL; - clearModRegion(); - debugMode = gFalse; -} - -Splash::~Splash() { - while (state->next) { - restoreState(); - } - delete state; - if (softMask) { - delete softMask; - } -} - -//------------------------------------------------------------------------ -// state read -//------------------------------------------------------------------------ - -SplashPattern *Splash::getStrokePattern() { - return state->strokePattern; -} - -SplashPattern *Splash::getFillPattern() { - return state->fillPattern; -} - -SplashScreen *Splash::getScreen() { - return state->screen; -} - -SplashBlendFunc Splash::getBlendFunc() { - return state->blendFunc; -} - -SplashCoord Splash::getStrokeAlpha() { - return state->strokeAlpha; -} - -SplashCoord Splash::getFillAlpha() { - return state->fillAlpha; -} - -SplashCoord Splash::getLineWidth() { - return state->lineWidth; -} - -int Splash::getLineCap() { - return state->lineCap; -} - -int Splash::getLineJoin() { - return state->lineJoin; -} - -SplashCoord Splash::getMiterLimit() { - return state->miterLimit; -} - -SplashCoord Splash::getFlatness() { - return state->flatness; -} - -SplashCoord *Splash::getLineDash() { - return state->lineDash; -} - -int Splash::getLineDashLength() { - return state->lineDashLength; -} - -SplashCoord Splash::getLineDashPhase() { - return state->lineDashPhase; -} - -SplashClip *Splash::getClip() { - return state->clip; -} - -//------------------------------------------------------------------------ -// state write -//------------------------------------------------------------------------ - -void Splash::setStrokePattern(SplashPattern *strokePattern) { - state->setStrokePattern(strokePattern); -} - -void Splash::setFillPattern(SplashPattern *fillPattern) { - state->setFillPattern(fillPattern); -} - -void Splash::setScreen(SplashScreen *screen) { - state->setScreen(screen); -} - -void Splash::setBlendFunc(SplashBlendFunc func) { - state->blendFunc = func; -} - -void Splash::setStrokeAlpha(SplashCoord alpha) { - state->strokeAlpha = alpha; -} - -void Splash::setFillAlpha(SplashCoord alpha) { - state->fillAlpha = alpha; -} - -void Splash::setLineWidth(SplashCoord lineWidth) { - state->lineWidth = lineWidth; -} - -void Splash::setLineCap(int lineCap) { - state->lineCap = lineCap; -} - -void Splash::setLineJoin(int lineJoin) { - state->lineJoin = lineJoin; -} - -void Splash::setMiterLimit(SplashCoord miterLimit) { - state->miterLimit = miterLimit; -} - -void Splash::setFlatness(SplashCoord flatness) { - if (flatness < 1) { - state->flatness = 1; - } else { - state->flatness = flatness; - } -} - -void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength, - SplashCoord lineDashPhase) { - state->setLineDash(lineDash, lineDashLength, lineDashPhase); -} - -void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1) { - state->clip->resetToRect(x0, y0, x1, y1); -} - -SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1) { - return state->clip->clipToRect(x0, y0, x1, y1); -} - -SplashError Splash::clipToPath(SplashPath *path, GBool eo) { - return state->clip->clipToPath(path, state->flatness, eo); -} - -//------------------------------------------------------------------------ -// state save/restore -//------------------------------------------------------------------------ - -void Splash::saveState() { - SplashState *newState; - - newState = state->copy(); - newState->next = state; - state = newState; -} - -SplashError Splash::restoreState() { - SplashState *oldState; - - if (!state->next) { - return splashErrNoSave; - } - oldState = state; - state = state->next; - delete oldState; - return splashOk; -} - -//------------------------------------------------------------------------ -// soft mask -//------------------------------------------------------------------------ - -void Splash::setSoftMask(SplashBitmap *softMaskA) { - if (softMask) { - delete softMask; - } - softMask = softMaskA; -} - -//------------------------------------------------------------------------ -// modified region -//------------------------------------------------------------------------ - -void Splash::clearModRegion() { - modXMin = bitmap->getWidth(); - modYMin = bitmap->getHeight(); - modXMax = -1; - modYMax = -1; -} - -inline void Splash::updateModX(int x) { - if (x < modXMin) { - modXMin = x; - } - if (x > modXMax) { - modXMax = x; - } -} - -inline void Splash::updateModY(int y) { - if (y < modYMin) { - modYMin = y; - } - if (y > modYMax) { - modYMax = y; - } -} - -//------------------------------------------------------------------------ -// drawing operations -//------------------------------------------------------------------------ - -void Splash::clear(SplashColorPtr color) { - SplashColorPtr row, p; - Guchar mono; - int x, y; - - switch (bitmap->mode) { - case splashModeMono1: - mono = color[0] ? 0xff : 0x00; - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - mono, -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, mono, bitmap->rowSize * bitmap->height); - } - break; - case splashModeMono8: - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - color[0], -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); - } - break; - case splashModeAMono8: - if (color[0] == color[1]) { - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - color[0], -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); - } - } else { - row = bitmap->data; - for (y = 0; y < bitmap->height; ++y) { - p = row; - for (x = 0; x < bitmap->width; ++x) { - *p++ = color[0]; - *p++ = color[1]; - } - row += bitmap->rowSize; - } - } - break; - case splashModeRGB8: - case splashModeBGR8: - if (color[0] == color[1] && color[1] == color[2]) { - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - color[0], -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); - } - } else { - row = bitmap->data; - for (y = 0; y < bitmap->height; ++y) { - p = row; - for (x = 0; x < bitmap->width; ++x) { - *p++ = color[0]; - *p++ = color[1]; - *p++ = color[2]; - } - row += bitmap->rowSize; - } - } - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) { - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - color[0], -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); - } - } else { - row = bitmap->data; - for (y = 0; y < bitmap->height; ++y) { - p = row; - for (x = 0; x < bitmap->width; ++x) { - *p++ = color[0]; - *p++ = color[1]; - *p++ = color[2]; - *p++ = color[3]; - } - row += bitmap->rowSize; - } - } - break; -#if SPLASH_CMYK - case splashModeACMYK8: - if (color[0] == color[1] && color[1] == color[2] && - color[2] == color[3] && color[3] == color[4]) { - if (bitmap->rowSize < 0) { - memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), - color[0], -bitmap->rowSize * bitmap->height); - } else { - memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); - } - } else { - row = bitmap->data; - for (y = 0; y < bitmap->height; ++y) { - p = row; - for (x = 0; x < bitmap->width; ++x) { - *p++ = color[0]; - *p++ = color[1]; - *p++ = color[2]; - *p++ = color[3]; - *p++ = color[4]; - } - row += bitmap->rowSize; - } - } - break; -#endif - } - - updateModX(0); - updateModY(0); - updateModX(bitmap->width - 1); - updateModY(bitmap->height - 1); -} - -SplashError Splash::stroke(SplashPath *path) { - SplashXPath *xPath, *xPath2; - - if (debugMode) { - printf("stroke [dash:%d] [width:%.2f]:\n", - state->lineDashLength, (double)state->lineWidth); - dumpPath(path); - } - opClipRes = splashClipAllOutside; - if (path->length == 0) { - return splashErrEmptyPath; - } - xPath = new SplashXPath(path, state->flatness, gFalse); - if (xPath->length == 0) { - delete xPath; - return splashErrEmptyPath; - } - if (state->lineDashLength > 0) { - xPath2 = makeDashedPath(xPath); - delete xPath; - xPath = xPath2; - } - if (state->lineWidth <= 1) { - strokeNarrow(xPath); - } else { - strokeWide(xPath); - } - delete xPath; - return splashOk; -} - -void Splash::strokeNarrow(SplashXPath *xPath) { - SplashXPathSeg *seg; - int x0, x1, x2, x3, y0, y1, x, y, t; - SplashCoord dx, dy, dxdy; - SplashClipResult clipRes; - int nClipRes[3]; - int i; - - for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { - - x0 = splashFloor(seg->x0); - x1 = splashFloor(seg->x1); - y0 = splashFloor(seg->y0); - y1 = splashFloor(seg->y1); - - // horizontal segment - if (y0 == y1) { - if (x0 > x1) { - t = x0; x0 = x1; x1 = t; - } - if ((clipRes = state->clip->testSpan(x0, x1, y0)) - != splashClipAllOutside) { - drawSpan(x0, x1, y0, state->strokePattern, state->strokeAlpha, - clipRes == splashClipAllInside); - } - - // segment with |dx| > |dy| - } else if (splashAbs(seg->dxdy) > 1) { - dx = seg->x1 - seg->x0; - dy = seg->y1 - seg->y0; - dxdy = seg->dxdy; - if (y0 > y1) { - t = y0; y0 = y1; y1 = t; - t = x0; x0 = x1; x1 = t; - dx = -dx; - dy = -dy; - } - if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, - x0 <= x1 ? x1 : x0, y1)) - != splashClipAllOutside) { - if (dx > 0) { - x2 = x0; - x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy); - drawSpan(x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0, state->strokePattern, - state->strokeAlpha, clipRes == splashClipAllInside); - x2 = x3; - for (y = y0 + 1; y <= y1 - 1; ++y) { - x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy); - drawSpan(x2, x3 - 1, y, state->strokePattern, - state->strokeAlpha, clipRes == splashClipAllInside); - x2 = x3; - } - drawSpan(x2, x2 <= x1 ? x1 : x2, y1, state->strokePattern, - state->strokeAlpha, clipRes == splashClipAllInside); - } else { - x2 = x0; - x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy); - drawSpan((x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0, state->strokePattern, - state->strokeAlpha, clipRes == splashClipAllInside); - x2 = x3; - for (y = y0 + 1; y <= y1 - 1; ++y) { - x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy); - drawSpan(x3 + 1, x2, y, state->strokePattern, - state->strokeAlpha, clipRes == splashClipAllInside); - x2 = x3; - } - drawSpan(x1, (x1 <= x2) ? x2 : x1, y1, state->strokePattern, - state->strokeAlpha, clipRes == splashClipAllInside); - } - } - - // segment with |dy| > |dx| - } else { - dxdy = seg->dxdy; - if (y0 > y1) { - t = x0; x0 = x1; x1 = t; - t = y0; y0 = y1; y1 = t; - } - if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, - x0 <= x1 ? x1 : x0, y1)) - != splashClipAllOutside) { - drawPixel(x0, y0, state->strokePattern, state->strokeAlpha, - clipRes == splashClipAllInside); - for (y = y0 + 1; y <= y1 - 1; ++y) { - x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy); - drawPixel(x, y, state->strokePattern, state->strokeAlpha, - clipRes == splashClipAllInside); - } - drawPixel(x1, y1, state->strokePattern, state->strokeAlpha, - clipRes == splashClipAllInside); - } - } - ++nClipRes[clipRes]; - } - if (nClipRes[splashClipPartial] || - (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) { - opClipRes = splashClipPartial; - } else if (nClipRes[splashClipAllInside]) { - opClipRes = splashClipAllInside; - } else { - opClipRes = splashClipAllOutside; - } -} - -void Splash::strokeWide(SplashXPath *xPath) { - SplashXPathSeg *seg, *seg2; - SplashPath *widePath; - SplashCoord d, dx, dy, wdx, wdy, dxPrev, dyPrev, wdxPrev, wdyPrev; - SplashCoord dotprod, miter; - int i, j; - - dx = dy = wdx = wdy = 0; // make gcc happy - dxPrev = dyPrev = wdxPrev = wdyPrev = 0; // make gcc happy - - for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { - - // save the deltas for the previous segment; if this is the first - // segment on a subpath, compute the deltas for the last segment - // on the subpath (which may be used to draw a line join) - if (seg->flags & splashXPathFirst) { - for (j = i + 1, seg2 = &xPath->segs[j]; j < xPath->length; ++j, ++seg2) { - if (seg2->flags & splashXPathLast) { - d = splashDist(seg2->x0, seg2->y0, seg2->x1, seg2->y1); - if (d == 0) { - //~ not clear what the behavior should be for joins with d==0 - dxPrev = 0; - dyPrev = 1; - } else { - d = (SplashCoord)1 / d; - dxPrev = d * (seg2->x1 - seg2->x0); - dyPrev = d * (seg2->y1 - seg2->y0); - } - wdxPrev = (SplashCoord)0.5 * state->lineWidth * dxPrev; - wdyPrev = (SplashCoord)0.5 * state->lineWidth * dyPrev; - break; - } - } - } else { - dxPrev = dx; - dyPrev = dy; - wdxPrev = wdx; - wdyPrev = wdy; - } - - // compute deltas for this line segment - d = splashDist(seg->x0, seg->y0, seg->x1, seg->y1); - if (d == 0) { - // we need to draw end caps on zero-length lines - //~ not clear what the behavior should be for splashLineCapButt with d==0 - dx = 0; - dy = 1; - } else { - d = (SplashCoord)1 / d; - dx = d * (seg->x1 - seg->x0); - dy = d * (seg->y1 - seg->y0); - } - wdx = (SplashCoord)0.5 * state->lineWidth * dx; - wdy = (SplashCoord)0.5 * state->lineWidth * dy; - - // initialize the path (which will be filled) - widePath = new SplashPath(); - widePath->moveTo(seg->x0 - wdy, seg->y0 + wdx); - - // draw the start cap - if (seg->flags & splashXPathEnd0) { - switch (state->lineCap) { - case splashLineCapButt: - widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); - break; - case splashLineCapRound: - widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0); - break; - case splashLineCapProjecting: - widePath->lineTo(seg->x0 - wdx - wdy, seg->y0 + wdx - wdy); - widePath->lineTo(seg->x0 - wdx + wdy, seg->y0 - wdx - wdy); - widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); - break; - } - } else { - widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); - } - - // draw the left side of the segment - widePath->lineTo(seg->x1 + wdy, seg->y1 - wdx); - - // draw the end cap - if (seg->flags & splashXPathEnd1) { - switch (state->lineCap) { - case splashLineCapButt: - widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); - break; - case splashLineCapRound: - widePath->arcCWTo(seg->x1 - wdy, seg->y1 + wdx, seg->x1, seg->y1); - break; - case splashLineCapProjecting: - widePath->lineTo(seg->x1 + wdx + wdy, seg->y1 - wdx + wdy); - widePath->lineTo(seg->x1 + wdx - wdy, seg->y1 + wdx + wdy); - widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); - break; - } - } else { - widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); - } - - // draw the right side of the segment - widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); - - // fill the segment - fillWithPattern(widePath, gTrue, state->strokePattern, state->strokeAlpha); - delete widePath; - - // draw the line join - if (!(seg->flags & splashXPathEnd0)) { - widePath = NULL; - switch (state->lineJoin) { - case splashLineJoinMiter: - dotprod = -(dx * dxPrev + dy * dyPrev); - if (splashAbs(splashAbs(dotprod) - 1) > 0.01) { - widePath = new SplashPath(); - widePath->moveTo(seg->x0, seg->y0); - miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod); - if (splashSqrt(miter) <= state->miterLimit) { - miter = splashSqrt(miter - 1); - if (dy * dxPrev > dx * dyPrev) { - widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); - widePath->lineTo(seg->x0 + wdy - miter * wdx, - seg->y0 - wdx - miter * wdy); - widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); - } else { - widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); - widePath->lineTo(seg->x0 - wdy - miter * wdx, - seg->y0 + wdx - miter * wdy); - widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); - } - } else { - if (dy * dxPrev > dx * dyPrev) { - widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); - widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); - } else { - widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); - widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); - } - } - } - break; - case splashLineJoinRound: - widePath = new SplashPath(); - widePath->moveTo(seg->x0 + wdy, seg->y0 - wdx); - widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0); - break; - case splashLineJoinBevel: - widePath = new SplashPath(); - widePath->moveTo(seg->x0, seg->y0); - if (dy * dxPrev > dx * dyPrev) { - widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); - widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); - } else { - widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); - widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); - } - break; - } - if (widePath) { - fillWithPattern(widePath, gTrue, state->strokePattern, - state->strokeAlpha); - delete widePath; - } - } - } -} - -SplashXPath *Splash::makeDashedPath(SplashXPath *xPath) { - SplashXPath *dPath; - GBool lineDashStartOn, lineDashOn; - GBool atSegStart, atSegEnd, atDashStart, atDashEnd; - int lineDashStartIdx, lineDashIdx, subpathStart; - SplashCoord lineDashTotal, lineDashStartPhase, lineDashDist; - int segIdx; - SplashXPathSeg *seg; - SplashCoord sx0, sy0, sx1, sy1, ax0, ay0, ax1, ay1, dist; - int i; - - dPath = new SplashXPath(); - - lineDashTotal = 0; - for (i = 0; i < state->lineDashLength; ++i) { - lineDashTotal += state->lineDash[i]; - } - lineDashStartPhase = state->lineDashPhase; - i = splashFloor(lineDashStartPhase / lineDashTotal); - lineDashStartPhase -= (SplashCoord)i * lineDashTotal; - lineDashStartOn = gTrue; - lineDashStartIdx = 0; - while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { - lineDashStartOn = !lineDashStartOn; - lineDashStartPhase -= state->lineDash[lineDashStartIdx]; - ++lineDashStartIdx; - } - - segIdx = 0; - seg = xPath->segs; - sx0 = seg->x0; - sy0 = seg->y0; - sx1 = seg->x1; - sy1 = seg->y1; - dist = splashDist(sx0, sy0, sx1, sy1); - lineDashOn = lineDashStartOn; - lineDashIdx = lineDashStartIdx; - lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; - atSegStart = gTrue; - atDashStart = gTrue; - subpathStart = dPath->length; - - while (segIdx < xPath->length) { - - ax0 = sx0; - ay0 = sy0; - if (dist <= lineDashDist) { - ax1 = sx1; - ay1 = sy1; - lineDashDist -= dist; - dist = 0; - atSegEnd = gTrue; - atDashEnd = lineDashDist == 0 || (seg->flags & splashXPathLast); - } else { - ax1 = sx0 + (lineDashDist / dist) * (sx1 - sx0); - ay1 = sy0 + (lineDashDist / dist) * (sy1 - sy0); - sx0 = ax1; - sy0 = ay1; - dist -= lineDashDist; - lineDashDist = 0; - atSegEnd = gFalse; - atDashEnd = gTrue; - } - - if (lineDashOn) { - dPath->addSegment(ax0, ay0, ax1, ay1, - atDashStart, atDashEnd, - atDashStart, atDashEnd); - // end of closed subpath - if (atSegEnd && - (seg->flags & splashXPathLast) && - !(seg->flags & splashXPathEnd1)) { - dPath->segs[subpathStart].flags &= ~splashXPathEnd0; - dPath->segs[dPath->length - 1].flags &= ~splashXPathEnd1; - } - } - - if (atDashEnd) { - lineDashOn = !lineDashOn; - if (++lineDashIdx == state->lineDashLength) { - lineDashIdx = 0; - } - lineDashDist = state->lineDash[lineDashIdx]; - atDashStart = gTrue; - } else { - atDashStart = gFalse; - } - if (atSegEnd) { - if (++segIdx < xPath->length) { - ++seg; - sx0 = seg->x0; - sy0 = seg->y0; - sx1 = seg->x1; - sy1 = seg->y1; - dist = splashDist(sx0, sy0, sx1, sy1); - if (seg->flags & splashXPathFirst) { - lineDashOn = lineDashStartOn; - lineDashIdx = lineDashStartIdx; - lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; - atDashStart = gTrue; - subpathStart = dPath->length; - } - } - atSegStart = gTrue; - } else { - atSegStart = gFalse; - } - } - - return dPath; -} - -SplashError Splash::fill(SplashPath *path, GBool eo) { - if (debugMode) { - printf("fill [eo:%d]:\n", eo); - dumpPath(path); - } - return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha); -} - -SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, - SplashPattern *pattern, - SplashCoord alpha) { - SplashXPath *xPath; - SplashXPathScanner *scanner; - int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; - SplashClipResult clipRes, clipRes2; - - if (path->length == 0) { - return splashErrEmptyPath; - } - xPath = new SplashXPath(path, state->flatness, gTrue); - xPath->sort(); - scanner = new SplashXPathScanner(xPath, eo); - - // get the min and max x and y values - scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); - - // check clipping - if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) - != splashClipAllOutside) { - - // limit the y range - if (yMinI < state->clip->getYMin()) { - yMinI = state->clip->getYMin(); - } - if (yMaxI > state->clip->getYMax()) { - yMaxI = state->clip->getYMax(); - } - - // draw the spans - for (y = yMinI; y <= yMaxI; ++y) { - while (scanner->getNextSpan(y, &x0, &x1)) { - if (clipRes == splashClipAllInside) { - drawSpan(x0, x1, y, pattern, alpha, gTrue); - } else { - // limit the x range - if (x0 < state->clip->getXMin()) { - x0 = state->clip->getXMin(); - } - if (x1 > state->clip->getXMax()) { - x1 = state->clip->getXMax(); - } - clipRes2 = state->clip->testSpan(x0, x1, y); - drawSpan(x0, x1, y, pattern, alpha, clipRes2 == splashClipAllInside); - } - } - } - } - opClipRes = clipRes; - - delete scanner; - delete xPath; - return splashOk; -} - -SplashError Splash::xorFill(SplashPath *path, GBool eo) { - SplashXPath *xPath; - SplashXPathScanner *scanner; - int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; - SplashClipResult clipRes, clipRes2; - - if (path->length == 0) { - return splashErrEmptyPath; - } - xPath = new SplashXPath(path, state->flatness, gTrue); - xPath->sort(); - scanner = new SplashXPathScanner(xPath, eo); - - // get the min and max x and y values - scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); - - // check clipping - if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) - != splashClipAllOutside) { - - // limit the y range - if (yMinI < state->clip->getYMin()) { - yMinI = state->clip->getYMin(); - } - if (yMaxI > state->clip->getYMax()) { - yMaxI = state->clip->getYMax(); - } - - // draw the spans - for (y = yMinI; y <= yMaxI; ++y) { - while (scanner->getNextSpan(y, &x0, &x1)) { - if (clipRes == splashClipAllInside) { - xorSpan(x0, x1, y, state->fillPattern, gTrue); - } else { - // limit the x range - if (x0 < state->clip->getXMin()) { - x0 = state->clip->getXMin(); - } - if (x1 > state->clip->getXMax()) { - x1 = state->clip->getXMax(); - } - clipRes2 = state->clip->testSpan(x0, x1, y); - xorSpan(x0, x1, y, state->fillPattern, - clipRes2 == splashClipAllInside); - } - } - } - } - opClipRes = clipRes; - - delete scanner; - delete xPath; - return splashOk; -} - -void Splash::drawPixel(int x, int y, SplashColorPtr color, - SplashCoord alpha, GBool noClip) { - SplashBlendFunc blendFunc; - SplashColorPtr p; - SplashColor dest, blend; - int alpha2, ialpha2; - Guchar t; - - if (noClip || state->clip->test(x, y)) { - if (alpha != 1 || softMask || state->blendFunc) { - blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; - if (softMask) { - alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]); - } else { - alpha2 = (int)(alpha * 255); - } - ialpha2 = 255 - alpha2; - switch (bitmap->mode) { - case splashModeMono1: - p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; - dest[0] = (*p >> (7 - (x & 7))) & 1; - (*blendFunc)(color, dest, blend, bitmap->mode); - t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; - if (t) { - *p |= 0x80 >> (x & 7); - } else { - *p &= ~(0x80 >> (x & 7)); - } - break; - case splashModeMono8: - p = &bitmap->data[y * bitmap->rowSize + x]; - (*blendFunc)(color, p, blend, bitmap->mode); - // note: floor(x / 255) = x >> 8 (for 16-bit x) - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - break; - case splashModeAMono8: - p = &bitmap->data[y * bitmap->rowSize + 2 * x]; - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - break; - case splashModeRGB8: - case splashModeBGR8: - p = &bitmap->data[y * bitmap->rowSize + 3 * x]; - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - p = &bitmap->data[y * bitmap->rowSize + 4 * x]; - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; - break; -#if SPLASH_CMYK - case splashModeACMYK8: - p = &bitmap->data[y * bitmap->rowSize + 5 * x]; - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; - p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; - break; -#endif - } - } else { - switch (bitmap->mode) { - case splashModeMono1: - p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; - if (color[0]) { - *p |= 0x80 >> (x & 7); - } else { - *p &= ~(0x80 >> (x & 7)); - } - break; - case splashModeMono8: - p = &bitmap->data[y * bitmap->rowSize + x]; - p[0] = color[0]; - break; - case splashModeAMono8: - p = &bitmap->data[y * bitmap->rowSize + 2 * x]; - p[0] = color[0]; - p[1] = color[1]; - break; - case splashModeRGB8: - case splashModeBGR8: - p = &bitmap->data[y * bitmap->rowSize + 3 * x]; - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - p = &bitmap->data[y * bitmap->rowSize + 4 * x]; - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - p[3] = color[3]; - break; -#if SPLASH_CMYK - case splashModeACMYK8: - p = &bitmap->data[y * bitmap->rowSize + 5 * x]; - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - p[3] = color[3]; - p[4] = color[4]; - break; -#endif - } - } - updateModX(x); - updateModY(y); - } -} - -void Splash::drawPixel(int x, int y, SplashPattern *pattern, - SplashCoord alpha, GBool noClip) { - SplashBlendFunc blendFunc; - SplashColor color; - SplashColorPtr p; - SplashColor dest, blend; - int alpha2, ialpha2; - Guchar t; - - if (noClip || state->clip->test(x, y)) { - if (alpha != 1 || softMask || state->blendFunc) { - blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; - pattern->getColor(x, y, color); - if (softMask) { - alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]); - } else { - alpha2 = (int)(alpha * 255); - } - ialpha2 = 255 - alpha2; - switch (bitmap->mode) { - case splashModeMono1: - p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; - dest[0] = (*p >> (7 - (x & 7))) & 1; - (*blendFunc)(color, dest, blend, bitmap->mode); - t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; - if (t) { - *p |= 0x80 >> (x & 7); - } else { - *p &= ~(0x80 >> (x & 7)); - } - break; - case splashModeMono8: - p = &bitmap->data[y * bitmap->rowSize + x]; - (*blendFunc)(color, p, blend, bitmap->mode); - // note: floor(x / 255) = x >> 8 (for 16-bit x) - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - break; - case splashModeAMono8: - p = &bitmap->data[y * bitmap->rowSize + 2 * x]; - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - break; - case splashModeRGB8: - case splashModeBGR8: - p = &bitmap->data[y * bitmap->rowSize + 3 * x]; - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - p = &bitmap->data[y * bitmap->rowSize + 4 * x]; - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; - break; -#if SPLASH_CMYK - case splashModeACMYK8: - p = &bitmap->data[y * bitmap->rowSize + 5 * x]; - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; - p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; - break; -#endif - } - } else { - pattern->getColor(x, y, color); - switch (bitmap->mode) { - case splashModeMono1: - p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; - if (color[0]) { - *p |= 0x80 >> (x & 7); - } else { - *p &= ~(0x80 >> (x & 7)); - } - break; - case splashModeMono8: - p = &bitmap->data[y * bitmap->rowSize + x]; - p[0] = color[0]; - break; - case splashModeAMono8: - p = &bitmap->data[y * bitmap->rowSize + 2 * x]; - p[0] = color[0]; - p[1] = color[1]; - break; - case splashModeRGB8: - case splashModeBGR8: - p = &bitmap->data[y * bitmap->rowSize + 3 * x]; - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - p = &bitmap->data[y * bitmap->rowSize + 4 * x]; - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - p[3] = color[3]; - break; -#if SPLASH_CMYK - case splashModeACMYK8: - p = &bitmap->data[y * bitmap->rowSize + 5 * x]; - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - p[3] = color[3]; - p[4] = color[4]; - break; -#endif - } - } - updateModX(x); - updateModY(y); - } -} - -void Splash::drawSpan(int x0, int x1, int y, SplashPattern *pattern, - SplashCoord alpha, GBool noClip) { - SplashBlendFunc blendFunc; - SplashColor color; - SplashColorPtr p; - SplashColor dest, blend; - Guchar mask, t; - int alpha2, ialpha2; - int i, j, n; - - n = x1 - x0 + 1; - - if (noClip) { - updateModX(x0); - updateModX(x1); - updateModY(y); - } - - if (alpha != 1 || softMask || state->blendFunc) { - blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; - if (softMask) { - alpha2 = ialpha2 = 0; // make gcc happy - } else { - alpha2 = (int)(alpha * 255); - ialpha2 = 255 - alpha2; - } - switch (bitmap->mode) { - case splashModeMono1: - p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; - i = 0; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - if ((j = x0 & 7)) { - mask = 0x80 >> j; - for (; j < 8 && i < n; ++i, ++j) { - if (noClip || state->clip->test(x0 + i, y)) { - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - dest[0] = (*p >> (7 - j)) & 1; - (*blendFunc)(color, dest, blend, bitmap->mode); - t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; - if (t) { - *p |= mask; - } else { - *p &= ~mask; - } - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - mask >>= 1; - } - ++p; - } - while (i < n) { - mask = 0x80; - for (j = 0; j < 8 && i < n; ++i, ++j) { - if (noClip || state->clip->test(x0 + i, y)) { - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - dest[0] = (*p >> (7 - j)) & 1; - (*blendFunc)(color, dest, blend, bitmap->mode); - t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; - if (t) { - *p |= mask; - } else { - *p &= ~mask; - } - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - mask >>= 1; - } - ++p; - } - } else { - if ((j = x0 & 7)) { - mask = 0x80 >> j; - for (; j < 8 && i < n; ++i, ++j) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - dest[0] = (*p >> (7 - j)) & 1; - (*blendFunc)(color, dest, blend, bitmap->mode); - t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; - if (t) { - *p |= mask; - } else { - *p &= ~mask; - } - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - mask >>= 1; - } - ++p; - } - while (i < n) { - mask = 0x80; - for (j = 0; j < 8 && i < n; ++i, ++j) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - dest[0] = (*p >> (7 - j)) & 1; - (*blendFunc)(color, dest, blend, bitmap->mode); - t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; - if (t) { - *p |= mask; - } else { - *p &= ~mask; - } - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - mask >>= 1; - } - ++p; - } - } - break; - - case splashModeMono8: - p = &bitmap->data[y * bitmap->rowSize + x0]; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - (*blendFunc)(color, p, blend, bitmap->mode); - *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - ++p; - } - } else { - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - (*blendFunc)(color, p, blend, bitmap->mode); - *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - ++p; - } - } - break; - - case splashModeAMono8: - p = &bitmap->data[y * bitmap->rowSize + 2 * x0]; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 2; - } - } else { - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 2; - } - } - break; - - case splashModeRGB8: - case splashModeBGR8: - p = &bitmap->data[y * bitmap->rowSize + 3 * x0]; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 3; - } - } else { - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 3; - } - } - break; - - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - p = &bitmap->data[y * bitmap->rowSize + 4 * x0]; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 4; - } - } else { - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 4; - } - } - break; -#if SPLASH_CMYK - case splashModeACMYK8: - p = &bitmap->data[y * bitmap->rowSize + 5 * x0]; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; - p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 4; - } - } else { - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (softMask) { - alpha2 = (int)(alpha * - softMask->data[y * softMask->rowSize + x0 + i]); - ialpha2 = 255 - alpha2; - } - (*blendFunc)(color, p, blend, bitmap->mode); - p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; - p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; - p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; - p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; - p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 4; - } - } - break; -#endif - } - - } else { - switch (bitmap->mode) { - case splashModeMono1: - p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; - i = 0; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - if ((j = x0 & 7)) { - mask = 0x80 >> j; - for (; j < 8 && i < n; ++i, ++j) { - if (noClip || state->clip->test(x0 + i, y)) { - if (color[0]) { - *p |= mask; - } else { - *p &= ~mask; - } - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - mask >>= 1; - } - ++p; - } - while (i < n) { - mask = 0x80; - for (j = 0; j < 8 && i < n; ++i, ++j) { - if (noClip || state->clip->test(x0 + i, y)) { - if (color[0]) { - *p |= mask; - } else { - *p &= ~mask; - } - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - mask >>= 1; - } - ++p; - } - } else { - if ((j = x0 & 7)) { - mask = 0x80 >> j; - for (; j < 8 && i < n; ++i, ++j) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (color[0]) { - *p |= mask; - } else { - *p &= ~mask; - } - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - mask >>= 1; - } - ++p; - } - while (i < n) { - mask = 0x80; - for (j = 0; j < 8 && i < n; ++i, ++j) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (color[0]) { - *p |= mask; - } else { - *p &= ~mask; - } - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - mask >>= 1; - } - ++p; - } - } - break; - - case splashModeMono8: - p = &bitmap->data[y * bitmap->rowSize + x0]; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - *p = color[0]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - ++p; - } - } else { - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - *p = color[0]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - ++p; - } - } - break; - - case splashModeAMono8: - p = &bitmap->data[y * bitmap->rowSize + 2 * x0]; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - p[0] = color[0]; - p[1] = color[1]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 2; - } - } else { - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - p[0] = color[0]; - p[1] = color[1]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 2; - } - } - break; - - case splashModeRGB8: - case splashModeBGR8: - p = &bitmap->data[y * bitmap->rowSize + 3 * x0]; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 3; - } - } else { - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 3; - } - } - break; - - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - p = &bitmap->data[y * bitmap->rowSize + 4 * x0]; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - p[3] = color[3]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 4; - } - } else { - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - p[3] = color[3]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 4; - } - } - break; -#if SPLASH_CMYK - case splashModeACMYK8: - p = &bitmap->data[y * bitmap->rowSize + 5 * x0]; - if (pattern->isStatic()) { - pattern->getColor(0, 0, color); - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - p[3] = color[3]; - p[4] = color[4]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 4; - } - } else { - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - p[0] = color[0]; - p[1] = color[1]; - p[2] = color[2]; - p[3] = color[3]; - p[4] = color[4]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 4; - } - } - break; -#endif - } - } -} - -void Splash::xorSpan(int x0, int x1, int y, SplashPattern *pattern, - GBool noClip) { - SplashColor color; - SplashColorPtr p; - Guchar mask; - int i, j, n; - - n = x1 - x0 + 1; - - if (noClip) { - updateModX(x0); - updateModX(x1); - updateModY(y); - } - - switch (bitmap->mode) { - case splashModeMono1: - p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; - i = 0; - if ((j = x0 & 7)) { - mask = 0x80 >> j; - for (; j < 8 && i < n; ++i, ++j) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (color[0]) { - *p ^= mask; - } - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - mask >>= 1; - } - ++p; - } - while (i < n) { - mask = 0x80; - for (j = 0; j < 8 && i < n; ++i, ++j) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - if (color[0]) { - *p ^= mask; - } - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - mask >>= 1; - } - ++p; - } - break; - - case splashModeMono8: - p = &bitmap->data[y * bitmap->rowSize + x0]; - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - *p ^= color[0]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - ++p; - } - break; - - case splashModeAMono8: - p = &bitmap->data[y * bitmap->rowSize + 2 * x0]; - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - p[0] ^= color[0]; - p[1] ^= color[1]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 2; - } - break; - - case splashModeRGB8: - case splashModeBGR8: - p = &bitmap->data[y * bitmap->rowSize + 3 * x0]; - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - p[0] ^= color[0]; - p[1] ^= color[1]; - p[2] ^= color[2]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 3; - } - break; - - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - p = &bitmap->data[y * bitmap->rowSize + 4 * x0]; - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - p[0] ^= color[0]; - p[1] ^= color[1]; - p[2] ^= color[2]; - p[3] ^= color[3]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 4; - } - break; -#if SPLASH_CMYK - case splashModeACMYK8: - p = &bitmap->data[y * bitmap->rowSize + 5 * x0]; - for (i = 0; i < n; ++i) { - if (noClip || state->clip->test(x0 + i, y)) { - pattern->getColor(x0 + i, y, color); - p[0] ^= color[0]; - p[1] ^= color[1]; - p[2] ^= color[2]; - p[3] ^= color[3]; - p[4] ^= color[4]; - if (!noClip) { - updateModX(x0 + i); - updateModY(y); - } - } - p += 4; - } - break; -#endif - } -} - -SplashError Splash::fillChar(SplashCoord x, SplashCoord y, - int c, SplashFont *font) { - SplashGlyphBitmap glyph; - int x0, y0, xFrac, yFrac; - SplashError err; - - if (debugMode) { - printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n", - (double)x, (double)y, c, c, c); - } - x0 = splashFloor(x); - xFrac = splashFloor((x - x0) * splashFontFraction); - y0 = splashFloor(y); - yFrac = splashFloor((y - y0) * splashFontFraction); - if (!font->getGlyph(c, xFrac, yFrac, &glyph)) { - return splashErrNoGlyph; - } - err = fillGlyph(x, y, &glyph); - if (glyph.freeData) { - gfree(glyph.data); - } - return err; -} - -SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y, - SplashGlyphBitmap *glyph) { - SplashBlendFunc blendFunc; - int alpha0, alpha, ialpha; - Guchar *p; - SplashColor fg, dest, blend; - SplashColorPtr pix; - SplashClipResult clipRes; - GBool noClip; - Guchar t; - int x0, y0, x1, y1, xx, xx1, yy; - - x0 = splashFloor(x); - y0 = splashFloor(y); - - if ((clipRes = state->clip->testRect(x0 - glyph->x, - y0 - glyph->y, - x0 - glyph->x + glyph->w - 1, - y0 - glyph->y + glyph->h - 1)) - != splashClipAllOutside) { - noClip = clipRes == splashClipAllInside; - - if (noClip) { - updateModX(x0 - glyph->x); - updateModX(x0 - glyph->x + glyph->w - 1); - updateModY(y0 - glyph->y); - updateModY(y0 - glyph->y + glyph->h - 1); - } - - //~ optimize this - if (state->fillAlpha != 1 || softMask || state->blendFunc) { - blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; - if (glyph->aa) { - p = glyph->data; - for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { - for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) { - alpha = *p++; - if (softMask) { - alpha = (int)(alpha * state->fillAlpha * - softMask->data[y1 * softMask->rowSize + x1]); - } else { - alpha = (int)(alpha * state->fillAlpha); - } - if (alpha > 0) { - if (noClip || state->clip->test(x1, y1)) { - ialpha = 255 - alpha; - state->fillPattern->getColor(x1, y1, fg); - switch (bitmap->mode) { - case splashModeMono1: - pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; - dest[0] = (*pix >> (7 - (x1 & 7))) & 1; - (*blendFunc)(fg, dest, blend, bitmap->mode); - t = (alpha * blend[0] + ialpha * dest[0]) >> 8; - if (t) { - *pix |= 0x80 >> (x1 & 7); - } else { - *pix &= ~(0x80 >> (x1 & 7)); - } - break; - case splashModeMono8: - pix = &bitmap->data[y1 * bitmap->rowSize + x1]; - (*blendFunc)(fg, pix, blend, bitmap->mode); - // note: floor(x / 255) = x >> 8 (for 16-bit x) - pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; - break; - case splashModeAMono8: - pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; - (*blendFunc)(fg, pix, blend, bitmap->mode); - pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; - break; - case splashModeRGB8: - case splashModeBGR8: - pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; - (*blendFunc)(fg, pix, blend, bitmap->mode); - pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; - pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; - (*blendFunc)(fg, pix, blend, bitmap->mode); - pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; - pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; - pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; - break; -#if SPLASH_CMYK - case splashModeACMYK8: - pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; - (*blendFunc)(fg, pix, blend, bitmap->mode); - pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; - pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; - pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; - pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8; - break; -#endif - } - if (!noClip) { - updateModX(x1); - updateModY(y1); - } - } - } - } - } - - } else { - p = glyph->data; - for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { - for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) { - alpha0 = *p++; - for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) { - if (alpha0 & 0x80) { - if (noClip || state->clip->test(x1, y1)) { - if (softMask) { - alpha = (int)(state->fillAlpha * - softMask->data[y1 * softMask->rowSize + x1]); - } else { - alpha = (int)(state->fillAlpha * 255); - } - ialpha = 255 - alpha; - state->fillPattern->getColor(x1, y1, fg); - switch (bitmap->mode) { - case splashModeMono1: - pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; - dest[0] = (*pix >> (7 - (x1 & 7))) & 1; - (*blendFunc)(fg, dest, blend, bitmap->mode); - t = (alpha * blend[0] + ialpha * dest[0]) >> 8; - if (t) { - *pix |= 0x80 >> (x1 & 7); - } else { - *pix &= ~(0x80 >> (x1 & 7)); - } - break; - case splashModeMono8: - pix = &bitmap->data[y1 * bitmap->rowSize + x1]; - (*blendFunc)(fg, pix, blend, bitmap->mode); - // note: floor(x / 255) = x >> 8 (for 16-bit x) - pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; - break; - case splashModeAMono8: - pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; - (*blendFunc)(fg, pix, blend, bitmap->mode); - pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; - break; - case splashModeRGB8: - case splashModeBGR8: - pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; - (*blendFunc)(fg, pix, blend, bitmap->mode); - pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; - pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; - (*blendFunc)(fg, pix, blend, bitmap->mode); - pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; - pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; - pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; - break; -#if SPLASH_CMYK - case splashModeACMYK8: - pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; - (*blendFunc)(fg, pix, blend, bitmap->mode); - pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; - pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; - pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; - pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8; - break; -#endif - } - if (!noClip) { - updateModX(x1); - updateModY(y1); - } - } - } - alpha0 <<= 1; - } - } - } - } - - } else { - if (glyph->aa) { - p = glyph->data; - for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { - for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) { - alpha = *p++; - if (alpha > 0) { - if (noClip || state->clip->test(x1, y1)) { - ialpha = 255 - alpha; - state->fillPattern->getColor(x1, y1, fg); - switch (bitmap->mode) { - case splashModeMono1: - if (alpha >= 0x80) { - pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; - if (fg[0]) { - *pix |= 0x80 >> (x1 & 7); - } else { - *pix &= ~(0x80 >> (x1 & 7)); - } - } - break; - case splashModeMono8: - pix = &bitmap->data[y1 * bitmap->rowSize + x1]; - // note: floor(x / 255) = x >> 8 (for 16-bit x) - pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; - break; - case splashModeAMono8: - pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; - pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; - break; - case splashModeRGB8: - case splashModeBGR8: - pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; - pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; - pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8; - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; - pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; - pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8; - pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8; - break; -#if SPLASH_CMYK - case splashModeACMYK8: - pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; - pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; - pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; - pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8; - pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8; - pix[4] = (alpha * fg[4] + ialpha * pix[4]) >> 8; - break; -#endif - } - if (!noClip) { - updateModX(x1); - updateModY(y1); - } - } - } - } - } - - } else { - p = glyph->data; - for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { - for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) { - alpha0 = *p++; - for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) { - if (alpha0 & 0x80) { - if (noClip || state->clip->test(x1, y1)) { - state->fillPattern->getColor(x1, y1, fg); - switch (bitmap->mode) { - case splashModeMono1: - pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; - if (fg[0]) { - *pix |= 0x80 >> (x1 & 7); - } else { - *pix &= ~(0x80 >> (x1 & 7)); - } - break; - case splashModeMono8: - pix = &bitmap->data[y1 * bitmap->rowSize + x1]; - pix[0] = fg[0]; - break; - case splashModeAMono8: - pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; - pix[0] = fg[0]; - pix[1] = fg[1]; - break; - case splashModeRGB8: - case splashModeBGR8: - pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; - pix[0] = fg[0]; - pix[1] = fg[1]; - pix[2] = fg[2]; - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; - pix[0] = fg[0]; - pix[1] = fg[1]; - pix[2] = fg[2]; - pix[3] = fg[3]; - break; -#if SPLASH_CMYK - case splashModeACMYK8: - pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; - pix[0] = fg[0]; - pix[1] = fg[1]; - pix[2] = fg[2]; - pix[3] = fg[3]; - pix[4] = fg[4]; - break; -#endif - } - if (!noClip) { - updateModX(x1); - updateModY(y1); - } - } - } - alpha0 <<= 1; - } - } - } - } - } - } - opClipRes = clipRes; - - return splashOk; -} - -SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, - int w, int h, SplashCoord *mat) { - GBool rot; - SplashCoord xScale, yScale, xShear, yShear, yShear1; - int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign; - int ulx, uly, llx, lly, urx, ury, lrx, lry; - int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; - int xMin, xMax, yMin, yMax; - SplashClipResult clipRes, clipRes2; - int yp, yq, yt, yStep, lastYStep; - int xp, xq, xt, xStep, xSrc; - int k1, spanXMin, spanXMax, spanY; - SplashColorPtr pixBuf, p; - int pixAcc; - SplashCoord alpha; - int x, y, x1, x2, y2; - SplashCoord y1; - int n, m, i, j; - - if (debugMode) { - printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", - w, h, (double)mat[0], (double)mat[1], (double)mat[2], - (double)mat[3], (double)mat[4], (double)mat[5]); - } - - // check for singular matrix - if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) { - return splashErrSingularMatrix; - } - - // compute scale, shear, rotation, translation parameters - rot = splashAbs(mat[1]) > splashAbs(mat[0]); - if (rot) { - xScale = -mat[1]; - yScale = mat[2] - (mat[0] * mat[3]) / mat[1]; - xShear = -mat[3] / yScale; - yShear = -mat[0] / mat[1]; - } else { - xScale = mat[0]; - yScale = mat[3] - (mat[1] * mat[2]) / mat[0]; - xShear = mat[2] / yScale; - yShear = mat[1] / mat[0]; - } - // the +/-0.01 in these computations is to avoid floating point - // precision problems which can lead to gaps between image stripes - // (it can cause image stripes to overlap, but that's a much less - // visible problem) - if (xScale >= 0) { - tx = splashRound(mat[4] - 0.01); - tx2 = splashRound(mat[4] + xScale + 0.01) - 1; - } else { - tx = splashRound(mat[4] + 0.01) - 1; - tx2 = splashRound(mat[4] + xScale - 0.01); - } - scaledWidth = abs(tx2 - tx) + 1; - if (scaledWidth == 0) { - // technically, this should draw nothing, but it generally seems - // better to draw a one-pixel-wide stripe rather than throwing it - // away - scaledWidth = 1; - } - if (yScale >= 0) { - ty = splashRound(mat[5] - 0.01); - ty2 = splashRound(mat[5] + yScale + 0.01) - 1; - } else { - ty = splashRound(mat[5] + 0.01) - 1; - ty2 = splashRound(mat[5] + yScale - 0.01); - } - scaledHeight = abs(ty2 - ty) + 1; - if (scaledHeight == 0) { - // technically, this should draw nothing, but it generally seems - // better to draw a one-pixel-wide stripe rather than throwing it - // away - scaledHeight = 1; - } - xSign = (xScale < 0) ? -1 : 1; - ySign = (yScale < 0) ? -1 : 1; - yShear1 = (SplashCoord)xSign * yShear; - - // clipping - ulx1 = 0; - uly1 = 0; - urx1 = xSign * (scaledWidth - 1); - ury1 = (int)(yShear * urx1); - llx1 = splashRound(xShear * ySign * (scaledHeight - 1)); - lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1); - lrx1 = xSign * (scaledWidth - 1) + - splashRound(xShear * ySign * (scaledHeight - 1)); - lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1); - if (rot) { - ulx = tx + uly1; uly = ty - ulx1; - urx = tx + ury1; ury = ty - urx1; - llx = tx + lly1; lly = ty - llx1; - lrx = tx + lry1; lry = ty - lrx1; - } else { - ulx = tx + ulx1; uly = ty + uly1; - urx = tx + urx1; ury = ty + ury1; - llx = tx + llx1; lly = ty + lly1; - lrx = tx + lrx1; lry = ty + lry1; - } - xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx - : (llx < lrx) ? llx : lrx - : (urx < llx) ? (urx < lrx) ? urx : lrx - : (llx < lrx) ? llx : lrx; - xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx - : (llx > lrx) ? llx : lrx - : (urx > llx) ? (urx > lrx) ? urx : lrx - : (llx > lrx) ? llx : lrx; - yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry - : (lly < lry) ? lly : lry - : (ury < lly) ? (ury < lry) ? ury : lry - : (lly < lry) ? lly : lry; - yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry - : (lly > lry) ? lly : lry - : (ury > lly) ? (ury > lry) ? ury : lry - : (lly > lry) ? lly : lry; - clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); - opClipRes = clipRes; - - // compute Bresenham parameters for x and y scaling - yp = h / scaledHeight; - yq = h % scaledHeight; - xp = w / scaledWidth; - xq = w % scaledWidth; - - // allocate pixel buffer - pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w); - - // init y scale Bresenham - yt = 0; - lastYStep = 1; - - for (y = 0; y < scaledHeight; ++y) { - - // y scale Bresenham - yStep = yp; - yt += yq; - if (yt >= scaledHeight) { - yt -= scaledHeight; - ++yStep; - } - - // read row(s) from image - n = (yp > 0) ? yStep : lastYStep; - if (n > 0) { - p = pixBuf; - for (i = 0; i < n; ++i) { - (*src)(srcData, p); - p += w; - } - } - lastYStep = yStep; - - // loop-invariant constants - k1 = splashRound(xShear * ySign * y); - - // clipping test - if (clipRes != splashClipAllInside && - !rot && - (int)(yShear * k1) == - (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { - if (xSign > 0) { - spanXMin = tx + k1; - spanXMax = spanXMin + (scaledWidth - 1); - } else { - spanXMax = tx + k1; - spanXMin = spanXMax - (scaledWidth - 1); - } - spanY = ty + ySign * y + (int)(yShear * k1); - clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); - if (clipRes2 == splashClipAllOutside) { - continue; - } - } else { - clipRes2 = clipRes; - } - - // init x scale Bresenham - xt = 0; - xSrc = 0; - - // x shear - x1 = k1; - - // y shear - y1 = (SplashCoord)ySign * y + yShear * x1; - // this is a kludge: if yShear1 is negative, then (int)y1 would - // change immediately after the first pixel, which is not what we - // want - if (yShear1 < 0) { - y1 += 0.999; - } - - // loop-invariant constants - n = yStep > 0 ? yStep : 1; - - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - xStep = xp; - xt += xq; - if (xt >= scaledWidth) { - xt -= scaledWidth; - ++xStep; - } - - // rotation - if (rot) { - x2 = (int)y1; - y2 = -x1; - } else { - x2 = x1; - y2 = (int)y1; - } - - // compute the alpha value for (x,y) after the x and y scaling - // operations - m = xStep > 0 ? xStep : 1; - p = pixBuf + xSrc; - pixAcc = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - pixAcc += *p++; - } - p += w - m; - } - - // blend fill color with background - if (pixAcc != 0) { - if (pixAcc == n * m) { - drawPixel(tx + x2, ty + y2, state->fillPattern, state->fillAlpha, - clipRes2 == splashClipAllInside); - } else { - alpha = (SplashCoord)pixAcc / (SplashCoord)(n * m); - drawPixel(tx + x2, ty + y2, state->fillPattern, - state->fillAlpha * alpha, - clipRes2 == splashClipAllInside); - } - } - - // x scale Bresenham - xSrc += xStep; - - // x shear - x1 += xSign; - - // y shear - y1 += yShear1; - } - } - - // free memory - gfree(pixBuf); - - return splashOk; -} - -SplashError Splash::drawImage(SplashImageSource src, void *srcData, - SplashColorMode srcMode, - int w, int h, SplashCoord *mat) { - GBool ok, rot, halftone, srcAlpha; - SplashCoord xScale, yScale, xShear, yShear, yShear1; - int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign; - int ulx, uly, llx, lly, urx, ury, lrx, lry; - int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; - int xMin, xMax, yMin, yMax; - SplashClipResult clipRes, clipRes2; - int yp, yq, yt, yStep, lastYStep; - int xp, xq, xt, xStep, xSrc; - int k1, spanXMin, spanXMax, spanY; - SplashColorPtr pixBuf, p; - SplashColor pix; -#if SPLASH_CMYK - int pixAcc0, pixAcc1, pixAcc2, pixAcc3; -#else - int pixAcc0, pixAcc1, pixAcc2; -#endif - int alphaAcc; - SplashCoord pixMul, alphaMul, alpha; - int x, y, x1, x2, y2; - SplashCoord y1; - int nComps, n, m, i, j; - - if (debugMode) { - printf("drawImage: srcMode=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", - srcMode, w, h, (double)mat[0], (double)mat[1], (double)mat[2], - (double)mat[3], (double)mat[4], (double)mat[5]); - } - - // check color modes - ok = gFalse; // make gcc happy - nComps = 0; // make gcc happy - halftone = gFalse; - srcAlpha = gFalse; - switch (bitmap->mode) { - case splashModeMono1: - ok = srcMode == splashModeMono1 || srcMode == splashModeMono8 || - srcMode == splashModeAMono8; - halftone = srcMode == splashModeMono8 || srcMode == splashModeAMono8; - srcAlpha = srcMode == splashModeAMono8; - nComps = srcAlpha ? 2 : 1; - break; - case splashModeMono8: - ok = srcMode == splashModeMono8 || srcMode == splashModeAMono8; - srcAlpha = srcMode == splashModeAMono8; - nComps = srcAlpha ? 2 : 1; - break; - case splashModeAMono8: - //~ not implemented yet - ok = gFalse; - nComps = 2; - break; - case splashModeRGB8: - ok = srcMode == splashModeRGB8 || srcMode == splashModeARGB8; - srcAlpha = srcMode == splashModeARGB8; - nComps = srcAlpha ? 4 : 3; - break; - case splashModeBGR8: - ok = srcMode == splashModeBGR8 || srcMode == splashModeBGRA8; - srcAlpha = srcMode == splashModeBGRA8; - nComps = srcAlpha ? 4 : 3; - break; -#if SPLASH_CMYK - case splashModeCMYK8: - ok = srcMode == splashModeCMYK8 || srcMode == splashModeACMYK8; - srcAlpha = srcMode == splashModeACMYK8; - nComps = srcAlpha ? 5 : 4; - break; -#endif - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeACMYK8: -#endif - //~ not implemented yet - ok = gFalse; - nComps = 4; - break; - } - if (!ok) { - return splashErrModeMismatch; - } - - // check for singular matrix - if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) { - return splashErrSingularMatrix; - } - - // compute scale, shear, rotation, translation parameters - rot = splashAbs(mat[1]) > splashAbs(mat[0]); - if (rot) { - xScale = -mat[1]; - yScale = mat[2] - (mat[0] * mat[3]) / mat[1]; - xShear = -mat[3] / yScale; - yShear = -mat[0] / mat[1]; - } else { - xScale = mat[0]; - yScale = mat[3] - (mat[1] * mat[2]) / mat[0]; - xShear = mat[2] / yScale; - yShear = mat[1] / mat[0]; - } - // the +/-0.01 in these computations is to avoid floating point - // precision problems which can lead to gaps between image stripes - // (it can cause image stripes to overlap, but that's a much less - // visible problem) - if (xScale >= 0) { - tx = splashRound(mat[4] - 0.01); - tx2 = splashRound(mat[4] + xScale + 0.01) - 1; - } else { - tx = splashRound(mat[4] + 0.01) - 1; - tx2 = splashRound(mat[4] + xScale - 0.01); - } - scaledWidth = abs(tx2 - tx) + 1; - if (scaledWidth == 0) { - // technically, this should draw nothing, but it generally seems - // better to draw a one-pixel-wide stripe rather than throwing it - // away - scaledWidth = 1; - } - if (yScale >= 0) { - ty = splashRound(mat[5] - 0.01); - ty2 = splashRound(mat[5] + yScale + 0.01) - 1; - } else { - ty = splashRound(mat[5] + 0.01) - 1; - ty2 = splashRound(mat[5] + yScale - 0.01); - } - scaledHeight = abs(ty2 - ty) + 1; - if (scaledHeight == 0) { - // technically, this should draw nothing, but it generally seems - // better to draw a one-pixel-wide stripe rather than throwing it - // away - scaledHeight = 1; - } - xSign = (xScale < 0) ? -1 : 1; - ySign = (yScale < 0) ? -1 : 1; - yShear1 = (SplashCoord)xSign * yShear; - - // clipping - ulx1 = 0; - uly1 = 0; - urx1 = xSign * (scaledWidth - 1); - ury1 = (int)(yShear * urx1); - llx1 = splashRound(xShear * ySign * (scaledHeight - 1)); - lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1); - lrx1 = xSign * (scaledWidth - 1) + - splashRound(xShear * ySign * (scaledHeight - 1)); - lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1); - if (rot) { - ulx = tx + uly1; uly = ty - ulx1; - urx = tx + ury1; ury = ty - urx1; - llx = tx + lly1; lly = ty - llx1; - lrx = tx + lry1; lry = ty - lrx1; - } else { - ulx = tx + ulx1; uly = ty + uly1; - urx = tx + urx1; ury = ty + ury1; - llx = tx + llx1; lly = ty + lly1; - lrx = tx + lrx1; lry = ty + lry1; - } - xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx - : (llx < lrx) ? llx : lrx - : (urx < llx) ? (urx < lrx) ? urx : lrx - : (llx < lrx) ? llx : lrx; - xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx - : (llx > lrx) ? llx : lrx - : (urx > llx) ? (urx > lrx) ? urx : lrx - : (llx > lrx) ? llx : lrx; - yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry - : (lly < lry) ? lly : lry - : (ury < lly) ? (ury < lry) ? ury : lry - : (lly < lry) ? lly : lry; - yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry - : (lly > lry) ? lly : lry - : (ury > lly) ? (ury > lry) ? ury : lry - : (lly > lry) ? lly : lry; - clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); - opClipRes = clipRes; - if (clipRes == splashClipAllOutside) { - return splashOk; - } - - // compute Bresenham parameters for x and y scaling - yp = h / scaledHeight; - yq = h % scaledHeight; - xp = w / scaledWidth; - xq = w % scaledWidth; - - // allocate pixel buffer - pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w * nComps); - - pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy -#if SPLASH_CMYK - pixAcc3 = 0; // make gcc happy -#endif - - if (srcAlpha) { - - // init y scale Bresenham - yt = 0; - lastYStep = 1; - - for (y = 0; y < scaledHeight; ++y) { - - // y scale Bresenham - yStep = yp; - yt += yq; - if (yt >= scaledHeight) { - yt -= scaledHeight; - ++yStep; - } - - // read row(s) from image - n = (yp > 0) ? yStep : lastYStep; - if (n > 0) { - p = pixBuf; - for (i = 0; i < n; ++i) { - (*src)(srcData, p); - p += w * nComps; - } - } - lastYStep = yStep; - - // loop-invariant constants - k1 = splashRound(xShear * ySign * y); - - // clipping test - if (clipRes != splashClipAllInside && - !rot && - (int)(yShear * k1) == - (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { - if (xSign > 0) { - spanXMin = tx + k1; - spanXMax = spanXMin + (scaledWidth - 1); - } else { - spanXMax = tx + k1; - spanXMin = spanXMax - (scaledWidth - 1); - } - spanY = ty + ySign * y + (int)(yShear * k1); - clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); - if (clipRes2 == splashClipAllOutside) { - continue; - } - } else { - clipRes2 = clipRes; - } - - // init x scale Bresenham - xt = 0; - xSrc = 0; - - // x shear - x1 = k1; - - // y shear - y1 = (SplashCoord)ySign * y + yShear * x1; - // this is a kludge: if yShear1 is negative, then (int)y1 would - // change immediately after the first pixel, which is not what - // we want - if (yShear1 < 0) { - y1 += 0.999; - } - - // loop-invariant constants - n = yStep > 0 ? yStep : 1; - - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - xStep = xp; - xt += xq; - if (xt >= scaledWidth) { - xt -= scaledWidth; - ++xStep; - } - - // rotation - if (rot) { - x2 = (int)y1; - y2 = -x1; - } else { - x2 = x1; - y2 = (int)y1; - } - - // compute the filtered pixel at (x,y) after the x and y scaling - // operations - m = xStep > 0 ? xStep : 1; - alphaAcc = 0; - switch (srcMode) { - case splashModeAMono8: - p = pixBuf + xSrc * 2; - pixAcc0 = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - alphaAcc += *p++; - pixAcc0 += *p++; - } - p += 2 * (w - m); - } - break; - case splashModeARGB8: - p = pixBuf + xSrc * 4; - pixAcc0 = pixAcc1 = pixAcc2 = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - alphaAcc += *p++; - pixAcc0 += *p++; - pixAcc1 += *p++; - pixAcc2 += *p++; - } - p += 4 * (w - m); - } - break; - case splashModeBGRA8: - p = pixBuf + xSrc * 4; - pixAcc0 = pixAcc1 = pixAcc2 = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - pixAcc0 += *p++; - pixAcc1 += *p++; - pixAcc2 += *p++; - alphaAcc += *p++; - } - p += 4 * (w - m); - } - break; -#if SPLASH_CMYK - case splashModeACMYK8: - p = pixBuf + xSrc * 5; - pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - alphaAcc += *p++; - pixAcc0 += *p++; - pixAcc1 += *p++; - pixAcc2 += *p++; - pixAcc3 += *p++; - } - p += 5 * (w - m); - } - break; -#endif - default: // make gcc happy - break; - } - pixMul = (SplashCoord)1 / (SplashCoord)(n * m); - alphaMul = pixMul * (1.0 / 256.0); - alpha = (SplashCoord)alphaAcc * alphaMul; - - if (alpha > 0) { - // mono8 -> mono1 conversion, with halftoning - if (halftone) { - pix[0] = state->screen->test(tx + x2, ty + y2, - (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0)); - - // no conversion, no halftoning - } else { - switch (bitmap->mode) { -#if SPLASH_CMYK - case splashModeCMYK8: - pix[3] = (int)((SplashCoord)pixAcc3 * pixMul); - // fall through -#endif - case splashModeRGB8: - case splashModeBGR8: - pix[2] = (int)((SplashCoord)pixAcc2 * pixMul); - pix[1] = (int)((SplashCoord)pixAcc1 * pixMul); - // fall through - case splashModeMono1: - case splashModeMono8: - pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); - break; - default: // make gcc happy - break; - } - } - - // set pixel - drawPixel(tx + x2, ty + y2, pix, alpha * state->fillAlpha, - clipRes2 == splashClipAllInside); - } - - // x scale Bresenham - xSrc += xStep; - - // x shear - x1 += xSign; - - // y shear - y1 += yShear1; - } - } - - } else { - - // init y scale Bresenham - yt = 0; - lastYStep = 1; - - for (y = 0; y < scaledHeight; ++y) { - - // y scale Bresenham - yStep = yp; - yt += yq; - if (yt >= scaledHeight) { - yt -= scaledHeight; - ++yStep; - } - - // read row(s) from image - n = (yp > 0) ? yStep : lastYStep; - if (n > 0) { - p = pixBuf; - for (i = 0; i < n; ++i) { - (*src)(srcData, p); - p += w * nComps; - } - } - lastYStep = yStep; - - // loop-invariant constants - k1 = splashRound(xShear * ySign * y); - - // clipping test - if (clipRes != splashClipAllInside && - !rot && - (int)(yShear * k1) == - (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { - if (xSign > 0) { - spanXMin = tx + k1; - spanXMax = spanXMin + (scaledWidth - 1); - } else { - spanXMax = tx + k1; - spanXMin = spanXMax - (scaledWidth - 1); - } - spanY = ty + ySign * y + (int)(yShear * k1); - clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); - if (clipRes2 == splashClipAllOutside) { - continue; - } - } else { - clipRes2 = clipRes; - } - - // init x scale Bresenham - xt = 0; - xSrc = 0; - - // x shear - x1 = k1; - - // y shear - y1 = (SplashCoord)ySign * y + yShear * x1; - // this is a kludge: if yShear1 is negative, then (int)y1 would - // change immediately after the first pixel, which is not what - // we want - if (yShear1 < 0) { - y1 += 0.999; - } - - // loop-invariant constants - n = yStep > 0 ? yStep : 1; - - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - xStep = xp; - xt += xq; - if (xt >= scaledWidth) { - xt -= scaledWidth; - ++xStep; - } - - // rotation - if (rot) { - x2 = (int)y1; - y2 = -x1; - } else { - x2 = x1; - y2 = (int)y1; - } - - // compute the filtered pixel at (x,y) after the x and y scaling - // operations - m = xStep > 0 ? xStep : 1; - switch (srcMode) { - case splashModeMono1: - case splashModeMono8: - p = pixBuf + xSrc; - pixAcc0 = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - pixAcc0 += *p++; - } - p += w - m; - } - break; - case splashModeRGB8: - case splashModeBGR8: - p = pixBuf + xSrc * 3; - pixAcc0 = pixAcc1 = pixAcc2 = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - pixAcc0 += *p++; - pixAcc1 += *p++; - pixAcc2 += *p++; - } - p += 3 * (w - m); - } - break; -#if SPLASH_CMYK - case splashModeCMYK8: - p = pixBuf + xSrc * 4; - pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - pixAcc0 += *p++; - pixAcc1 += *p++; - pixAcc2 += *p++; - pixAcc3 += *p++; - } - p += 4 * (w - m); - } - break; -#endif - default: // make gcc happy - break; - } - pixMul = (SplashCoord)1 / (SplashCoord)(n * m); - - // mono8 -> mono1 conversion, with halftoning - if (halftone) { - pix[0] = state->screen->test(tx + x2, ty + y2, - (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0)); - - // no conversion, no halftoning - } else { - switch (bitmap->mode) { -#if SPLASH_CMYK - case splashModeCMYK8: - pix[3] = (int)((SplashCoord)pixAcc3 * pixMul); - // fall through -#endif - case splashModeRGB8: - case splashModeBGR8: - pix[2] = (int)((SplashCoord)pixAcc2 * pixMul); - pix[1] = (int)((SplashCoord)pixAcc1 * pixMul); - // fall through - case splashModeMono1: - case splashModeMono8: - pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); - break; - default: // make gcc happy - break; - } - } - - // set pixel - drawPixel(tx + x2, ty + y2, pix, state->fillAlpha, - clipRes2 == splashClipAllInside); - - // x scale Bresenham - xSrc += xStep; - - // x shear - x1 += xSign; - - // y shear - y1 += yShear1; - } - } - - } - - gfree(pixBuf); - - return splashOk; -} - -void Splash::dumpPath(SplashPath *path) { - int i; - - for (i = 0; i < path->length; ++i) { - printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s%s\n", - i, (double)path->pts[i].x, (double)path->pts[i].y, - (path->flags[i] & splashPathFirst) ? " first" : "", - (path->flags[i] & splashPathLast) ? " last" : "", - (path->flags[i] & splashPathClosed) ? " closed" : "", - (path->flags[i] & splashPathCurve) ? " curve" : "", - (path->flags[i] & splashPathArcCW) ? " arcCW" : ""); - } -} - -void Splash::dumpXPath(SplashXPath *path) { - int i; - - for (i = 0; i < path->length; ++i) { - printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n", - i, (double)path->segs[i].x0, (double)path->segs[i].y0, - (double)path->segs[i].x1, (double)path->segs[i].y1, - (path->segs[i].flags & splashXPathFirst) ? "F" : " ", - (path->segs[i].flags & splashXPathLast) ? "L" : " ", - (path->segs[i].flags & splashXPathEnd0) ? "0" : " ", - (path->segs[i].flags & splashXPathEnd1) ? "1" : " ", - (path->segs[i].flags & splashXPathHoriz) ? "H" : " ", - (path->segs[i].flags & splashXPathVert) ? "V" : " ", - (path->segs[i].flags & splashXPathFlip) ? "P" : " "); - } -} diff --git a/xpdf/splash/Splash.h b/xpdf/splash/Splash.h deleted file mode 100644 index fd3ec80da..000000000 --- a/xpdf/splash/Splash.h +++ /dev/null @@ -1,204 +0,0 @@ -//======================================================================== -// -// Splash.h -// -//======================================================================== - -#ifndef SPLASH_H -#define SPLASH_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashTypes.h" -#include "SplashClip.h" - -class SplashBitmap; -struct SplashGlyphBitmap; -class SplashState; -class SplashPattern; -class SplashScreen; -class SplashPath; -class SplashXPath; -class SplashFont; - -//------------------------------------------------------------------------ - -// Retrieves the next line of pixels in an image mask. Normally, -// fills in * and returns true. If the image stream is -// exhausted, returns false. -typedef GBool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel); - -// Retrieves the next line of pixels in an image. Normally, fills in -// * and returns true. If the image stream is exhausted, -// returns false. -typedef GBool (*SplashImageSource)(void *data, SplashColorPtr line); - -//------------------------------------------------------------------------ -// Splash -//------------------------------------------------------------------------ - -class Splash { -public: - - // Create a new rasterizer object. - Splash(SplashBitmap *bitmapA); - - ~Splash(); - - //----- state read - - SplashPattern *getStrokePattern(); - SplashPattern *getFillPattern(); - SplashScreen *getScreen(); - SplashBlendFunc getBlendFunc(); - SplashCoord getStrokeAlpha(); - SplashCoord getFillAlpha(); - SplashCoord getLineWidth(); - int getLineCap(); - int getLineJoin(); - SplashCoord getMiterLimit(); - SplashCoord getFlatness(); - SplashCoord *getLineDash(); - int getLineDashLength(); - SplashCoord getLineDashPhase(); - SplashClip *getClip(); - - //----- state write - - void setStrokePattern(SplashPattern *strokeColor); - void setFillPattern(SplashPattern *fillColor); - void setScreen(SplashScreen *screen); - void setBlendFunc(SplashBlendFunc func); - void setStrokeAlpha(SplashCoord alpha); - void setFillAlpha(SplashCoord alpha); - void setLineWidth(SplashCoord lineWidth); - void setLineCap(int lineCap); - void setLineJoin(int lineJoin); - void setMiterLimit(SplashCoord miterLimit); - void setFlatness(SplashCoord flatness); - // the array will be copied - void setLineDash(SplashCoord *lineDash, int lineDashLength, - SplashCoord lineDashPhase); - void clipResetToRect(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1); - SplashError clipToRect(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1); - SplashError clipToPath(SplashPath *path, GBool eo); - - //----- state save/restore - - void saveState(); - SplashError restoreState(); - - //----- soft mask - - void setSoftMask(SplashBitmap *softMaskA); - - //----- drawing operations - - // Fill the bitmap with . This is not subject to clipping. - void clear(SplashColorPtr color); - - // Stroke a path using the current stroke pattern. - SplashError stroke(SplashPath *path); - - // Fill a path using the current fill pattern. - SplashError fill(SplashPath *path, GBool eo); - - // Fill a path, XORing with the current fill pattern. - SplashError xorFill(SplashPath *path, GBool eo); - - // Draw a character, using the current fill pattern. - SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font); - - // Draw a glyph, using the current fill pattern. This function does - // not free any data, i.e., it ignores glyph->freeData. - SplashError fillGlyph(SplashCoord x, SplashCoord y, - SplashGlyphBitmap *glyph); - - // Draws an image mask using the fill color. This will read - // lines of pixels from , starting with the top line. "1" - // pixels will be drawn with the current fill color; "0" pixels are - // transparent. The matrix: - // [ mat[0] mat[1] 0 ] - // [ mat[2] mat[3] 0 ] - // [ mat[4] mat[5] 1 ] - // maps a unit square to the desired destination for the image, in - // PostScript style: - // [x' y' 1] = [x y 1] * mat - // Note that the Splash y axis points downward, and the image source - // is assumed to produce pixels in raster order, starting from the - // top line. - SplashError fillImageMask(SplashImageMaskSource src, void *srcData, - int w, int h, SplashCoord *mat); - - // Draw an image. This will read lines of pixels from - // , starting with the top line. These pixels are assumed to - // be in the source mode, . The following combinations of - // source and target modes are supported: - // source target - // ------ ------ - // Mono1 Mono1 - // Mono8 Mono1 -- with dithering - // Mono8 Mono8 - // RGB8 RGB8 - // BGR8 BGR8 - // ARGB8 RGB8 -- with source alpha (masking) - // BGRA8 BGR8 -- with source alpha (masking) - // The matrix behaves as for fillImageMask. - SplashError drawImage(SplashImageSource src, void *srcData, - SplashColorMode srcMode, - int w, int h, SplashCoord *mat); - - //----- misc - - // Return the associated bitmap. - SplashBitmap *getBitmap() { return bitmap; } - - // Get a bounding box which includes all modifications since the - // last call to clearModRegion. - void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax) - { *xMin = modXMin; *yMin = modYMin; *xMax = modXMax; *yMax = modYMax; } - - // Clear the modified region bounding box. - void clearModRegion(); - - // Get clipping status for the last drawing operation subject to - // clipping. - SplashClipResult getClipRes() { return opClipRes; } - - // Toggle debug mode on or off. - void setDebugMode(GBool debugModeA) { debugMode = debugModeA; } - -private: - - void updateModX(int x); - void updateModY(int y); - void strokeNarrow(SplashXPath *xPath); - void strokeWide(SplashXPath *xPath); - SplashXPath *makeDashedPath(SplashXPath *xPath); - SplashError fillWithPattern(SplashPath *path, GBool eo, - SplashPattern *pattern, SplashCoord alpha); - void drawPixel(int x, int y, SplashColorPtr color, - SplashCoord alpha, GBool noClip); - void drawPixel(int x, int y, SplashPattern *pattern, - SplashCoord alpha, GBool noClip); - void drawSpan(int x0, int x1, int y, SplashPattern *pattern, - SplashCoord alpha, GBool noClip); - void xorSpan(int x0, int x1, int y, SplashPattern *pattern, GBool noClip); - void dumpPath(SplashPath *path); - void dumpXPath(SplashXPath *path); - - SplashBitmap *bitmap; - SplashState *state; - SplashBitmap *softMask; - int modXMin, modYMin, modXMax, modYMax; - SplashClipResult opClipRes; - GBool debugMode; -}; - -#endif diff --git a/xpdf/splash/SplashBitmap.cc b/xpdf/splash/SplashBitmap.cc deleted file mode 100644 index 30702bcf8..000000000 --- a/xpdf/splash/SplashBitmap.cc +++ /dev/null @@ -1,243 +0,0 @@ -//======================================================================== -// -// SplashBitmap.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "SplashErrorCodes.h" -#include "SplashBitmap.h" - -//------------------------------------------------------------------------ -// SplashBitmap -//------------------------------------------------------------------------ - -SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, - SplashColorMode modeA, GBool topDown) { - width = widthA; - height = heightA; - mode = modeA; - switch (mode) { - case splashModeMono1: - rowSize = (width + 7) >> 3; - break; - case splashModeMono8: - rowSize = width; - break; - case splashModeAMono8: - rowSize = width * 2; - break; - case splashModeRGB8: - case splashModeBGR8: - rowSize = width * 3; - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - rowSize = width * 4; - break; -#if SPLASH_CMYK - case splashModeACMYK8: - rowSize = width * 5; - break; -#endif - } - rowSize += rowPad - 1; - rowSize -= rowSize % rowPad; - data = (SplashColorPtr)gmalloc(rowSize * height); - if (!topDown) { - data += (height - 1) * rowSize; - rowSize = -rowSize; - } -} - - -SplashBitmap::~SplashBitmap() { - if (rowSize < 0) { - gfree(data + (height - 1) * rowSize); - } else { - gfree(data); - } -} - -SplashError SplashBitmap::writePNMFile(char *fileName) { - FILE *f; - SplashColorPtr row, p; - int x, y; - - if (!(f = fopen(fileName, "wb"))) { - return splashErrOpenFile; - } - - switch (mode) { - - case splashModeMono1: - fprintf(f, "P4\n%d %d\n", width, height); - row = data; - for (y = 0; y < height; ++y) { - p = row; - for (x = 0; x < width; x += 8) { - fputc(*p ^ 0xff, f); - ++p; - } - row += rowSize; - } - break; - - case splashModeMono8: - fprintf(f, "P5\n%d %d\n255\n", width, height); - row = data; - for (y = 0; y < height; ++y) { - p = row; - for (x = 0; x < width; ++x) { - fputc(*p, f); - ++p; - } - row += rowSize; - } - break; - - case splashModeAMono8: - fprintf(f, "P5\n%d %d\n255\n", width, height); - row = data; - for (y = 0; y < height; ++y) { - p = row; - for (x = 0; x < width; ++x) { - fputc(splashAMono8M(p), f); - p += 2; - } - row += rowSize; - } - break; - - case splashModeRGB8: - fprintf(f, "P6\n%d %d\n255\n", width, height); - row = data; - for (y = 0; y < height; ++y) { - p = row; - for (x = 0; x < width; ++x) { - fputc(splashRGB8R(p), f); - fputc(splashRGB8G(p), f); - fputc(splashRGB8B(p), f); - p += 3; - } - row += rowSize; - } - break; - - case splashModeBGR8: - fprintf(f, "P6\n%d %d\n255\n", width, height); - row = data; - for (y = 0; y < height; ++y) { - p = row; - for (x = 0; x < width; ++x) { - fputc(splashBGR8R(p), f); - fputc(splashBGR8G(p), f); - fputc(splashBGR8B(p), f); - p += 3; - } - row += rowSize; - } - break; - - case splashModeARGB8: - fprintf(f, "P6\n%d %d\n255\n", width, height); - row = data; - for (y = 0; y < height; ++y) { - p = row; - for (x = 0; x < width; ++x) { - fputc(splashARGB8R(p), f); - fputc(splashARGB8G(p), f); - fputc(splashARGB8B(p), f); - p += 4; - } - row += rowSize; - } - break; - - case splashModeBGRA8: - fprintf(f, "P6\n%d %d\n255\n", width, height); - row = data; - for (y = 0; y < height; ++y) { - p = row; - for (x = 0; x < width; ++x) { - fputc(splashBGRA8R(p), f); - fputc(splashBGRA8G(p), f); - fputc(splashBGRA8B(p), f); - p += 4; - } - row += rowSize; - } - break; - -#if SPLASH_CMYK - case splashModeCMYK8: - case splashModeACMYK8: - // PNM doesn't support CMYK - break; -#endif - } - - fclose(f); - return splashOk; -} - -void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { - SplashColorPtr p; - - if (y < 0 || y >= height || x < 0 || x >= width) { - return; - } - switch (mode) { - case splashModeMono1: - p = &data[y * rowSize + (x >> 3)]; - pixel[0] = (p[0] >> (7 - (x & 7))) & 1; - break; - case splashModeMono8: - p = &data[y * rowSize + x]; - pixel[0] = p[0]; - break; - case splashModeAMono8: - p = &data[y * rowSize + 2 * x]; - pixel[0] = p[0]; - pixel[1] = p[1]; - break; - case splashModeRGB8: - case splashModeBGR8: - p = &data[y * rowSize + 3 * x]; - pixel[0] = p[0]; - pixel[1] = p[1]; - pixel[2] = p[2]; - break; - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeCMYK8: -#endif - p = &data[y * rowSize + 4 * x]; - pixel[0] = p[0]; - pixel[1] = p[1]; - pixel[2] = p[2]; - pixel[3] = p[3]; - break; -#if SPLASH_CMYK - case splashModeACMYK8: - p = &data[y * rowSize + 5 * x]; - pixel[0] = p[0]; - pixel[1] = p[1]; - pixel[2] = p[2]; - pixel[3] = p[3]; - pixel[4] = p[4]; - break; -#endif - } -} diff --git a/xpdf/splash/SplashBitmap.h b/xpdf/splash/SplashBitmap.h deleted file mode 100644 index 0f2270da1..000000000 --- a/xpdf/splash/SplashBitmap.h +++ /dev/null @@ -1,55 +0,0 @@ -//======================================================================== -// -// SplashBitmap.h -// -//======================================================================== - -#ifndef SPLASHBITMAP_H -#define SPLASHBITMAP_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashTypes.h" - -//------------------------------------------------------------------------ -// SplashBitmap -//------------------------------------------------------------------------ - -class SplashBitmap { -public: - - // Create a new bitmap. It will have x pixels in - // color mode . Rows will be padded out to a multiple of - // bytes. If is false, the bitmap will be stored - // upside-down, i.e., with the last row first in memory. - SplashBitmap(int widthA, int heightA, int rowPad, - SplashColorMode modeA, GBool topDown = gTrue); - - ~SplashBitmap(); - - int getWidth() { return width; } - int getHeight() { return height; } - int getRowSize() { return rowSize; } - SplashColorMode getMode() { return mode; } - SplashColorPtr getDataPtr() { return data; } - - SplashError writePNMFile(char *fileName); - - void getPixel(int x, int y, SplashColorPtr pixel); - -private: - - int width, height; // size of bitmap - int rowSize; // size of one row of data, in bytes - // - negative for bottom-up bitmaps - SplashColorMode mode; // color mode - SplashColorPtr data; // pointer to row zero of the bitmap data - - friend class Splash; -}; - -#endif diff --git a/xpdf/splash/SplashClip.cc b/xpdf/splash/SplashClip.cc deleted file mode 100644 index 07f740715..000000000 --- a/xpdf/splash/SplashClip.cc +++ /dev/null @@ -1,270 +0,0 @@ -//======================================================================== -// -// SplashClip.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "SplashErrorCodes.h" -#include "SplashMath.h" -#include "SplashPath.h" -#include "SplashXPath.h" -#include "SplashXPathScanner.h" -#include "SplashClip.h" - -//------------------------------------------------------------------------ -// SplashClip.flags -//------------------------------------------------------------------------ - -#define splashClipEO 0x01 // use even-odd rule - -//------------------------------------------------------------------------ -// SplashClip -//------------------------------------------------------------------------ - -SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1) { - if (x0 < x1) { - xMin = splashFloor(x0); - xMax = splashFloor(x1); - } else { - xMin = splashFloor(x1); - xMax = splashFloor(x0); - } - if (y0 < y1) { - yMin = splashFloor(y0); - yMax = splashFloor(y1); - } else { - yMin = splashFloor(y1); - yMax = splashFloor(y0); - } - paths = NULL; - flags = NULL; - scanners = NULL; - length = size = 0; -} - -SplashClip::SplashClip(SplashClip *clip) { - int i; - - xMin = clip->xMin; - yMin = clip->yMin; - xMax = clip->xMax; - yMax = clip->yMax; - length = clip->length; - size = clip->size; - paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *)); - flags = (Guchar *)gmallocn(size, sizeof(Guchar)); - scanners = (SplashXPathScanner **) - gmallocn(size, sizeof(SplashXPathScanner *)); - for (i = 0; i < length; ++i) { - paths[i] = clip->paths[i]->copy(); - flags[i] = clip->flags[i]; - scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO); - } -} - -SplashClip::~SplashClip() { - int i; - - for (i = 0; i < length; ++i) { - delete paths[i]; - delete scanners[i]; - } - gfree(paths); - gfree(flags); - gfree(scanners); -} - -void SplashClip::grow(int nPaths) { - if (length + nPaths > size) { - if (size == 0) { - size = 32; - } - while (size < length + nPaths) { - size *= 2; - } - paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *)); - flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); - scanners = (SplashXPathScanner **) - greallocn(scanners, size, sizeof(SplashXPathScanner *)); - } -} - -void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1) { - int i; - - for (i = 0; i < length; ++i) { - delete paths[i]; - delete scanners[i]; - } - gfree(paths); - gfree(flags); - gfree(scanners); - paths = NULL; - flags = NULL; - scanners = NULL; - length = size = 0; - - if (x0 < x1) { - xMin = splashFloor(x0); - xMax = splashFloor(x1); - } else { - xMin = splashFloor(x1); - xMax = splashFloor(x0); - } - if (y0 < y1) { - yMin = splashFloor(y0); - yMax = splashFloor(y1); - } else { - yMin = splashFloor(y1); - yMax = splashFloor(y0); - } -} - -SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1) { - int x0I, y0I, x1I, y1I; - - if (x0 < x1) { - x0I = splashFloor(x0); - x1I = splashFloor(x1); - } else { - x0I = splashFloor(x1); - x1I = splashFloor(x0); - } - if (x0I > xMin) { - xMin = x0I; - } - if (x1I < xMax) { - xMax = x1I; - } - if (y0 < y1) { - y0I = splashFloor(y0); - y1I = splashFloor(y1); - } else { - y0I = splashFloor(y1); - y1I = splashFloor(y0); - } - if (y0I > yMin) { - yMin = y0I; - } - if (y1I < yMax) { - yMax = y1I; - } - return splashOk; -} - -SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord flatness, - GBool eo) { - SplashXPath *xPath; - - xPath = new SplashXPath(path, flatness, gTrue); - - // check for an empty path - if (xPath->length == 0) { - xMax = xMin - 1; - yMax = yMin - 1; - delete xPath; - - // check for a rectangle - } else if (xPath->length == 4 && - ((xPath->segs[0].x0 == xPath->segs[0].x1 && - xPath->segs[0].x0 == xPath->segs[1].x0 && - xPath->segs[0].x0 == xPath->segs[3].x1 && - xPath->segs[2].x0 == xPath->segs[2].x1 && - xPath->segs[2].x0 == xPath->segs[1].x1 && - xPath->segs[2].x0 == xPath->segs[3].x0 && - xPath->segs[1].y0 == xPath->segs[1].y1 && - xPath->segs[1].y0 == xPath->segs[0].y1 && - xPath->segs[1].y0 == xPath->segs[2].y0 && - xPath->segs[3].y0 == xPath->segs[3].y1 && - xPath->segs[3].y0 == xPath->segs[0].y0 && - xPath->segs[3].y0 == xPath->segs[2].y1) || - (xPath->segs[0].y0 == xPath->segs[0].y1 && - xPath->segs[0].y0 == xPath->segs[1].y0 && - xPath->segs[0].y0 == xPath->segs[3].y1 && - xPath->segs[2].y0 == xPath->segs[2].y1 && - xPath->segs[2].y0 == xPath->segs[1].y1 && - xPath->segs[2].y0 == xPath->segs[3].y0 && - xPath->segs[1].x0 == xPath->segs[1].x1 && - xPath->segs[1].x0 == xPath->segs[0].x1 && - xPath->segs[1].x0 == xPath->segs[2].x0 && - xPath->segs[3].x0 == xPath->segs[3].x1 && - xPath->segs[3].x0 == xPath->segs[0].x0 && - xPath->segs[3].x0 == xPath->segs[2].x1))) { - clipToRect(xPath->segs[0].x0, xPath->segs[0].y0, - xPath->segs[2].x0, xPath->segs[2].y0); - delete xPath; - - } else { - grow(1); - xPath->sort(); - paths[length] = xPath; - flags[length] = eo ? splashClipEO : 0; - scanners[length] = new SplashXPathScanner(xPath, eo); - ++length; - } - - return splashOk; -} - -GBool SplashClip::test(int x, int y) { - int i; - - // check the rectangle - if (x < xMin || x > xMax || y < yMin || y > yMax) { - return gFalse; - } - - // check the paths - for (i = 0; i < length; ++i) { - if (!scanners[i]->test(x, y)) { - return gFalse; - } - } - - return gTrue; -} - -SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, - int rectXMax, int rectYMax) { - if (rectXMax < xMin || rectXMin > xMax || - rectYMax < yMin || rectYMin > yMax) { - return splashClipAllOutside; - } - if (rectXMin >= xMin && rectXMax <= xMax && - rectYMin >= yMin && rectYMax <= yMax && - length == 0) { - return splashClipAllInside; - } - return splashClipPartial; -} - -SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) { - int i; - - if (spanXMax < xMin || spanXMin > xMax || - spanY < yMin || spanY > yMax) { - return splashClipAllOutside; - } - if (!(spanXMin >= xMin && spanXMax <= xMax && - spanY >= yMin && spanY <= yMax)) { - return splashClipPartial; - } - for (i = 0; i < length; ++i) { - if (!scanners[i]->testSpan(xMin, xMax, spanY)) { - return splashClipPartial; - } - } - return splashClipAllInside; -} diff --git a/xpdf/splash/SplashClip.h b/xpdf/splash/SplashClip.h deleted file mode 100644 index 7f302ced6..000000000 --- a/xpdf/splash/SplashClip.h +++ /dev/null @@ -1,97 +0,0 @@ -//======================================================================== -// -// SplashClip.h -// -//======================================================================== - -#ifndef SPLASHCLIP_H -#define SPLASHCLIP_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashTypes.h" - -class SplashPath; -class SplashXPath; -class SplashXPathScanner; - -//------------------------------------------------------------------------ - -enum SplashClipResult { - splashClipAllInside, - splashClipAllOutside, - splashClipPartial -}; - -//------------------------------------------------------------------------ -// SplashClip -//------------------------------------------------------------------------ - -class SplashClip { -public: - - // Create a clip, for the given rectangle. - SplashClip(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1); - - // Copy a clip. - SplashClip *copy() { return new SplashClip(this); } - - ~SplashClip(); - - // Reset the clip to a rectangle. - void resetToRect(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1); - - // Intersect the clip with a rectangle. - SplashError clipToRect(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1); - - // Interesect the clip with . - SplashError clipToPath(SplashPath *path, SplashCoord flatness, - GBool eo); - - // Returns true if (,) is inside the clip. - GBool test(int x, int y); - - // Tests a rectangle against the clipping region. Returns one of: - // - splashClipAllInside if the entire rectangle is inside the - // clipping region, i.e., all pixels in the rectangle are - // visible - // - splashClipAllOutside if the entire rectangle is outside the - // clipping region, i.e., all the pixels in the rectangle are - // clipped - // - splashClipPartial if the rectangle is part inside and part - // outside the clipping region - SplashClipResult testRect(int rectXMin, int rectYMin, - int rectXMax, int rectYMax); - - // Similar to testRect, but tests a horizontal span. - SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY); - - // Get the rectangle part of the clip region. - int getXMin() { return xMin; } - int getXMax() { return xMax; } - int getYMin() { return yMin; } - int getYMax() { return yMax; } - - // Get the number of arbitrary paths used by the clip region. - int getNumPaths() { return length; } - -private: - - SplashClip(SplashClip *clip); - void grow(int nPaths); - - int xMin, yMin, xMax, yMax; - SplashXPath **paths; - Guchar *flags; - SplashXPathScanner **scanners; - int length, size; -}; - -#endif diff --git a/xpdf/splash/SplashErrorCodes.h b/xpdf/splash/SplashErrorCodes.h deleted file mode 100644 index 2a70d4b77..000000000 --- a/xpdf/splash/SplashErrorCodes.h +++ /dev/null @@ -1,32 +0,0 @@ -//======================================================================== -// -// SplashErrorCodes.h -// -//======================================================================== - -#ifndef SPLASHERRORCODES_H -#define SPLASHERRORCODES_H - -#include - -//------------------------------------------------------------------------ - -#define splashOk 0 // no error - -#define splashErrNoCurPt 1 // no current point - -#define splashErrEmptyPath 2 // zero points in path - -#define splashErrBogusPath 3 // only one point in subpath - -#define splashErrNoSave 4 // state stack is empty - -#define splashErrOpenFile 5 // couldn't open file - -#define splashErrNoGlyph 6 // couldn't get the requested glyph - -#define splashErrModeMismatch 7 // invalid combination of color modes - -#define splashErrSingularMatrix 8 // matrix is singular - -#endif diff --git a/xpdf/splash/SplashFTFont.cc b/xpdf/splash/SplashFTFont.cc deleted file mode 100644 index 00946e4db..000000000 --- a/xpdf/splash/SplashFTFont.cc +++ /dev/null @@ -1,346 +0,0 @@ -//======================================================================== -// -// SplashFTFont.cc -// -//======================================================================== - -#include - -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#define MAKE_VERSION( a,b,c ) (((a) << 16) | ((b) << 8) | (c)) - -#define FREETYPE_VERSION \ - MAKE_VERSION(FREETYPE_MAJOR,FREETYPE_MINOR,FREETYPE_PATCH) - -#include -#include FT_OUTLINE_H -#include FT_SIZES_H -#include FT_GLYPH_H -#include "gmem.h" -#include "SplashMath.h" -#include "SplashGlyphBitmap.h" -#include "SplashPath.h" -#include "SplashFTFontEngine.h" -#include "SplashFTFontFile.h" -#include "SplashFTFont.h" - -//------------------------------------------------------------------------ - -#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) ) -static int glyphPathMoveTo(const FT_Vector *pt, void *path); -static int glyphPathLineTo(const FT_Vector *pt, void *path); -static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, void *path); -static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, - const FT_Vector *pt, void *path); -#else -static int glyphPathMoveTo(FT_Vector *pt, void *path); -static int glyphPathLineTo(FT_Vector *pt, void *path); -static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path); -static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, - FT_Vector *pt, void *path); -#endif - -//------------------------------------------------------------------------ -// SplashFTFont -//------------------------------------------------------------------------ - -SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA): - SplashFont(fontFileA, matA, fontFileA->engine->aa) -{ - FT_Face face; - SplashCoord size, div; - int x, y; - - face = fontFileA->face; - if (FT_New_Size(face, &sizeObj)) { - return; - } - face->size = sizeObj; - size = splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]); - if (FT_Set_Pixel_Sizes(face, 0, (int)size)) { - return; - } - - div = face->bbox.xMax > 20000 ? 65536 : 1; - - // transform the four corners of the font bounding box -- the min - // and max values form the bounding box of the transformed font - x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) / - (div * face->units_per_EM)); - xMin = xMax = x; - y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) / - (div * face->units_per_EM)); - yMin = yMax = y; - x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) / - (div * face->units_per_EM)); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) / - (div * face->units_per_EM)); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) / - (div * face->units_per_EM)); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) / - (div * face->units_per_EM)); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) / - (div * face->units_per_EM)); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) / - (div * face->units_per_EM)); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - // This is a kludge: some buggy PDF generators embed fonts with - // zero bounding boxes. - if (xMax == xMin) { - xMin = 0; - xMax = (int)size; - } - if (yMax == yMin) { - yMin = 0; - yMax = (int)((SplashCoord)1.2 * size); - } - - // compute the transform matrix - matrix.xx = (FT_Fixed)((mat[0] / size) * 65536); - matrix.yx = (FT_Fixed)((mat[1] / size) * 65536); - matrix.xy = (FT_Fixed)((mat[2] / size) * 65536); - matrix.yy = (FT_Fixed)((mat[3] / size) * 65536); -} - -SplashFTFont::~SplashFTFont() { -} - -GBool SplashFTFont::getGlyph(int c, int xFrac, int /*yFrac*/, - SplashGlyphBitmap *bitmap) { - return SplashFont::getGlyph(c, xFrac, 0, bitmap); -} - -GBool SplashFTFont::makeGlyph(int c, int xFrac, int /*yFrac*/, - SplashGlyphBitmap *bitmap) { - SplashFTFontFile *ff; - FT_Vector offset; - FT_GlyphSlot slot; - FT_UInt gid; - int rowSize; - Guchar *p, *q; - int i; - - ff = (SplashFTFontFile *)fontFile; - - ff->face->size = sizeObj; - offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64); - offset.y = 0; - FT_Set_Transform(ff->face, &matrix, &offset); - slot = ff->face->glyph; - - if (ff->codeToGID && c < ff->codeToGIDLen) { - gid = (FT_UInt)ff->codeToGID[c]; - } else { - gid = (FT_UInt)c; - } - - // if we have the FT2 bytecode interpreter, autohinting won't be used -#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER - if (FT_Load_Glyph(ff->face, gid, - aa ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT)) { - return gFalse; - } -#else - // FT2's autohinting doesn't always work very well (especially with - // font subsets), so turn it off if anti-aliasing is enabled; if - // anti-aliasing is disabled, this seems to be a tossup - some fonts - // look better with hinting, some without, so leave hinting on - if (FT_Load_Glyph(ff->face, gid, - aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP - : FT_LOAD_DEFAULT)) { - return gFalse; - } -#endif - if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal - : ft_render_mode_mono)) { - return gFalse; - } - - bitmap->x = -slot->bitmap_left; - bitmap->y = slot->bitmap_top; - bitmap->w = slot->bitmap.width; - bitmap->h = slot->bitmap.rows; - bitmap->aa = aa; - if (aa) { - rowSize = bitmap->w; - } else { - rowSize = (bitmap->w + 7) >> 3; - } - bitmap->data = (Guchar *)gmalloc(rowSize * bitmap->h); - bitmap->freeData = gTrue; - for (i = 0, p = bitmap->data, q = slot->bitmap.buffer; - i < bitmap->h; - ++i, p += rowSize, q += slot->bitmap.pitch) { - memcpy(p, q, rowSize); - } - - return gTrue; -} - -struct SplashFTFontPath { - SplashPath *path; - GBool needClose; -}; - -SplashPath *SplashFTFont::getGlyphPath(int c) { - static FT_Outline_Funcs outlineFuncs = { - &glyphPathMoveTo, - &glyphPathLineTo, - &glyphPathConicTo, - &glyphPathCubicTo, - 0, 0 - }; - SplashFTFontFile *ff; - SplashFTFontPath path; - FT_GlyphSlot slot; - FT_UInt gid; - FT_Glyph glyph; - - ff = (SplashFTFontFile *)fontFile; - ff->face->size = sizeObj; - FT_Set_Transform(ff->face, &matrix, NULL); - slot = ff->face->glyph; - if (ff->codeToGID && c < ff->codeToGIDLen) { - gid = ff->codeToGID[c]; - } else { - gid = (FT_UInt)c; - } - if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) { - return NULL; - } - if (FT_Get_Glyph(slot, &glyph)) { - return NULL; - } - path.path = new SplashPath(); - path.needClose = gFalse; - FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, - &outlineFuncs, &path); - if (path.needClose) { - path.path->close(); - } - FT_Done_Glyph(glyph); - return path.path; -} - -#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) ) -static int glyphPathMoveTo(const FT_Vector *pt, void *path) -#else -static int glyphPathMoveTo(FT_Vector *pt, void *path) -#endif -{ - SplashFTFontPath *p = (SplashFTFontPath *)path; - - if (p->needClose) { - p->path->close(); - p->needClose = gFalse; - } - p->path->moveTo(pt->x / 64.0, -pt->y / 64.0); - return 0; -} - -#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) ) -static int glyphPathLineTo(const FT_Vector *pt, void *path) -#else -static int glyphPathLineTo(FT_Vector *pt, void *path) -#endif -{ - SplashFTFontPath *p = (SplashFTFontPath *)path; - - p->path->lineTo(pt->x / 64.0, -pt->y / 64.0); - p->needClose = gTrue; - return 0; -} - -#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) ) -static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, void *path) -#else -static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path) -#endif -{ - SplashFTFontPath *p = (SplashFTFontPath *)path; - SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc; - - if (!p->path->getCurPt(&x0, &y0)) { - return 0; - } - xc = ctrl->x / 64.0; - yc = -ctrl->y / 64.0; - x3 = pt->x / 64.0; - y3 = -pt->y / 64.0; - - // A second-order Bezier curve is defined by two endpoints, p0 and - // p3, and one control point, pc: - // - // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3 - // - // A third-order Bezier curve is defined by the same two endpoints, - // p0 and p3, and two control points, p1 and p2: - // - // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3 - // - // Applying some algebra, we can convert a second-order curve to a - // third-order curve: - // - // p1 = (1/3) * (p0 + 2pc) - // p2 = (1/3) * (2pc + p3) - - x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc); - y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc); - x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3); - y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3); - - p->path->curveTo(x1, y1, x2, y2, x3, y3); - p->needClose = gTrue; - return 0; -} - -#if ( FREETYPE_VERSION >= MAKE_VERSION(2,2,0) ) -static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, const FT_Vector *pt, void *path) -#else -static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, FT_Vector *pt, void *path) -#endif -{ - SplashFTFontPath *p = (SplashFTFontPath *)path; - - p->path->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0, - ctrl2->x / 64.0, -ctrl2->y / 64.0, - pt->x / 64.0, -pt->y / 64.0); - p->needClose = gTrue; - return 0; -} - -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/xpdf/splash/SplashFTFont.h b/xpdf/splash/SplashFTFont.h deleted file mode 100644 index efd0eda7b..000000000 --- a/xpdf/splash/SplashFTFont.h +++ /dev/null @@ -1,55 +0,0 @@ -//======================================================================== -// -// SplashFTFont.h -// -//======================================================================== - -#ifndef SPLASHFTFONT_H -#define SPLASHFTFONT_H - -#include - -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include FT_FREETYPE_H -#include "SplashFont.h" - -class SplashFTFontFile; - -//------------------------------------------------------------------------ -// SplashFTFont -//------------------------------------------------------------------------ - -class SplashFTFont: public SplashFont { -public: - - SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA); - - virtual ~SplashFTFont(); - - // Munge xFrac and yFrac before calling SplashFont::getGlyph. - virtual GBool getGlyph(int c, int xFrac, int yFrac, - SplashGlyphBitmap *bitmap); - - // Rasterize a glyph. The and values are the same - // as described for getGlyph. - virtual GBool makeGlyph(int c, int xFrac, int yFrac, - SplashGlyphBitmap *bitmap); - - // Return the path for a glyph. - virtual SplashPath *getGlyphPath(int c); - -private: - - FT_Size sizeObj; - FT_Matrix matrix; -}; - -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - -#endif diff --git a/xpdf/splash/SplashFTFontEngine.cc b/xpdf/splash/SplashFTFontEngine.cc deleted file mode 100644 index 6c9ba337d..000000000 --- a/xpdf/splash/SplashFTFontEngine.cc +++ /dev/null @@ -1,161 +0,0 @@ -//======================================================================== -// -// SplashFTFontEngine.cc -// -//======================================================================== - -#include - -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#ifndef WIN32 -# include -#endif -#include "gmem.h" -#include "GString.h" -#include "gfile.h" -#include "FoFiTrueType.h" -#include "FoFiType1C.h" -#include "SplashFTFontFile.h" -#include "SplashFTFontEngine.h" - -#ifdef VMS -#if (__VMS_VER < 70000000) -extern "C" int unlink(char *filename); -#endif -#endif - -//------------------------------------------------------------------------ - -#if 0 -static void FT_fileWrite(void *stream, const char *data, int len) { - fwrite(data, 1, len, (FILE *)stream); -} -#endif - -//------------------------------------------------------------------------ -// SplashFTFontEngine -//------------------------------------------------------------------------ - -SplashFTFontEngine::SplashFTFontEngine(GBool aaA, FT_Library libA) { - FT_Int major, minor, patch; - - aa = aaA; - lib = libA; - - // as of FT 2.1.8, CID fonts are indexed by CID instead of GID - FT_Library_Version(lib, &major, &minor, &patch); - useCIDs = major > 2 || - (major == 2 && (minor > 1 || (minor == 1 && patch > 7))); -} - -SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA) { - FT_Library libA; - - if (FT_Init_FreeType(&libA)) { - return NULL; - } - return new SplashFTFontEngine(aaA, libA); -} - -SplashFTFontEngine::~SplashFTFontEngine() { - FT_Done_FreeType(lib); -} - -SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA, - SplashFontSrc *src, - const char **enc) { - return SplashFTFontFile::loadType1Font(this, idA, src, enc); -} - -SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, - SplashFontSrc *src, - const char **enc) { - return SplashFTFontFile::loadType1Font(this, idA, src, enc); -} - -SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, - SplashFontSrc *src) { - Gushort *cidToGIDMap; - int nCIDs; - SplashFontFile *ret; - - // check for a CFF font - if (!useCIDs) - { - FoFiType1C *ff; - if (src->isFile) { - ff = FoFiType1C::load(src->fileName->getCString()); - } else { - ff = new FoFiType1C(src->buf, src->bufLen, gFalse); - } - if (ff) { - cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); - delete ff; - } else { - cidToGIDMap = NULL; - nCIDs = 0; - } - } - else - { - // Freetype 2.1.8 and up treats all CID fonts the same way - cidToGIDMap = NULL; - nCIDs = 0; - } - ret = SplashFTFontFile::loadCIDFont(this, idA, src, cidToGIDMap, nCIDs); - if (!ret) { - gfree(cidToGIDMap); - } - return ret; -} - -SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, - SplashFontSrc *src, - Gushort *codeToGID, - int codeToGIDLen, - int faceIndex) { -#if 0 - FoFiTrueType *ff; - GString *tmpFileName; - FILE *tmpFile; - SplashFontFile *ret; - - if (!(ff = FoFiTrueType::load(fileName, faceIndex))) { - return NULL; - } - tmpFileName = NULL; - if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { - delete ff; - return NULL; - } - ff->writeTTF(&FT_fileWrite, tmpFile); - delete ff; - fclose(tmpFile); - ret = SplashFTFontFile::loadTrueTypeFont(this, idA, - tmpFileName->getCString(), - gTrue, codeToGID, codeToGIDLen, - faceIndex); - if (ret) { - if (deleteFile) { - unlink(fileName); - } - } else { - unlink(tmpFileName->getCString()); - } - delete tmpFileName; - return ret; -#else - SplashFontFile *ret; - ret = SplashFTFontFile::loadTrueTypeFont(this, idA, src, - codeToGID, codeToGIDLen, - faceIndex); - return ret; -#endif -} - -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/xpdf/splash/SplashFTFontEngine.h b/xpdf/splash/SplashFTFontEngine.h deleted file mode 100644 index 05dc94bf0..000000000 --- a/xpdf/splash/SplashFTFontEngine.h +++ /dev/null @@ -1,59 +0,0 @@ -//======================================================================== -// -// SplashFTFontEngine.h -// -//======================================================================== - -#ifndef SPLASHFTFONTENGINE_H -#define SPLASHFTFONTENGINE_H - -#include - -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include FT_FREETYPE_H -#include "gtypes.h" - -class SplashFontFile; -class SplashFontFileID; -class SplashFontSrc; - -//------------------------------------------------------------------------ -// SplashFTFontEngine -//------------------------------------------------------------------------ - -class SplashFTFontEngine { -public: - - static SplashFTFontEngine *init(GBool aaA); - - ~SplashFTFontEngine(); - - // Load fonts. - SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); - SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); - SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src); - SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, - Gushort *codeToGID, int codeToGIDLen, - int faceIndex=0); - -private: - - SplashFTFontEngine(GBool aaA, FT_Library libA); - - GBool aa; - FT_Library lib; - GBool useCIDs; - - friend class SplashFTFontFile; - friend class SplashFTFont; -}; - -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - -#endif diff --git a/xpdf/splash/SplashFTFontFile.cc b/xpdf/splash/SplashFTFontFile.cc deleted file mode 100644 index 043903547..000000000 --- a/xpdf/splash/SplashFTFontFile.cc +++ /dev/null @@ -1,122 +0,0 @@ -//======================================================================== -// -// SplashFTFontFile.cc -// -//======================================================================== - -#include - -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "gmem.h" -#include "SplashFTFontEngine.h" -#include "SplashFTFont.h" -#include "SplashFTFontFile.h" -#include "GString.h" - -//------------------------------------------------------------------------ -// SplashFTFontFile -//------------------------------------------------------------------------ - -SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *src, - const char **encA) { - FT_Face faceA; - Gushort *codeToGIDA; - const char *name; - int i; - - if (src->isFile) { - if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA)) - return NULL; - } else { - if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA)) - return NULL; - } - codeToGIDA = (Gushort *)gmallocn(256, sizeof(int)); - for (i = 0; i < 256; ++i) { - codeToGIDA[i] = 0; - if ((name = encA[i])) { - codeToGIDA[i] = (Gushort)FT_Get_Name_Index(faceA, (char*)name); - } - } - - return new SplashFTFontFile(engineA, idA, src, - faceA, codeToGIDA, 256); -} - -SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *src, - Gushort *codeToGIDA, - int codeToGIDLenA) { - FT_Face faceA; - - if (src->isFile) { - if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA)) - return NULL; - } else { - if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA)) - return NULL; - } - - return new SplashFTFontFile(engineA, idA, src, - faceA, codeToGIDA, codeToGIDLenA); -} - -SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *src, - Gushort *codeToGIDA, - int codeToGIDLenA, - int faceIndexA) { - FT_Face faceA; - - if (src->isFile) { - if (FT_New_Face(engineA->lib, src->fileName->getCString(), faceIndexA, &faceA)) - return NULL; - } else { - if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, faceIndexA, &faceA)) - return NULL; - } - - return new SplashFTFontFile(engineA, idA, src, - faceA, codeToGIDA, codeToGIDLenA); -} - -SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *srcA, - FT_Face faceA, - Gushort *codeToGIDA, int codeToGIDLenA): - SplashFontFile(idA, srcA) -{ - engine = engineA; - face = faceA; - codeToGID = codeToGIDA; - codeToGIDLen = codeToGIDLenA; -} - -SplashFTFontFile::~SplashFTFontFile() { - if (face) { - FT_Done_Face(face); - } - if (codeToGID) { - gfree(codeToGID); - } -} - -SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat) { - SplashFont *font; - - font = new SplashFTFont(this, mat); - font->initCache(); - return font; -} - -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/xpdf/splash/SplashFTFontFile.h b/xpdf/splash/SplashFTFontFile.h deleted file mode 100644 index 91fed355c..000000000 --- a/xpdf/splash/SplashFTFontFile.h +++ /dev/null @@ -1,70 +0,0 @@ -//======================================================================== -// -// SplashFTFontFile.h -// -//======================================================================== - -#ifndef SPLASHFTFONTFILE_H -#define SPLASHFTFONTFILE_H - -#include - -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include FT_FREETYPE_H -#include "SplashFontFile.h" - -class SplashFontFileID; -class SplashFTFontEngine; - -//------------------------------------------------------------------------ -// SplashFTFontFile -//------------------------------------------------------------------------ - -class SplashFTFontFile: public SplashFontFile { -public: - - static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *src, const char **encA); - static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *src, - Gushort *codeToCIDA, int codeToGIDLenA); - static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *src, - Gushort *codeToGIDA, - int codeToGIDLenA, - int faceIndexA=0); - - virtual ~SplashFTFontFile(); - - // Create a new SplashFTFont, i.e., a scaled instance of this font - // file. - virtual SplashFont *makeFont(SplashCoord *mat); - -private: - - SplashFTFontFile(SplashFTFontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *srcA, - FT_Face faceA, - Gushort *codeToGIDA, int codeToGIDLenA); - - SplashFTFontEngine *engine; - FT_Face face; - Gushort *codeToGID; - int codeToGIDLen; - - friend class SplashFTFont; -}; - -#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - -#endif diff --git a/xpdf/splash/SplashFont.cc b/xpdf/splash/SplashFont.cc deleted file mode 100644 index 8db3c51d5..000000000 --- a/xpdf/splash/SplashFont.cc +++ /dev/null @@ -1,172 +0,0 @@ -//======================================================================== -// -// SplashFont.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "SplashMath.h" -#include "SplashGlyphBitmap.h" -#include "SplashFontFile.h" -#include "SplashFont.h" - -//------------------------------------------------------------------------ - -struct SplashFontCacheTag { - int c; - short xFrac, yFrac; // x and y fractions - int mru; // valid bit (0x80000000) and MRU index - int x, y, w, h; // offset and size of glyph -}; - -//------------------------------------------------------------------------ -// SplashFont -//------------------------------------------------------------------------ - -SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, - GBool aaA) { - fontFile = fontFileA; - fontFile->incRefCnt(); - mat[0] = matA[0]; - mat[1] = matA[1]; - mat[2] = matA[2]; - mat[3] = matA[3]; - aa = aaA; - - cache = NULL; - cacheTags = NULL; - - xMin = yMin = xMax = yMax = 0; -} - -void SplashFont::initCache() { - int i; - - // this should be (max - min + 1), but we add some padding to - // deal with rounding errors - glyphW = xMax - xMin + 3; - glyphH = yMax - yMin + 3; - if (aa) { - glyphSize = glyphW * glyphH; - } else { - glyphSize = ((glyphW + 7) >> 3) * glyphH; - } - - // set up the glyph pixmap cache - cacheAssoc = 8; - if (glyphSize <= 256) { - cacheSets = 8; - } else if (glyphSize <= 512) { - cacheSets = 4; - } else if (glyphSize <= 1024) { - cacheSets = 2; - } else { - cacheSets = 1; - } - cache = (Guchar *)gmallocn(cacheSets* cacheAssoc, glyphSize); - cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, - sizeof(SplashFontCacheTag)); - for (i = 0; i < cacheSets * cacheAssoc; ++i) { - cacheTags[i].mru = i & (cacheAssoc - 1); - } -} - -SplashFont::~SplashFont() { - fontFile->decRefCnt(); - if (cache) { - gfree(cache); - } - if (cacheTags) { - gfree(cacheTags); - } -} - -GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, - SplashGlyphBitmap *bitmap) { - SplashGlyphBitmap bitmap2; - int size; - Guchar *p; - int i, j, k; - - // no fractional coordinates for large glyphs or non-anti-aliased - // glyphs - if (!aa || glyphH > 50) { - xFrac = yFrac = 0; - } - - // check the cache - i = (c & (cacheSets - 1)) * cacheAssoc; - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x80000000) && - cacheTags[i+j].c == c && - (int)cacheTags[i+j].xFrac == xFrac && - (int)cacheTags[i+j].yFrac == yFrac) { - bitmap->x = cacheTags[i+j].x; - bitmap->y = cacheTags[i+j].y; - bitmap->w = cacheTags[i+j].w; - bitmap->h = cacheTags[i+j].h; - for (k = 0; k < cacheAssoc; ++k) { - if (k != j && - (cacheTags[i+k].mru & 0x7fffffff) < - (cacheTags[i+j].mru & 0x7fffffff)) { - ++cacheTags[i+k].mru; - } - } - cacheTags[i+j].mru = 0x80000000; - bitmap->aa = aa; - bitmap->data = cache + (i+j) * glyphSize; - bitmap->freeData = gFalse; - return gTrue; - } - } - - // generate the glyph bitmap - if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) { - return gFalse; - } - - // if the glyph doesn't fit in the bounding box, return a temporary - // uncached bitmap - if (bitmap2.w > glyphW || bitmap2.h > glyphH) { - *bitmap = bitmap2; - return gTrue; - } - - // insert glyph pixmap in cache - if (aa) { - size = bitmap2.w * bitmap2.h; - } else { - size = ((bitmap2.w + 7) >> 3) * bitmap2.h; - } - p = NULL; // make gcc happy - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) { - cacheTags[i+j].mru = 0x80000000; - cacheTags[i+j].c = c; - cacheTags[i+j].xFrac = (short)xFrac; - cacheTags[i+j].yFrac = (short)yFrac; - cacheTags[i+j].x = bitmap2.x; - cacheTags[i+j].y = bitmap2.y; - cacheTags[i+j].w = bitmap2.w; - cacheTags[i+j].h = bitmap2.h; - p = cache + (i+j) * glyphSize; - memcpy(p, bitmap2.data, size); - } else { - ++cacheTags[i+j].mru; - } - } - *bitmap = bitmap2; - bitmap->data = p; - bitmap->freeData = gFalse; - if (bitmap2.freeData) { - gfree(bitmap2.data); - } - return gTrue; -} diff --git a/xpdf/splash/SplashFont.h b/xpdf/splash/SplashFont.h deleted file mode 100644 index 980154d65..000000000 --- a/xpdf/splash/SplashFont.h +++ /dev/null @@ -1,97 +0,0 @@ -//======================================================================== -// -// SplashFont.h -// -//======================================================================== - -#ifndef SPLASHFONT_H -#define SPLASHFONT_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "SplashTypes.h" - -struct SplashGlyphBitmap; -struct SplashFontCacheTag; -class SplashFontFile; -class SplashPath; - -//------------------------------------------------------------------------ - -// Fractional positioning uses this many bits to the right of the -// decimal points. -#define splashFontFractionBits 2 -#define splashFontFraction (1 << splashFontFractionBits) -#define splashFontFractionMul \ - ((SplashCoord)1 / (SplashCoord)splashFontFraction) - -//------------------------------------------------------------------------ -// SplashFont -//------------------------------------------------------------------------ - -class SplashFont { -public: - - SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, GBool aaA); - - // This must be called after the constructor, so that the subclass - // constructor has a chance to compute the bbox. - void initCache(); - - virtual ~SplashFont(); - - SplashFontFile *getFontFile() { return fontFile; } - - // Return true if matches the specified font file and matrix. - GBool matches(SplashFontFile *fontFileA, SplashCoord *matA) { - return fontFileA == fontFile && - matA[0] == mat[0] && matA[1] == mat[1] && - matA[2] == mat[2] && matA[3] == mat[3]; - } - - // Get a glyph - this does a cache lookup first, and if not found, - // creates a new bitmap and adds it to the cache. The and - // values are splashFontFractionBits bits each, representing - // the numerators of fractions in [0, 1), where the denominator is - // splashFontFraction = 1 << splashFontFractionBits. Subclasses - // should override this to zero out xFrac and/or yFrac if they don't - // support fractional coordinates. - virtual GBool getGlyph(int c, int xFrac, int yFrac, - SplashGlyphBitmap *bitmap); - - // Rasterize a glyph. The and values are the same - // as described for getGlyph. - virtual GBool makeGlyph(int c, int xFrac, int yFrac, - SplashGlyphBitmap *bitmap) = 0; - - // Return the path for a glyph. - virtual SplashPath *getGlyphPath(int c) = 0; - - // Return the font transform matrix. - SplashCoord *getMatrix() { return mat; } - - // Return the glyph bounding box. - void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) - { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } - -protected: - - SplashFontFile *fontFile; - SplashCoord mat[4]; // font transform matrix - GBool aa; // anti-aliasing - int xMin, yMin, xMax, yMax; // glyph bounding box - Guchar *cache; // glyph bitmap cache - SplashFontCacheTag * // cache tags - cacheTags; - int glyphW, glyphH; // size of glyph bitmaps - int glyphSize; // size of glyph bitmaps, in bytes - int cacheSets; // number of sets in cache - int cacheAssoc; // cache associativity (glyphs per set) -}; - -#endif diff --git a/xpdf/splash/SplashFontEngine.cc b/xpdf/splash/SplashFontEngine.cc deleted file mode 100644 index a655c55f0..000000000 --- a/xpdf/splash/SplashFontEngine.cc +++ /dev/null @@ -1,229 +0,0 @@ -//======================================================================== -// -// SplashFontEngine.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#if HAVE_T1LIB_H -#include -#endif - -#include -#include -#ifndef WIN32 -# include -#endif -#include "gmem.h" -#include "GString.h" -#include "SplashT1FontEngine.h" -#include "SplashFTFontEngine.h" -#include "SplashFontFile.h" -#include "SplashFontFileID.h" -#include "SplashFont.h" -#include "SplashFontEngine.h" - -//------------------------------------------------------------------------ -// SplashFontEngine -//------------------------------------------------------------------------ - -SplashFontEngine::SplashFontEngine( -#if HAVE_T1LIB_H - GBool enableT1lib, -#endif -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - GBool enableFreeType, -#endif - GBool aa) { - int i; - - for (i = 0; i < splashFontCacheSize; ++i) { - fontCache[i] = NULL; - } - -#if HAVE_T1LIB_H - if (enableT1lib) { - t1Engine = SplashT1FontEngine::init(aa); - } else { - t1Engine = NULL; - } -#endif -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - if (enableFreeType) { - ftEngine = SplashFTFontEngine::init(aa); - } else { - ftEngine = NULL; - } -#endif -} - -SplashFontEngine::~SplashFontEngine() { - int i; - - for (i = 0; i < splashFontCacheSize; ++i) { - if (fontCache[i]) { - delete fontCache[i]; - } - } - -#if HAVE_T1LIB_H - if (t1Engine) { - delete t1Engine; - } -#endif -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - if (ftEngine) { - delete ftEngine; - } -#endif -} - -SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) { - SplashFontFile *fontFile; - int i; - - for (i = 0; i < splashFontCacheSize; ++i) { - if (fontCache[i]) { - fontFile = fontCache[i]->getFontFile(); - if (fontFile && fontFile->getID()->matches(id)) { - return fontFile; - } - } - } - return NULL; -} - -SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA, - SplashFontSrc *src, - const char **enc) { - SplashFontFile *fontFile; - - fontFile = NULL; -#if HAVE_T1LIB_H - if (!fontFile && t1Engine) { - fontFile = t1Engine->loadType1Font(idA, src, enc); - } -#endif -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - if (!fontFile && ftEngine) { - fontFile = ftEngine->loadType1Font(idA, src, enc); - } -#endif - - // delete the (temporary) font file -- with Unix hard link - // semantics, this will remove the last link; otherwise it will - // return an error, leaving the file to be deleted later (if - // loadXYZFont failed, the file will always be deleted) - src->unref(); - - return fontFile; -} - -SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, - SplashFontSrc *src, - const char **enc) { - SplashFontFile *fontFile; - - fontFile = NULL; -#if HAVE_T1LIB_H - if (!fontFile && t1Engine) { - fontFile = t1Engine->loadType1CFont(idA, src, enc); - } -#endif -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - if (!fontFile && ftEngine) { - fontFile = ftEngine->loadType1CFont(idA, src, enc); - } -#endif - - // delete the (temporary) font file -- with Unix hard link - // semantics, this will remove the last link; otherwise it will - // return an error, leaving the file to be deleted later (if - // loadXYZFont failed, the file will always be deleted) - src->unref(); - - return fontFile; -} - -SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, - SplashFontSrc *src) { - SplashFontFile *fontFile; - - fontFile = NULL; -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - if (!fontFile && ftEngine) { - fontFile = ftEngine->loadCIDFont(idA, src); - } -#endif - - // delete the (temporary) font file -- with Unix hard link - // semantics, this will remove the last link; otherwise it will - // return an error, leaving the file to be deleted later (if - // loadXYZFont failed, the file will always be deleted) - src->unref(); - - return fontFile; -} - -SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, - SplashFontSrc *src, - Gushort *codeToGID, - int codeToGIDLen, - int faceIndex) { - SplashFontFile *fontFile; - - fontFile = NULL; -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - if (!fontFile && ftEngine) { - fontFile = ftEngine->loadTrueTypeFont(idA, src, - codeToGID, codeToGIDLen, faceIndex); - } -#endif - - if (!fontFile) { - gfree(codeToGID); - } - - // delete the (temporary) font file -- with Unix hard link - // semantics, this will remove the last link; otherwise it will - // return an error, leaving the file to be deleted later (if - // loadXYZFont failed, the file will always be deleted) - src->unref(); - - return fontFile; -} - -SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile, - SplashCoord *mat) { - SplashFont *font; - int i, j; - - font = fontCache[0]; - if (font && font->matches(fontFile, mat)) { - return font; - } - for (i = 1; i < splashFontCacheSize; ++i) { - font = fontCache[i]; - if (font && font->matches(fontFile, mat)) { - for (j = i; j > 0; --j) { - fontCache[j] = fontCache[j-1]; - } - fontCache[0] = font; - return font; - } - } - font = fontFile->makeFont(mat); - if (fontCache[splashFontCacheSize - 1]) { - delete fontCache[splashFontCacheSize - 1]; - } - for (j = splashFontCacheSize - 1; j > 0; --j) { - fontCache[j] = fontCache[j-1]; - } - fontCache[0] = font; - return font; -} diff --git a/xpdf/splash/SplashFontEngine.h b/xpdf/splash/SplashFontEngine.h deleted file mode 100644 index ccc2105c1..000000000 --- a/xpdf/splash/SplashFontEngine.h +++ /dev/null @@ -1,83 +0,0 @@ -//======================================================================== -// -// SplashFontEngine.h -// -//======================================================================== - -#ifndef SPLASHFONTENGINE_H -#define SPLASHFONTENGINE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -class SplashT1FontEngine; -class SplashFTFontEngine; -class SplashDTFontEngine; -class SplashFontFile; -class SplashFontFileID; -class SplashFont; -class SplashFontSrc; - -//------------------------------------------------------------------------ - -#define splashFontCacheSize 16 - -//------------------------------------------------------------------------ -// SplashFontEngine -//------------------------------------------------------------------------ - -class SplashFontEngine { -public: - - // Create a font engine. - SplashFontEngine( -#if HAVE_T1LIB_H - GBool enableT1lib, -#endif -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - GBool enableFreeType, -#endif - GBool aa); - - ~SplashFontEngine(); - - // Get a font file from the cache. Returns NULL if there is no - // matching entry in the cache. - SplashFontFile *getFontFile(SplashFontFileID *id); - - // Load fonts - these create new SplashFontFile objects. - SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); - SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc); - SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src); - SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, - Gushort *codeToGID, int codeToGIDLen, - int faceIndex=0); - - // Get a font - this does a cache lookup first, and if not found, - // creates a new SplashFont object and adds it to the cache. The - // matrix: - // [ mat[0] mat[1] ] - // [ mat[2] mat[3] ] - // specifies the font transform in PostScript style: - // [x' y'] = [x y] * mat - // Note that the Splash y axis points downward. - SplashFont *getFont(SplashFontFile *fontFile, SplashCoord *mat); - -private: - - SplashFont *fontCache[splashFontCacheSize]; - -#if HAVE_T1LIB_H - SplashT1FontEngine *t1Engine; -#endif -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - SplashFTFontEngine *ftEngine; -#endif -}; - -#endif diff --git a/xpdf/splash/SplashFontFile.cc b/xpdf/splash/SplashFontFile.cc deleted file mode 100644 index 6cc0dadcc..000000000 --- a/xpdf/splash/SplashFontFile.cc +++ /dev/null @@ -1,109 +0,0 @@ -//======================================================================== -// -// SplashFontFile.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#ifndef WIN32 -# include -#endif -#include "GString.h" -#include "SplashFontFile.h" -#include "SplashFontFileID.h" -#include "gmem.h" - -#ifdef VMS -#if (__VMS_VER < 70000000) -extern "C" int unlink(char *filename); -#endif -#endif - -//------------------------------------------------------------------------ -// SplashFontFile -//------------------------------------------------------------------------ - -SplashFontFile::SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA) { - id = idA; - src = srcA; - src->ref(); - refCnt = 0; -} - -SplashFontFile::~SplashFontFile() { - src->unref(); - delete id; -} - -void SplashFontFile::incRefCnt() { - ++refCnt; -} - -void SplashFontFile::decRefCnt() { - if (!--refCnt) { - delete this; - } -} - -// - -SplashFontSrc::SplashFontSrc() { - isFile = gFalse; - deleteSrc = gFalse; - fileName = NULL; - buf = NULL; - refcnt = 1; -} - -SplashFontSrc::~SplashFontSrc() { - if (deleteSrc) { - if (isFile) { - if (fileName) - unlink(fileName->getCString()); - } else { - if (buf) - gfree(buf); - } - } - - if (isFile && fileName) - delete fileName; -} - -void SplashFontSrc::ref() { - refcnt++; -} - -void SplashFontSrc::unref() { - if (! --refcnt) - delete this; -} - -void SplashFontSrc::setFile(GString *file, GBool del) -{ - isFile = gTrue; - fileName = file->copy(); - deleteSrc = del; -} - -void SplashFontSrc::setFile(const char *file, GBool del) -{ - isFile = gTrue; - fileName = new GString(file); - deleteSrc = del; -} - -void SplashFontSrc::setBuf(char *bufA, int bufLenA, GBool del) -{ - isFile = gFalse; - buf = bufA; - bufLen = bufLenA; - deleteSrc = del; -} - diff --git a/xpdf/splash/SplashFontFile.h b/xpdf/splash/SplashFontFile.h deleted file mode 100644 index 0ab0a3e85..000000000 --- a/xpdf/splash/SplashFontFile.h +++ /dev/null @@ -1,77 +0,0 @@ -//======================================================================== -// -// SplashFontFile.h -// -//======================================================================== - -#ifndef SPLASHFONTFILE_H -#define SPLASHFONTFILE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "SplashTypes.h" - -class GString; -class SplashFontEngine; -class SplashFont; -class SplashFontFileID; - -//------------------------------------------------------------------------ -// SplashFontFile -//------------------------------------------------------------------------ - -struct SplashFontSrc { - SplashFontSrc(); - ~SplashFontSrc(); - - void setFile(GString *file, GBool del); - void setFile(const char *file, GBool del); - void setBuf(char *bufA, int buflenA, GBool del); - - void ref(); - void unref(); - - GBool isFile; - GString *fileName; - char *buf; - int bufLen; - GBool deleteSrc; - int refcnt; -}; - -class SplashFontFile { -public: - - virtual ~SplashFontFile(); - - // Create a new SplashFont, i.e., a scaled instance of this font - // file. - virtual SplashFont *makeFont(SplashCoord *mat) = 0; - - // Get the font file ID. - SplashFontFileID *getID() { return id; } - - // Increment the reference count. - void incRefCnt(); - - // Decrement the reference count. If the new value is zero, delete - // the SplashFontFile object. - void decRefCnt(); - -protected: - - SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA); - - SplashFontFileID *id; - SplashFontSrc *src; - int refCnt; - - friend class SplashFontEngine; -}; - -#endif diff --git a/xpdf/splash/SplashFontFileID.cc b/xpdf/splash/SplashFontFileID.cc deleted file mode 100644 index af37cb2fd..000000000 --- a/xpdf/splash/SplashFontFileID.cc +++ /dev/null @@ -1,23 +0,0 @@ -//======================================================================== -// -// SplashFontFileID.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "SplashFontFileID.h" - -//------------------------------------------------------------------------ -// SplashFontFileID -//------------------------------------------------------------------------ - -SplashFontFileID::SplashFontFileID() { -} - -SplashFontFileID::~SplashFontFileID() { -} diff --git a/xpdf/splash/SplashFontFileID.h b/xpdf/splash/SplashFontFileID.h deleted file mode 100644 index bed11d336..000000000 --- a/xpdf/splash/SplashFontFileID.h +++ /dev/null @@ -1,30 +0,0 @@ -//======================================================================== -// -// SplashFontFileID.h -// -//======================================================================== - -#ifndef SPLASHFONTFILEID_H -#define SPLASHFONTFILEID_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -//------------------------------------------------------------------------ -// SplashFontFileID -//------------------------------------------------------------------------ - -class SplashFontFileID { -public: - - SplashFontFileID(); - virtual ~SplashFontFileID(); - virtual GBool matches(SplashFontFileID *id) = 0; -}; - -#endif diff --git a/xpdf/splash/SplashGlyphBitmap.h b/xpdf/splash/SplashGlyphBitmap.h deleted file mode 100644 index 044ba4a66..000000000 --- a/xpdf/splash/SplashGlyphBitmap.h +++ /dev/null @@ -1,26 +0,0 @@ -//======================================================================== -// -// SplashGlyphBitmap.h -// -//======================================================================== - -#ifndef SPLASHGLYPHBITMAP_H -#define SPLASHGLYPHBITMAP_H - -#include - -#include "gtypes.h" - -//------------------------------------------------------------------------ -// SplashGlyphBitmap -//------------------------------------------------------------------------ - -struct SplashGlyphBitmap { - int x, y, w, h; // offset and size of glyph - GBool aa; // anti-aliased: true means 8-bit alpha - // bitmap; false means 1-bit - Guchar *data; // bitmap data - GBool freeData; // true if data memory should be freed -}; - -#endif diff --git a/xpdf/splash/SplashMath.h b/xpdf/splash/SplashMath.h deleted file mode 100644 index f1bde145b..000000000 --- a/xpdf/splash/SplashMath.h +++ /dev/null @@ -1,46 +0,0 @@ -//======================================================================== -// -// SplashMath.h -// -//======================================================================== - -#ifndef SPLASHMATH_H -#define SPLASHMATH_H - -#include -#include -#include "SplashTypes.h" - -static inline SplashCoord splashAbs(SplashCoord x) { - return fabs(x); -} - -static inline int splashFloor(SplashCoord x) { - return (int)floor(x); -} - -static inline int splashCeil(SplashCoord x) { - return (int)ceil(x); -} - -static inline int splashRound(SplashCoord x) { - return (int)floor(x + 0.5); -} - -static inline SplashCoord splashSqrt(SplashCoord x) { - return sqrt(x); -} - -static inline SplashCoord splashPow(SplashCoord x, SplashCoord y) { - return pow(x, y); -} - -static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1) { - SplashCoord dx, dy; - dx = x1 - x0; - dy = y1 - y0; - return sqrt(dx * dx + dy * dy); -} - -#endif diff --git a/xpdf/splash/SplashPath.cc b/xpdf/splash/SplashPath.cc deleted file mode 100644 index 12f79b7e5..000000000 --- a/xpdf/splash/SplashPath.cc +++ /dev/null @@ -1,178 +0,0 @@ -//======================================================================== -// -// SplashPath.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "SplashErrorCodes.h" -#include "SplashPath.h" - -//------------------------------------------------------------------------ -// SplashPath -//------------------------------------------------------------------------ - -// A path can be in three possible states: -// -// 1. no current point -- zero or more finished subpaths -// [curSubpath == length] -// -// 2. one point in subpath -// [curSubpath == length - 1] -// -// 3. open subpath with two or more points -// [curSubpath < length - 1] - -SplashPath::SplashPath() { - pts = NULL; - flags = NULL; - length = size = 0; - curSubpath = 0; -} - -SplashPath::SplashPath(SplashPath *path) { - length = path->length; - size = path->size; - pts = (SplashPathPoint *)gmallocn(size, sizeof(SplashPathPoint)); - flags = (Guchar *)gmallocn(size, sizeof(Guchar)); - memcpy(pts, path->pts, length * sizeof(SplashPathPoint)); - memcpy(flags, path->flags, length * sizeof(Guchar)); - curSubpath = path->curSubpath; -} - -SplashPath::~SplashPath() { - gfree(pts); - gfree(flags); -} - -// Add space for more points. -void SplashPath::grow(int nPts) { - if (length + nPts > size) { - if (size == 0) { - size = 32; - } - while (size < length + nPts) { - size *= 2; - } - pts = (SplashPathPoint *)greallocn(pts, size, sizeof(SplashPathPoint)); - flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); - } -} - -void SplashPath::append(SplashPath *path) { - int i; - - curSubpath = length + path->curSubpath; - grow(path->length); - for (i = 0; i < path->length; ++i) { - pts[length] = path->pts[i]; - flags[length] = path->flags[i]; - ++length; - } -} - -SplashError SplashPath::moveTo(SplashCoord x, SplashCoord y) { - if (onePointSubpath()) { - return splashErrBogusPath; - } - grow(1); - pts[length].x = x; - pts[length].y = y; - flags[length] = splashPathFirst | splashPathLast; - curSubpath = length++; - return splashOk; -} - -SplashError SplashPath::lineTo(SplashCoord x, SplashCoord y) { - if (noCurrentPoint()) { - return splashErrNoCurPt; - } - flags[length-1] &= ~splashPathLast; - grow(1); - pts[length].x = x; - pts[length].y = y; - flags[length] = splashPathLast; - ++length; - return splashOk; -} - -SplashError SplashPath::curveTo(SplashCoord x1, SplashCoord y1, - SplashCoord x2, SplashCoord y2, - SplashCoord x3, SplashCoord y3) { - if (noCurrentPoint()) { - return splashErrNoCurPt; - } - flags[length-1] &= ~splashPathLast; - grow(3); - pts[length].x = x1; - pts[length].y = y1; - flags[length] = splashPathCurve; - ++length; - pts[length].x = x2; - pts[length].y = y2; - flags[length] = splashPathCurve; - ++length; - pts[length].x = x3; - pts[length].y = y3; - flags[length] = splashPathLast; - ++length; - return splashOk; -} - -SplashError SplashPath::arcCWTo(SplashCoord x1, SplashCoord y1, - SplashCoord xc, SplashCoord yc) { - if (noCurrentPoint()) { - return splashErrNoCurPt; - } - flags[length-1] &= ~splashPathLast; - grow(2); - pts[length].x = xc; - pts[length].y = yc; - flags[length] = splashPathArcCW; - ++length; - pts[length].x = x1; - pts[length].y = y1; - flags[length] = splashPathLast; - ++length; - return splashOk; -} - -SplashError SplashPath::close() { - if (noCurrentPoint()) { - return splashErrNoCurPt; - } - if (curSubpath == length - 1 || - pts[length - 1].x != pts[curSubpath].x || - pts[length - 1].y != pts[curSubpath].y) { - lineTo(pts[curSubpath].x, pts[curSubpath].y); - } - flags[curSubpath] |= splashPathClosed; - flags[length - 1] |= splashPathClosed; - curSubpath = length; - return splashOk; -} - -void SplashPath::offset(SplashCoord dx, SplashCoord dy) { - int i; - - for (i = 0; i < length; ++i) { - pts[i].x += dx; - pts[i].y += dy; - } -} - -GBool SplashPath::getCurPt(SplashCoord *x, SplashCoord *y) { - if (noCurrentPoint()) { - return gFalse; - } - *x = pts[length - 1].x; - *y = pts[length - 1].y; - return gTrue; -} diff --git a/xpdf/splash/SplashPath.h b/xpdf/splash/SplashPath.h deleted file mode 100644 index e06d6de3f..000000000 --- a/xpdf/splash/SplashPath.h +++ /dev/null @@ -1,112 +0,0 @@ -//======================================================================== -// -// SplashPath.h -// -//======================================================================== - -#ifndef SPLASHPATH_H -#define SPLASHPATH_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashTypes.h" - -//------------------------------------------------------------------------ -// SplashPathPoint -//------------------------------------------------------------------------ - -struct SplashPathPoint { - SplashCoord x, y; -}; - -//------------------------------------------------------------------------ -// SplashPath.flags -//------------------------------------------------------------------------ - -// first point on each subpath sets this flag -#define splashPathFirst 0x01 - -// last point on each subpath sets this flag -#define splashPathLast 0x02 - -// if the subpath is closed, its first and last points must be -// identical, and must set this flag -#define splashPathClosed 0x04 - -// curve control points set this flag -#define splashPathCurve 0x08 - -// clockwise arc center points set this flag -#define splashPathArcCW 0x10 - -//------------------------------------------------------------------------ -// SplashPath -//------------------------------------------------------------------------ - -class SplashPath { -public: - - // Create an empty path. - SplashPath(); - - // Copy a path. - SplashPath *copy() { return new SplashPath(this); } - - ~SplashPath(); - - // Append to . - void append(SplashPath *path); - - // Start a new subpath. - SplashError moveTo(SplashCoord x, SplashCoord y); - - // Add a line segment to the last subpath. - SplashError lineTo(SplashCoord x, SplashCoord y); - - // Add a third-order (cubic) Bezier curve segment to the last - // subpath. - SplashError curveTo(SplashCoord x1, SplashCoord y1, - SplashCoord x2, SplashCoord y2, - SplashCoord x3, SplashCoord y3); - - // Add a clockwise circular arc with center (xc, yc) and endpoint - // (x1, y1). - SplashError arcCWTo(SplashCoord x1, SplashCoord y1, - SplashCoord xc, SplashCoord yc); - - // Close the last subpath, adding a line segment if necessary. - SplashError close(); - - // Add (, ) to every point on this path. - void offset(SplashCoord dx, SplashCoord dy); - - // Get the points on the path. - int getLength() { return length; } - void getPoint(int i, double *x, double *y, Guchar *f) - { *x = pts[i].x; *y = pts[i].y; *f = flags[i]; } - - // Get the current point. - GBool getCurPt(SplashCoord *x, SplashCoord *y); - -private: - - SplashPath(SplashPath *path); - void grow(int nPts); - GBool noCurrentPoint() { return curSubpath == length; } - GBool onePointSubpath() { return curSubpath == length - 1; } - GBool openSubpath() { return curSubpath < length - 1; } - - SplashPathPoint *pts; // array of points - Guchar *flags; // array of flags - int length, size; // length/size of the pts and flags arrays - int curSubpath; // index of first point in last subpath - - friend class SplashXPath; - friend class Splash; -}; - -#endif diff --git a/xpdf/splash/SplashPattern.cc b/xpdf/splash/SplashPattern.cc deleted file mode 100644 index 76d4bdfc3..000000000 --- a/xpdf/splash/SplashPattern.cc +++ /dev/null @@ -1,68 +0,0 @@ -//======================================================================== -// -// SplashPattern.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "SplashMath.h" -#include "SplashScreen.h" -#include "SplashPattern.h" - -//------------------------------------------------------------------------ -// SplashPattern -//------------------------------------------------------------------------ - -SplashPattern::SplashPattern() { -} - -SplashPattern::~SplashPattern() { -} - -//------------------------------------------------------------------------ -// SplashSolidColor -//------------------------------------------------------------------------ - -SplashSolidColor::SplashSolidColor(SplashColorPtr colorA) { - splashColorCopy(color, colorA); -} - -SplashSolidColor::~SplashSolidColor() { -} - -void SplashSolidColor::getColor(int /*x*/, int /*y*/, SplashColorPtr c) { - splashColorCopy(c, color); -} - -//------------------------------------------------------------------------ -// SplashHalftone -//------------------------------------------------------------------------ - -SplashHalftone::SplashHalftone(SplashColorPtr color0A, SplashColorPtr color1A, - SplashScreen *screenA, SplashCoord valueA) { - splashColorCopy(color0, color0A); - splashColorCopy(color1, color1A); - screen = screenA; - value = valueA; -} - -SplashPattern *SplashHalftone::copy() { - return new SplashHalftone(color0, color1, screen->copy(), value); -} - -SplashHalftone::~SplashHalftone() { - delete screen; -} - -void SplashHalftone::getColor(int x, int y, SplashColorPtr c) { - splashColorCopy(c, screen->test(x, y, value) ? color1 : color0); -} - -GBool SplashHalftone::isStatic() { - return screen->isStatic(value); -} diff --git a/xpdf/splash/SplashPattern.h b/xpdf/splash/SplashPattern.h deleted file mode 100644 index fb633dac9..000000000 --- a/xpdf/splash/SplashPattern.h +++ /dev/null @@ -1,90 +0,0 @@ -//======================================================================== -// -// SplashPattern.h -// -//======================================================================== - -#ifndef SPLASHPATTERN_H -#define SPLASHPATTERN_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashTypes.h" - -class SplashScreen; - -//------------------------------------------------------------------------ -// SplashPattern -//------------------------------------------------------------------------ - -class SplashPattern { -public: - - SplashPattern(); - - virtual SplashPattern *copy() = 0; - - virtual ~SplashPattern(); - - // Return the color value for a specific pixel. - virtual void getColor(int x, int y, SplashColorPtr c) = 0; - - // Returns true if this pattern object will return the same color - // value for all pixels. - virtual GBool isStatic() = 0; - -private: -}; - -//------------------------------------------------------------------------ -// SplashSolidColor -//------------------------------------------------------------------------ - -class SplashSolidColor: public SplashPattern { -public: - - SplashSolidColor(SplashColorPtr colorA); - - virtual SplashPattern *copy() { return new SplashSolidColor(color); } - - virtual ~SplashSolidColor(); - - virtual void getColor(int x, int y, SplashColorPtr c); - - virtual GBool isStatic() { return gTrue; } - -private: - - SplashColor color; -}; - -//------------------------------------------------------------------------ -// SplashHalftone -//------------------------------------------------------------------------ - -class SplashHalftone: public SplashPattern { -public: - - SplashHalftone(SplashColorPtr color0A, SplashColorPtr color1A, - SplashScreen *screenA, SplashCoord valueA); - - virtual SplashPattern *copy(); - - virtual ~SplashHalftone(); - - virtual void getColor(int x, int y, SplashColorPtr c); - - virtual GBool isStatic(); - -private: - - SplashColor color0, color1; - SplashScreen *screen; - SplashCoord value; -}; - -#endif diff --git a/xpdf/splash/SplashScreen.cc b/xpdf/splash/SplashScreen.cc deleted file mode 100644 index 27c341c72..000000000 --- a/xpdf/splash/SplashScreen.cc +++ /dev/null @@ -1,141 +0,0 @@ -//======================================================================== -// -// SplashScreen.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "SplashMath.h" -#include "SplashScreen.h" - -//------------------------------------------------------------------------ -// SplashScreen -//------------------------------------------------------------------------ - -// This generates a 45 degree screen using a circular dot spot -// function. DPI = resolution / ((size / 2) * sqrt(2)). -// Gamma correction (gamma = 1 / 1.33) is also computed here. -SplashScreen::SplashScreen(int sizeA) { - SplashCoord *dist; - SplashCoord u, v, d, val; - int size2, x, y, x1, y1, i; - - size2 = sizeA >> 1; - if (size2 < 1) { - size2 = 1; - } - size = size2 << 1; - - // initialize the threshold matrix - mat = (SplashCoord *)gmallocn(size * size, sizeof(SplashCoord)); - for (y = 0; y < size; ++y) { - for (x = 0; x < size; ++x) { - mat[y * size + x] = -1; - } - } - - // build the distance matrix - dist = (SplashCoord *)gmallocn(size * size2, sizeof(SplashCoord)); - for (y = 0; y < size2; ++y) { - for (x = 0; x < size2; ++x) { - if (x + y < size2 - 1) { - u = (SplashCoord)x + 0.5 - 0; - v = (SplashCoord)y + 0.5 - 0; - } else { - u = (SplashCoord)x + 0.5 - (SplashCoord)size2; - v = (SplashCoord)y + 0.5 - (SplashCoord)size2; - } - dist[y * size2 + x] = u*u + v*v; - } - } - for (y = 0; y < size2; ++y) { - for (x = 0; x < size2; ++x) { - if (x < y) { - u = (SplashCoord)x + 0.5 - 0; - v = (SplashCoord)y + 0.5 - (SplashCoord)size2; - } else { - u = (SplashCoord)x + 0.5 - (SplashCoord)size2; - v = (SplashCoord)y + 0.5 - 0; - } - dist[(size2 + y) * size2 + x] = u*u + v*v; - } - } - - // build the threshold matrix - minVal = 1; - maxVal = 0; - x1 = y1 = 0; // make gcc happy - for (i = 1; i <= size * size2; ++i) { - d = size * size2; - for (y = 0; y < size; ++y) { - for (x = 0; x < size2; ++x) { - if (mat[y * size + x] < 0 && - dist[y * size2 + x] < d) { - x1 = x; - y1 = y; - d = dist[y1 * size2 + x1]; - } - } - } - u = (SplashCoord)1 - (SplashCoord)i / (SplashCoord)(size * size2 + 1); - val = splashPow(u, 1.33); - if (val < minVal) { - minVal = val; - } - if (val > maxVal) { - maxVal = val; - } - mat[y1 * size + x1] = val; - if (y1 < size2) { - mat[(y1 + size2) * size + x1 + size2] = val; - } else { - mat[(y1 - size2) * size + x1 + size2] = val; - } - } - - gfree(dist); -} - -SplashScreen::SplashScreen(SplashScreen *screen) { - int n; - - size = screen->size; - n = size * size * sizeof(SplashCoord); - mat = (SplashCoord *)gmalloc(n); - memcpy(mat, screen->mat, n); - minVal = screen->minVal; - maxVal = screen->maxVal; -} - -SplashScreen::~SplashScreen() { - gfree(mat); -} - -int SplashScreen::test(int x, int y, SplashCoord value) { - int xx, yy; - - if (value < minVal) { - return 0; - } - if (value >= maxVal) { - return 1; - } - if ((xx = x % size) < 0) { - xx = -xx; - } - if ((yy = y % size) < 0) { - yy = -yy; - } - return value < mat[yy * size + xx] ? 0 : 1; -} - -GBool SplashScreen::isStatic(SplashCoord value) { - return value < minVal || value >= maxVal; -} diff --git a/xpdf/splash/SplashScreen.h b/xpdf/splash/SplashScreen.h deleted file mode 100644 index 66f7c4898..000000000 --- a/xpdf/splash/SplashScreen.h +++ /dev/null @@ -1,50 +0,0 @@ -//======================================================================== -// -// SplashScreen.h -// -//======================================================================== - -#ifndef SPLASHSCREEN_H -#define SPLASHSCREEN_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashTypes.h" - -//------------------------------------------------------------------------ -// SplashScreen -//------------------------------------------------------------------------ - -class SplashScreen { -public: - - SplashScreen(int sizeA); - SplashScreen(SplashScreen *screen); - ~SplashScreen(); - - SplashScreen *copy() { return new SplashScreen(this); } - - // Return the computed pixel value (0=black, 1=white) for the gray - // level at (, ). - int test(int x, int y, SplashCoord value); - - // Returns true if value is above the white threshold or below the - // black threshold, i.e., if the corresponding halftone will be - // solid white or black. - GBool isStatic(SplashCoord value); - -private: - - SplashCoord *mat; // threshold matrix - int size; // size of the threshold matrix - SplashCoord minVal; // any pixel value below minVal generates - // solid black - SplashCoord maxVal; // any pixel value above maxVal generates - // solid white -}; - -#endif diff --git a/xpdf/splash/SplashState.cc b/xpdf/splash/SplashState.cc deleted file mode 100644 index 3fd17e172..000000000 --- a/xpdf/splash/SplashState.cc +++ /dev/null @@ -1,110 +0,0 @@ -//======================================================================== -// -// SplashState.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "SplashPattern.h" -#include "SplashScreen.h" -#include "SplashClip.h" -#include "SplashState.h" - -//------------------------------------------------------------------------ -// SplashState -//------------------------------------------------------------------------ - -// number of components in each color mode -int splashColorModeNComps[] = { - 1, 1, 2, 3, 3, 4, 4 -}; - -SplashState::SplashState(int width, int height) { - SplashColor color; - - memset(&color, 0, sizeof(SplashColor)); - strokePattern = new SplashSolidColor(color); - fillPattern = new SplashSolidColor(color); - screen = new SplashScreen(10); - blendFunc = NULL; - strokeAlpha = 1; - fillAlpha = 1; - lineWidth = 0; - lineCap = splashLineCapButt; - lineJoin = splashLineJoinMiter; - miterLimit = 10; - flatness = 1; - lineDash = NULL; - lineDashLength = 0; - lineDashPhase = 0; - clip = new SplashClip(0, 0, width - 1, height - 1); - next = NULL; -} - -SplashState::SplashState(SplashState *state) { - strokePattern = state->strokePattern->copy(); - fillPattern = state->fillPattern->copy(); - screen = state->screen->copy(); - blendFunc = state->blendFunc; - strokeAlpha = state->strokeAlpha; - fillAlpha = state->fillAlpha; - lineWidth = state->lineWidth; - lineCap = state->lineCap; - lineJoin = state->lineJoin; - miterLimit = state->miterLimit; - flatness = state->flatness; - if (state->lineDash) { - lineDashLength = state->lineDashLength; - lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); - memcpy(lineDash, state->lineDash, lineDashLength * sizeof(SplashCoord)); - } else { - lineDash = NULL; - lineDashLength = 0; - } - lineDashPhase = state->lineDashPhase; - clip = state->clip->copy(); - next = NULL; -} - -SplashState::~SplashState() { - delete strokePattern; - delete fillPattern; - delete screen; - gfree(lineDash); - delete clip; -} - -void SplashState::setStrokePattern(SplashPattern *strokePatternA) { - delete strokePattern; - strokePattern = strokePatternA; -} - -void SplashState::setFillPattern(SplashPattern *fillPatternA) { - delete fillPattern; - fillPattern = fillPatternA; -} - -void SplashState::setScreen(SplashScreen *screenA) { - delete screen; - screen = screenA; -} - -void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA, - SplashCoord lineDashPhaseA) { - gfree(lineDash); - lineDashLength = lineDashLengthA; - if (lineDashLength > 0) { - lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); - memcpy(lineDash, lineDashA, lineDashLength * sizeof(SplashCoord)); - } else { - lineDash = NULL; - } - lineDashPhase = lineDashPhaseA; -} diff --git a/xpdf/splash/SplashState.h b/xpdf/splash/SplashState.h deleted file mode 100644 index ba00d2da0..000000000 --- a/xpdf/splash/SplashState.h +++ /dev/null @@ -1,91 +0,0 @@ -//======================================================================== -// -// SplashState.h -// -//======================================================================== - -#ifndef SPLASHSTATE_H -#define SPLASHSTATE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashTypes.h" - -class SplashPattern; -class SplashScreen; -class SplashClip; - -//------------------------------------------------------------------------ -// line cap values -//------------------------------------------------------------------------ - -#define splashLineCapButt 0 -#define splashLineCapRound 1 -#define splashLineCapProjecting 2 - -//------------------------------------------------------------------------ -// line join values -//------------------------------------------------------------------------ - -#define splashLineJoinMiter 0 -#define splashLineJoinRound 1 -#define splashLineJoinBevel 2 - -//------------------------------------------------------------------------ -// SplashState -//------------------------------------------------------------------------ - -class SplashState { -public: - - // Create a new state object, initialized with default settings. - SplashState(int width, int height); - - // Copy a state object. - SplashState *copy() { return new SplashState(this); } - - ~SplashState(); - - // Set the stroke pattern. This does not copy . - void setStrokePattern(SplashPattern *strokePatternA); - - // Set the fill pattern. This does not copy . - void setFillPattern(SplashPattern *fillPatternA); - - // Set the screen. This does not copy . - void setScreen(SplashScreen *screenA); - - // Set the line dash pattern. This copies the array. - void setLineDash(SplashCoord *lineDashA, int lineDashLengthA, - SplashCoord lineDashPhaseA); - -private: - - SplashState(SplashState *state); - - SplashPattern *strokePattern; - SplashPattern *fillPattern; - SplashScreen *screen; - SplashBlendFunc blendFunc; - SplashCoord strokeAlpha; - SplashCoord fillAlpha; - SplashCoord lineWidth; - int lineCap; - int lineJoin; - SplashCoord miterLimit; - SplashCoord flatness; - SplashCoord *lineDash; - int lineDashLength; - SplashCoord lineDashPhase; - SplashClip *clip; - - SplashState *next; // used by Splash class - - friend class Splash; -}; - -#endif diff --git a/xpdf/splash/SplashT1Font.cc b/xpdf/splash/SplashT1Font.cc deleted file mode 100644 index d94f4af51..000000000 --- a/xpdf/splash/SplashT1Font.cc +++ /dev/null @@ -1,264 +0,0 @@ -//======================================================================== -// -// SplashT1Font.cc -// -//======================================================================== - -#include - -#if HAVE_T1LIB_H - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "SplashMath.h" -#include "SplashGlyphBitmap.h" -#include "SplashPath.h" -#include "SplashT1FontEngine.h" -#include "SplashT1FontFile.h" -#include "SplashT1Font.h" - -//------------------------------------------------------------------------ - -static Guchar bitReverse[256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff -}; - -//------------------------------------------------------------------------ -// SplashT1Font -//------------------------------------------------------------------------ - -SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA): - SplashFont(fontFileA, matA, ((SplashT1FontFile *)fontFileA)->engine->aa) -{ - T1_TMATRIX matrix; - BBox bbox; - SplashCoord bbx0, bby0, bbx1, bby1; - int x, y; - - t1libID = T1_CopyFont(fontFileA->t1libID); - - // compute font size - size = (float)splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]); - - // transform the four corners of the font bounding box -- the min - // and max values form the bounding box of the transformed font - bbox = T1_GetFontBBox(t1libID); - bbx0 = 0.001 * bbox.llx; - bby0 = 0.001 * bbox.lly; - bbx1 = 0.001 * bbox.urx; - bby1 = 0.001 * bbox.ury; - // some fonts are completely broken, so we fake it (with values - // large enough that most glyphs should fit) - if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) { - bbx0 = bby0 = -0.5; - bbx1 = bby1 = 1.5; - } - x = (int)(mat[0] * bbx0 + mat[2] * bby0); - xMin = xMax = x; - y = (int)(mat[1] * bbx0 + mat[3] * bby0); - yMin = yMax = y; - x = (int)(mat[0] * bbx0 + mat[2] * bby1); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)(mat[1] * bbx0 + mat[3] * bby1); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - x = (int)(mat[0] * bbx1 + mat[2] * bby0); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)(mat[1] * bbx1 + mat[3] * bby0); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - x = (int)(mat[0] * bbx1 + mat[2] * bby1); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)(mat[1] * bbx1 + mat[3] * bby1); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - // This is a kludge: some buggy PDF generators embed fonts with - // zero bounding boxes. - if (xMax == xMin) { - xMin = 0; - xMax = (int)size; - } - if (yMax == yMin) { - yMin = 0; - yMax = (int)(1.2 * size); - } - // Another kludge: an unusually large xMin or yMin coordinate is - // probably wrong. - if (xMin > 0) { - xMin = 0; - } - if (yMin > 0) { - yMin = 0; - } - // Another kludge: t1lib doesn't correctly handle fonts with - // real (non-integer) bounding box coordinates. - if (xMax - xMin > 5000) { - xMin = 0; - xMax = (int)size; - } - if (yMax - yMin > 5000) { - yMin = 0; - yMax = (int)(1.2 * size); - } - - // transform the font - matrix.cxx = (double)mat[0] / size; - matrix.cxy = (double)mat[1] / size; - matrix.cyx = (double)mat[2] / size; - matrix.cyy = (double)mat[3] / size; - T1_TransformFont(t1libID, &matrix); -} - -SplashT1Font::~SplashT1Font() { - T1_DeleteFont(t1libID); -} - -GBool SplashT1Font::getGlyph(int c, int /*xFrac*/, int /*yFrac*/, - SplashGlyphBitmap *bitmap) { - return SplashFont::getGlyph(c, 0, 0, bitmap); -} - -GBool SplashT1Font::makeGlyph(int c, int /*xFrac*/, int /*yFrac*/, - SplashGlyphBitmap *bitmap) { - GLYPH *glyph; - int n, i; - - if (aa) { - glyph = T1_AASetChar(t1libID, c, size, NULL); - } else { - glyph = T1_SetChar(t1libID, c, size, NULL); - } - if (!glyph) { - return gFalse; - } - - bitmap->x = -glyph->metrics.leftSideBearing; - bitmap->y = glyph->metrics.ascent; - bitmap->w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing; - bitmap->h = glyph->metrics.ascent - glyph->metrics.descent; - bitmap->aa = aa; - if (aa) { - bitmap->data = (Guchar *)glyph->bits; - bitmap->freeData = gFalse; - } else { - n = bitmap->h * ((bitmap->w + 7) >> 3); - bitmap->data = (Guchar *)gmalloc(n); - for (i = 0; i < n; ++i) { - bitmap->data[i] = bitReverse[glyph->bits[i] & 0xff]; - } - bitmap->freeData = gTrue; - } - - return gTrue; -} - -SplashPath *SplashT1Font::getGlyphPath(int c) { - SplashPath *path; - T1_OUTLINE *outline; - T1_PATHSEGMENT *seg; - T1_BEZIERSEGMENT *bez; - SplashCoord x, y, x1, y1; - GBool needClose; - - path = new SplashPath(); - if (!(outline = T1_GetCharOutline(t1libID, c, size, NULL))) { - return path; - } - x = 0; - y = 0; - needClose = gFalse; - for (seg = outline; seg; seg = seg->link) { - switch (seg->type) { - case T1_PATHTYPE_MOVE: - if (needClose) { - path->close(); - needClose = gFalse; - } - x += seg->dest.x / 65536.0; - y += seg->dest.y / 65536.0; - path->moveTo(x, y); - break; - case T1_PATHTYPE_LINE: - x += seg->dest.x / 65536.0; - y += seg->dest.y / 65536.0; - path->lineTo(x, y); - needClose = gTrue; - break; - case T1_PATHTYPE_BEZIER: - bez = (T1_BEZIERSEGMENT *)seg; - x1 = x + bez->dest.x / 65536.0; - y1 = y + bez->dest.y / 65536.0; - path->curveTo(x + bez->B.x / 65536.0, y + bez->B.y / 65536.0, - x + bez->C.x / 65536.0, y + bez->C.y / 65536.0, - x1, y1); - x = x1; - y = y1; - needClose = gTrue; - break; - } - } - if (needClose) { - path->close(); - } - T1_FreeOutline(outline); - return path; -} - -#endif // HAVE_T1LIB_H diff --git a/xpdf/splash/SplashT1Font.h b/xpdf/splash/SplashT1Font.h deleted file mode 100644 index 353f37608..000000000 --- a/xpdf/splash/SplashT1Font.h +++ /dev/null @@ -1,53 +0,0 @@ -//======================================================================== -// -// SplashT1Font.h -// -//======================================================================== - -#ifndef SPLASHT1FONT_H -#define SPLASHT1FONT_H - -#include - -#if HAVE_T1LIB_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashFont.h" - -class SplashT1FontFile; - -//------------------------------------------------------------------------ -// SplashT1Font -//------------------------------------------------------------------------ - -class SplashT1Font: public SplashFont { -public: - - SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA); - - virtual ~SplashT1Font(); - - // Munge xFrac and yFrac before calling SplashFont::getGlyph. - virtual GBool getGlyph(int c, int xFrac, int yFrac, - SplashGlyphBitmap *bitmap); - - // Rasterize a glyph. The and values are the same - // as described for getGlyph. - virtual GBool makeGlyph(int c, int xFrac, int yFrac, - SplashGlyphBitmap *bitmap); - - // Return the path for a glyph. - virtual SplashPath *getGlyphPath(int c); - -private: - - int t1libID; // t1lib font ID - float size; -}; - -#endif // HAVE_T1LIB_H - -#endif diff --git a/xpdf/splash/SplashT1FontEngine.cc b/xpdf/splash/SplashT1FontEngine.cc deleted file mode 100644 index 0fde8e222..000000000 --- a/xpdf/splash/SplashT1FontEngine.cc +++ /dev/null @@ -1,122 +0,0 @@ -//======================================================================== -// -// SplashT1FontEngine.cc -// -//======================================================================== - -#include - -#if HAVE_T1LIB_H - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#ifndef WIN32 -# include -#endif -#include -#include "GString.h" -#include "gfile.h" -#include "FoFiType1C.h" -#include "SplashT1FontFile.h" -#include "SplashT1FontEngine.h" - -#ifdef VMS -#if (__VMS_VER < 70000000) -extern "C" int unlink(char *filename); -#endif -#endif - -//------------------------------------------------------------------------ - -int SplashT1FontEngine::t1libInitCount = 0; - -//------------------------------------------------------------------------ - -static void T1_fileWrite(void *stream, const char *data, int len) { - fwrite(data, 1, len, (FILE *)stream); -} - -//------------------------------------------------------------------------ -// SplashT1FontEngine -//------------------------------------------------------------------------ - -SplashT1FontEngine::SplashT1FontEngine(GBool aaA) { - aa = aaA; -} - -SplashT1FontEngine *SplashT1FontEngine::init(GBool aaA) { - // grayVals[i] = round(i * 255 / 16) - static unsigned long grayVals[17] = { - 0, 16, 32, 48, 64, 80, 96, 112, 128, 143, 159, 175, 191, 207, 223, 239, 255 - }; - - //~ for multithreading: need a mutex here - if (t1libInitCount == 0) { - T1_SetBitmapPad(8); - if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE | - T1_NO_AFM)) { - return NULL; - } - if (aaA) { - T1_AASetBitsPerPixel(8); - T1_AASetLevel(T1_AA_HIGH); - T1_AAHSetGrayValues(grayVals); - } else { - T1_AANSetGrayValues(0, 1); - } - } - ++t1libInitCount; - - return new SplashT1FontEngine(aaA); -} - -SplashT1FontEngine::~SplashT1FontEngine() { - //~ for multithreading: need a mutex here - if (--t1libInitCount == 0) { - T1_CloseLib(); - } -} - -SplashFontFile *SplashT1FontEngine::loadType1Font(SplashFontFileID *idA, - SplashFontSrc *src, - const char **enc) { - return SplashT1FontFile::loadType1Font(this, idA, src, enc); -} - -SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA, - SplashFontSrc *src, - const char **enc) { - FoFiType1C *ff; - GString *tmpFileName; - FILE *tmpFile; - SplashFontFile *ret; - SplashFontSrc *newsrc; - - if (src->isFile) - ff = FoFiType1C::load(src->fileName); - else - ff = new FoFiType1C(src->buf, src->bufLen, gFalse); - if (! ff) - return NULL; - } - tmpFileName = NULL; - if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { - delete ff; - return NULL; - } - ff->convertToType1(NULL, gTrue, &T1_fileWrite, tmpFile); - delete ff; - fclose(tmpFile); - newsrc = new SplashFontSrc; - newsrc->setFile(tmpFileName, gTrue); - delete tmpFileName; - ret = SplashT1FontFile::loadType1Font(this, idA, newsrc, enc); - newsrc->unref(); - return ret; -} - -#endif // HAVE_T1LIB_H diff --git a/xpdf/splash/SplashT1FontEngine.h b/xpdf/splash/SplashT1FontEngine.h deleted file mode 100644 index 8942b8536..000000000 --- a/xpdf/splash/SplashT1FontEngine.h +++ /dev/null @@ -1,53 +0,0 @@ -//======================================================================== -// -// SplashT1FontEngine.h -// -//======================================================================== - -#ifndef SPLASHT1FONTENGINE_H -#define SPLASHT1FONTENGINE_H - -#include - -#if HAVE_T1LIB_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -class SplashFontFile; -class SplashFontFileID; - -//------------------------------------------------------------------------ -// SplashT1FontEngine -//------------------------------------------------------------------------ - -class SplashT1FontEngine { -public: - - static SplashT1FontEngine *init(GBool aaA); - - ~SplashT1FontEngine(); - - // Load fonts. - SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, - GBool deleteFile, const char **enc); - SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, - GBool deleteFile, const char **enc); - -private: - - SplashT1FontEngine(GBool aaA); - - static int t1libInitCount; - GBool aa; - - friend class SplashT1FontFile; - friend class SplashT1Font; -}; - -#endif // HAVE_T1LIB_H - -#endif diff --git a/xpdf/splash/SplashT1FontFile.cc b/xpdf/splash/SplashT1FontFile.cc deleted file mode 100644 index c87eeeb98..000000000 --- a/xpdf/splash/SplashT1FontFile.cc +++ /dev/null @@ -1,116 +0,0 @@ -//======================================================================== -// -// SplashT1FontFile.cc -// -//======================================================================== - -#include - -#if HAVE_T1LIB_H - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "SplashT1FontEngine.h" -#include "SplashT1Font.h" -#include "SplashT1FontFile.h" - -//------------------------------------------------------------------------ -// SplashT1FontFile -//------------------------------------------------------------------------ - -SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *src, - const char **encA) { - int t1libIDA; - const char **encTmp; - char *encStrTmp; - int encStrSize; - char *encPtr; - int i; - GString *fileNameA; - SplashFontSrc *newsrc = NULL; - SplashFontFile *ff; - - if (! src->isFile) { - GString *tmpFileName; - FILE *tmpFile; - if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) - return NULL; - fwrite(src->buf, 1, src->bufLen, tmpFile); - fclose(tmpFile); - newsrc = new SplashFontSrc; - newsrc->setFile(tmpFileName, gTrue); - src = newsrc; - delete tmpFileName; - } - fileNameA = src->fileName; - // load the font file - if ((t1libIDA = T1_AddFont(fileNameA)) < 0) { - if (newsrc) - delete newsrc; - return NULL; - } - T1_LoadFont(t1libIDA); - - // reencode it - encStrSize = 0; - for (i = 0; i < 256; ++i) { - if (encA[i]) { - encStrSize += strlen(encA[i]) + 1; - } - } - encTmp = (const char **)gmallocn(257, sizeof(char *)); - encStrTmp = (char *)gmallocn(encStrSize, sizeof(char)); - encPtr = encStrTmp; - for (i = 0; i < 256; ++i) { - if (encA[i]) { - strcpy(encPtr, encA[i]); - encTmp[i] = encPtr; - encPtr += strlen(encPtr) + 1; - } else { - encTmp[i] = ".notdef"; - } - } - encTmp[256] = "custom"; - T1_ReencodeFont(t1libIDA, (char**)encTmp); - - ff = new SplashT1FontFile(engineA, idA, src, - t1libIDA, encTmp, encStrTmp); - if (newsrc) - newsrc->unref(); - return ff; -} - -SplashT1FontFile::SplashT1FontFile(SplashT1FontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *srcA, - int t1libIDA, const char **encA, char *encStrA): - SplashFontFile(idA, srcA) -{ - engine = engineA; - t1libID = t1libIDA; - enc = encA; - encStr = encStrA; -} - -SplashT1FontFile::~SplashT1FontFile() { - gfree(encStr); - gfree(enc); - T1_DeleteFont(t1libID); -} - -SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat) { - SplashFont *font; - - font = new SplashT1Font(this, mat); - font->initCache(); - return font; -} - -#endif // HAVE_T1LIB_H diff --git a/xpdf/splash/SplashT1FontFile.h b/xpdf/splash/SplashT1FontFile.h deleted file mode 100644 index 86d96165f..000000000 --- a/xpdf/splash/SplashT1FontFile.h +++ /dev/null @@ -1,57 +0,0 @@ -//======================================================================== -// -// SplashT1FontFile.h -// -//======================================================================== - -#ifndef SPLASHT1FONTFILE_H -#define SPLASHT1FONTFILE_H - -#include - -#if HAVE_T1LIB_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashFontFile.h" - -class SplashT1FontEngine; - -//------------------------------------------------------------------------ -// SplashT1FontFile -//------------------------------------------------------------------------ - -class SplashT1FontFile: public SplashFontFile { -public: - - static SplashFontFile *loadType1Font(SplashT1FontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *src, - const char **encA); - - virtual ~SplashT1FontFile(); - - // Create a new SplashT1Font, i.e., a scaled instance of this font - // file. - virtual SplashFont *makeFont(SplashCoord *mat); - -private: - - SplashT1FontFile(SplashT1FontEngine *engineA, - SplashFontFileID *idA, - SplashFontSrc *src, - int t1libIDA, const char **encA, char *encStrA); - - SplashT1FontEngine *engine; - int t1libID; // t1lib font ID - const char **enc; - char *encStr; - - friend class SplashT1Font; -}; - -#endif // HAVE_T1LIB_H - -#endif diff --git a/xpdf/splash/SplashTypes.h b/xpdf/splash/SplashTypes.h deleted file mode 100644 index 04dd9f7ba..000000000 --- a/xpdf/splash/SplashTypes.h +++ /dev/null @@ -1,134 +0,0 @@ -//======================================================================== -// -// SplashTypes.h -// -//======================================================================== - -#ifndef SPLASHTYPES_H -#define SPLASHTYPES_H - -#include -#include "gtypes.h" - -//------------------------------------------------------------------------ -// coordinates -//------------------------------------------------------------------------ - -typedef double SplashCoord; - -//------------------------------------------------------------------------ -// colors -//------------------------------------------------------------------------ - -enum SplashColorMode { - splashModeMono1, // 1 bit per component, 8 pixels per byte, - // MSbit is on the left - splashModeMono8, // 1 byte per component, 1 byte per pixel - splashModeAMono8, // 1 byte per component, 2 bytes per pixel: - // AMAM... - splashModeRGB8, // 1 byte per component, 3 bytes per pixel: - // RGBRGB... - splashModeBGR8, // 1 byte per component, 3 bytes per pixel: - // BGRBGR... - splashModeARGB8, // 1 byte per component, 4 bytes per pixel: - // ARGBARGB... - splashModeBGRA8 // 1 byte per component, 4 bytes per pixel: - // BGRABGRA... -#if SPLASH_CMYK - , - splashModeCMYK8, // 1 byte per component, 4 bytes per pixel: - // CMYKCMYK... - splashModeACMYK8 // 1 byte per component, 5 bytes per pixel: - // ACMYKACMYK -#endif -}; - -// number of components in each color mode -// (defined in SplashState.cc) -extern int splashColorModeNComps[]; - -// max number of components in any SplashColor -#if SPLASH_CMYK -# define splashMaxColorComps 5 -#else -# define splashMaxColorComps 4 -#endif - -typedef Guchar SplashColor[splashMaxColorComps]; -typedef Guchar *SplashColorPtr; - -// AMono8 -static inline Guchar splashAMono8A(SplashColorPtr am8) { return am8[0]; } -static inline Guchar splashAMono8M(SplashColorPtr am8) { return am8[1]; } - -// RGB8 -static inline Guchar splashRGB8R(SplashColorPtr rgb8) { return rgb8[0]; } -static inline Guchar splashRGB8G(SplashColorPtr rgb8) { return rgb8[1]; } -static inline Guchar splashRGB8B(SplashColorPtr rgb8) { return rgb8[2]; } - -// BGR8 -static inline Guchar splashBGR8R(SplashColorPtr bgr8) { return bgr8[2]; } -static inline Guchar splashBGR8G(SplashColorPtr bgr8) { return bgr8[1]; } -static inline Guchar splashBGR8B(SplashColorPtr bgr8) { return bgr8[0]; } - -// ARGB8 -static inline Guchar splashARGB8A(SplashColorPtr argb8) { return argb8[0]; } -static inline Guchar splashARGB8R(SplashColorPtr argb8) { return argb8[1]; } -static inline Guchar splashARGB8G(SplashColorPtr argb8) { return argb8[2]; } -static inline Guchar splashARGB8B(SplashColorPtr argb8) { return argb8[3]; } - -// ARGB8 -static inline Guchar splashBGRA8A(SplashColorPtr bgra8) { return bgra8[3]; } -static inline Guchar splashBGRA8R(SplashColorPtr bgra8) { return bgra8[2]; } -static inline Guchar splashBGRA8G(SplashColorPtr bgra8) { return bgra8[1]; } -static inline Guchar splashBGRA8B(SplashColorPtr bgra8) { return bgra8[0]; } - -#if SPLASH_CMYK -// CMYK8 -static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; } -static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; } -static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; } -static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; } - -// ACMYK8 -static inline Guchar splashACMYK8A(SplashColorPtr acmyk8) { return acmyk8[0]; } -static inline Guchar splashACMYK8C(SplashColorPtr acmyk8) { return acmyk8[1]; } -static inline Guchar splashACMYK8M(SplashColorPtr acmyk8) { return acmyk8[2]; } -static inline Guchar splashACMYK8Y(SplashColorPtr acmyk8) { return acmyk8[3]; } -static inline Guchar splashACMYK8K(SplashColorPtr acmyk8) { return acmyk8[4]; } -#endif - -static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) { - dest[0] = src[0]; - dest[1] = src[1]; - dest[2] = src[2]; - dest[3] = src[3]; -#if SPLASH_CMYK - dest[4] = src[4]; -#endif -} - -static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) { - dest[0] ^= src[0]; - dest[1] ^= src[1]; - dest[2] ^= src[2]; - dest[3] ^= src[3]; -#if SPLASH_CMYK - dest[4] ^= src[4]; -#endif -} - -//------------------------------------------------------------------------ -// blend functions -//------------------------------------------------------------------------ - -typedef void (*SplashBlendFunc)(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm); - -//------------------------------------------------------------------------ -// error results -//------------------------------------------------------------------------ - -typedef int SplashError; - -#endif diff --git a/xpdf/splash/SplashXPath.cc b/xpdf/splash/SplashXPath.cc deleted file mode 100644 index 145e9ea2e..000000000 --- a/xpdf/splash/SplashXPath.cc +++ /dev/null @@ -1,414 +0,0 @@ -//======================================================================== -// -// SplashXPath.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "SplashMath.h" -#include "SplashPath.h" -#include "SplashXPath.h" - -//------------------------------------------------------------------------ - -#define maxCurveSplits (1 << 10) - -//------------------------------------------------------------------------ -// SplashXPath -//------------------------------------------------------------------------ - -SplashXPath::SplashXPath() { - segs = NULL; - length = size = 0; -} - -SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness, - GBool closeSubpaths) { - SplashCoord xc, yc, dx, dy, r, x0, y0, x1, y1; - int quad0, quad1, quad; - int curSubpath, n, i, j; - - segs = NULL; - length = size = 0; - - i = 0; - curSubpath = 0; - while (i < path->length) { - - // first point in subpath - skip it - if (path->flags[i] & splashPathFirst) { - curSubpath = i; - ++i; - - } else { - - // curve segment - if (path->flags[i] & splashPathCurve) { - addCurve(path->pts[i-1].x, path->pts[i-1].y, - path->pts[i ].x, path->pts[i ].y, - path->pts[i+1].x, path->pts[i+1].y, - path->pts[i+2].x, path->pts[i+2].y, - flatness, - (path->flags[i-1] & splashPathFirst), - (path->flags[i+2] & splashPathLast), - !closeSubpaths && - (path->flags[i-1] & splashPathFirst) && - !(path->flags[i-1] & splashPathClosed), - !closeSubpaths && - (path->flags[i+2] & splashPathLast) && - !(path->flags[i+2] & splashPathClosed)); - i += 3; - - // clockwise circular arc - } else if (path->flags[i] & splashPathArcCW) { - xc = path->pts[i].x; - yc = path->pts[i].y; - dx = path->pts[i+1].x - xc; - dy = path->pts[i+1].y - yc; - r = splashSqrt(dx * dx + dy * dy); - if (path->pts[i-1].x < xc && path->pts[i-1].y <= yc) { - quad0 = 0; - } else if (path->pts[i-1].x >= xc && path->pts[i-1].y < yc) { - quad0 = 1; - } else if (path->pts[i-1].x > xc && path->pts[i-1].y >= yc) { - quad0 = 2; - } else { - quad0 = 3; - } - if (path->pts[i+1].x <= xc && path->pts[i+1].y < yc) { - quad1 = 0; - } else if (path->pts[i+1].x > xc && path->pts[i+1].y <= yc) { - quad1 = 1; - } else if (path->pts[i+1].x >= xc && path->pts[i+1].y > yc) { - quad1 = 2; - } else { - quad1 = 3; - } - n = 0; // make gcc happy - if (quad0 == quad1) { - switch (quad0) { - case 0: - case 1: n = path->pts[i-1].x < path->pts[i+1].x ? 0 : 4; break; - case 2: - case 3: n = path->pts[i-1].x > path->pts[i+1].x ? 0 : 4; break; - } - } else { - n = (quad1 - quad0) & 3; - } - x0 = path->pts[i-1].x; - y0 = path->pts[i-1].y; - x1 = y1 = 0; // make gcc happy - quad = quad0; - for (j = 0; j < n; ++j) { - switch (quad) { - case 0: x1 = xc; y1 = yc - r; break; - case 1: x1 = xc + r; y1 = yc; break; - case 2: x1 = xc; y1 = yc + r; break; - case 3: x1 = xc - r; y1 = yc; break; - } - addArc(x0, y0, x1, y1, - xc, yc, r, quad, flatness, - quad == quad0 && (path->flags[i-1] & splashPathFirst), - gFalse, - quad == quad0 && !closeSubpaths && - (path->flags[i-1] & splashPathFirst) && - !(path->flags[i-1] & splashPathClosed), - gFalse); - x0 = x1; - y0 = y1; - quad = (quad + 1) & 3; - } - addArc(x0, y0, path->pts[i+1].x, path->pts[i+1].y, - xc, yc, r, quad, flatness, - quad == quad0 && (path->flags[i-1] & splashPathFirst), - (path->flags[i+1] & splashPathLast), - quad == quad0 && !closeSubpaths && - (path->flags[i-1] & splashPathFirst) && - !(path->flags[i-1] & splashPathClosed), - !closeSubpaths && - (path->flags[i+1] & splashPathLast) && - !(path->flags[i+1] & splashPathClosed)); - i += 2; - - // line segment - } else { - addSegment(path->pts[i-1].x, path->pts[i-1].y, - path->pts[i].x, path->pts[i].y, - path->flags[i-1] & splashPathFirst, - path->flags[i] & splashPathLast, - !closeSubpaths && - (path->flags[i-1] & splashPathFirst) && - !(path->flags[i-1] & splashPathClosed), - !closeSubpaths && - (path->flags[i] & splashPathLast) && - !(path->flags[i] & splashPathClosed)); - ++i; - } - - // close a subpath - if (closeSubpaths && - (path->flags[i-1] & splashPathLast) && - (path->pts[i-1].x != path->pts[curSubpath].x || - path->pts[i-1].y != path->pts[curSubpath]. y)) { - addSegment(path->pts[i-1].x, path->pts[i-1].y, - path->pts[curSubpath].x, path->pts[curSubpath].y, - gFalse, gTrue, gFalse, gFalse); - } - } - } -} - -SplashXPath::SplashXPath(SplashXPath *xPath) { - length = xPath->length; - size = xPath->size; - segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg)); - memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg)); -} - -SplashXPath::~SplashXPath() { - gfree(segs); -} - -// Add space for more segments -void SplashXPath::grow(int nSegs) { - if (length + nSegs > size) { - if (size == 0) { - size = 32; - } - while (size < length + nSegs) { - size *= 2; - } - segs = (SplashXPathSeg *)greallocn(segs, size, sizeof(SplashXPathSeg)); - } -} - -void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - SplashCoord x2, SplashCoord y2, - SplashCoord x3, SplashCoord y3, - SplashCoord flatness, - GBool first, GBool last, GBool end0, GBool end1) { - SplashCoord cx[maxCurveSplits + 1][3]; - SplashCoord cy[maxCurveSplits + 1][3]; - int cNext[maxCurveSplits + 1]; - SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; - SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; - SplashCoord dx, dy, mx, my, d1, d2, flatness2; - int p1, p2, p3; - - flatness2 = flatness * flatness; - - // initial segment - p1 = 0; - p2 = maxCurveSplits; - cx[p1][0] = x0; cy[p1][0] = y0; - cx[p1][1] = x1; cy[p1][1] = y1; - cx[p1][2] = x2; cy[p1][2] = y2; - cx[p2][0] = x3; cy[p2][0] = y3; - cNext[p1] = p2; - - while (p1 < maxCurveSplits) { - - // get the next segment - xl0 = cx[p1][0]; yl0 = cy[p1][0]; - xx1 = cx[p1][1]; yy1 = cy[p1][1]; - xx2 = cx[p1][2]; yy2 = cy[p1][2]; - p2 = cNext[p1]; - xr3 = cx[p2][0]; yr3 = cy[p2][0]; - - // compute the distances from the control points to the - // midpoint of the straight line (this is a bit of a hack, but - // it's much faster than computing the actual distances to the - // line) - mx = (xl0 + xr3) * 0.5; - my = (yl0 + yr3) * 0.5; - dx = xx1 - mx; - dy = yy1 - my; - d1 = dx*dx + dy*dy; - dx = xx2 - mx; - dy = yy2 - my; - d2 = dx*dx + dy*dy; - - // if the curve is flat enough, or no more subdivisions are - // allowed, add the straight line segment - if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { - addSegment(xl0, yl0, xr3, yr3, - p1 == 0 && first, - p2 == maxCurveSplits && last, - p1 == 0 && end0, - p2 == maxCurveSplits && end1); - p1 = p2; - - // otherwise, subdivide the curve - } else { - xl1 = (xl0 + xx1) * 0.5; - yl1 = (yl0 + yy1) * 0.5; - xh = (xx1 + xx2) * 0.5; - yh = (yy1 + yy2) * 0.5; - xl2 = (xl1 + xh) * 0.5; - yl2 = (yl1 + yh) * 0.5; - xr2 = (xx2 + xr3) * 0.5; - yr2 = (yy2 + yr3) * 0.5; - xr1 = (xh + xr2) * 0.5; - yr1 = (yh + yr2) * 0.5; - xr0 = (xl2 + xr1) * 0.5; - yr0 = (yl2 + yr1) * 0.5; - // add the new subdivision points - p3 = (p1 + p2) / 2; - cx[p1][1] = xl1; cy[p1][1] = yl1; - cx[p1][2] = xl2; cy[p1][2] = yl2; - cNext[p1] = p3; - cx[p3][0] = xr0; cy[p3][0] = yr0; - cx[p3][1] = xr1; cy[p3][1] = yr1; - cx[p3][2] = xr2; cy[p3][2] = yr2; - cNext[p3] = p2; - } - } -} - -void SplashXPath::addArc(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - SplashCoord xc, SplashCoord yc, - SplashCoord r, int quad, - SplashCoord flatness, - GBool first, GBool last, GBool end0, GBool end1) { - SplashCoord px[maxCurveSplits + 1]; - SplashCoord py[maxCurveSplits + 1]; - int pNext[maxCurveSplits + 1]; - SplashCoord r2, flatness2; - SplashCoord xx0, yy0, xx1, yy1, xm, ym, t, dx, dy; - int p1, p2, p3; - - r2 = r * r; - flatness2 = flatness * flatness; - - // initial segment - p1 = 0; - p2 = maxCurveSplits; - px[p1] = x0; py[p1] = y0; - px[p2] = x1; py[p2] = y1; - pNext[p1] = p2; - - while (p1 < maxCurveSplits) { - - // get the next segment - xx0 = px[p1]; yy0 = py[p1]; - p2 = pNext[p1]; - xx1 = px[p2]; yy1 = py[p2]; - - // compute the arc midpoint - t = (xx0 - xc) * (xx1 - xc) - (yy0 - yc) * (yy1 - yc); - xm = splashSqrt((SplashCoord)0.5 * (r2 + t)); - ym = splashSqrt((SplashCoord)0.5 * (r2 - t)); - switch (quad) { - case 0: xm = xc - xm; ym = yc - ym; break; - case 1: xm = xc + xm; ym = yc - ym; break; - case 2: xm = xc + xm; ym = yc + ym; break; - case 3: xm = xc - xm; ym = yc + ym; break; - } - - // compute distance from midpoint of straight segment to midpoint - // of arc - dx = (SplashCoord)0.5 * (xx0 + xx1) - xm; - dy = (SplashCoord)0.5 * (yy0 + yy1) - ym; - - // if the arc is flat enough, or no more subdivisions are allowed, - // add the straight line segment - if (p2 - p1 == 1 || dx * dx + dy * dy <= flatness2) { - addSegment(xx0, yy0, xx1, yy1, - p1 == 0 && first, - p2 == maxCurveSplits && last, - p1 == 0 && end0, - p2 == maxCurveSplits && end1); - p1 = p2; - - // otherwise, subdivide the arc - } else { - p3 = (p1 + p2) / 2; - px[p3] = xm; - py[p3] = ym; - pNext[p1] = p3; - pNext[p3] = p2; - } - } -} - -void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - GBool first, GBool last, GBool end0, GBool end1) { - grow(1); - segs[length].x0 = x0; - segs[length].y0 = y0; - segs[length].x1 = x1; - segs[length].y1 = y1; - segs[length].flags = 0; - if (first) { - segs[length].flags |= splashXPathFirst; - } - if (last) { - segs[length].flags |= splashXPathLast; - } - if (end0) { - segs[length].flags |= splashXPathEnd0; - } - if (end1) { - segs[length].flags |= splashXPathEnd1; - } - if (y1 == y0) { - segs[length].dxdy = segs[length].dydx = 0; - segs[length].flags |= splashXPathHoriz; - if (x1 == x0) { - segs[length].flags |= splashXPathVert; - } - } else if (x1 == x0) { - segs[length].dxdy = segs[length].dydx = 0; - segs[length].flags |= splashXPathVert; - } else { - segs[length].dxdy = (x1 - x0) / (y1 - y0); - segs[length].dydx = (SplashCoord)1 / segs[length].dxdy; - } - if (y0 > y1) { - segs[length].flags |= splashXPathFlip; - } - ++length; -} - -static int cmpXPathSegs(const void *arg0, const void *arg1) { - SplashXPathSeg *seg0 = (SplashXPathSeg *)arg0; - SplashXPathSeg *seg1 = (SplashXPathSeg *)arg1; - SplashCoord x0, y0, x1, y1; - - if (seg0->flags & splashXPathFlip) { - x0 = seg0->x1; - y0 = seg0->y1; - } else { - x0 = seg0->x0; - y0 = seg0->y0; - } - if (seg1->flags & splashXPathFlip) { - x1 = seg1->x1; - y1 = seg1->y1; - } else { - x1 = seg1->x0; - y1 = seg1->y0; - } - if (y0 != y1) { - return (y0 > y1) ? 1 : -1; - } - if (x0 != x1) { - return (x0 > x1) ? 1 : -1; - } - return 0; -} - -void SplashXPath::sort() { - qsort(segs, length, sizeof(SplashXPathSeg), &cmpXPathSegs); -} diff --git a/xpdf/splash/SplashXPath.h b/xpdf/splash/SplashXPath.h deleted file mode 100644 index a9fe9a2a6..000000000 --- a/xpdf/splash/SplashXPath.h +++ /dev/null @@ -1,92 +0,0 @@ -//======================================================================== -// -// SplashXPath.h -// -//======================================================================== - -#ifndef SPLASHXPATH_H -#define SPLASHXPATH_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashTypes.h" - -class SplashPath; - -//------------------------------------------------------------------------ -// SplashXPathSeg -//------------------------------------------------------------------------ - -struct SplashXPathSeg { - SplashCoord x0, y0; // first endpoint - SplashCoord x1, y1; // second endpoint - SplashCoord dxdy; // slope: delta-x / delta-y - SplashCoord dydx; // slope: delta-y / delta-x - Guint flags; -}; - -#define splashXPathFirst 0x01 // first segment of a subpath -#define splashXPathLast 0x02 // last segment of a subpath -#define splashXPathEnd0 0x04 // first endpoint is end of an open subpath -#define splashXPathEnd1 0x08 // second endpoint is end of an open subpath -#define splashXPathHoriz 0x10 // segment is vertical (y0 == y1) - // (dxdy is undef) -#define splashXPathVert 0x20 // segment is horizontal (x0 == x1) - // (dydx is undef) -#define splashXPathFlip 0x40 // y0 > y1 - -//------------------------------------------------------------------------ -// SplashXPath -//------------------------------------------------------------------------ - -class SplashXPath { -public: - - // Expands (converts to segments) and flattens (converts curves to - // lines) . If is true, closes all open - // subpaths. - SplashXPath(SplashPath *path, SplashCoord flatness, - GBool closeSubpaths); - - // Copy an expanded path. - SplashXPath *copy() { return new SplashXPath(this); } - - ~SplashXPath(); - - // Sort by upper coordinate (lower y), in y-major order. - void sort(); - -private: - - SplashXPath(); - SplashXPath(SplashXPath *xPath); - void grow(int nSegs); - void addCurve(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - SplashCoord x2, SplashCoord y2, - SplashCoord x3, SplashCoord y3, - SplashCoord flatness, - GBool first, GBool last, GBool end0, GBool end1); - void addArc(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - SplashCoord xc, SplashCoord yc, - SplashCoord r, int quad, - SplashCoord flatness, - GBool first, GBool last, GBool end0, GBool end1); - void addSegment(SplashCoord x0, SplashCoord y0, - SplashCoord x1, SplashCoord y1, - GBool first, GBool last, GBool end0, GBool end1); - - SplashXPathSeg *segs; - int length, size; // length and size of segs array - - friend class SplashXPathScanner; - friend class SplashClip; - friend class Splash; -}; - -#endif diff --git a/xpdf/splash/SplashXPathScanner.cc b/xpdf/splash/SplashXPathScanner.cc deleted file mode 100644 index 6c38d9354..000000000 --- a/xpdf/splash/SplashXPathScanner.cc +++ /dev/null @@ -1,285 +0,0 @@ -//======================================================================== -// -// SplashXPathScanner.cc -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "SplashMath.h" -#include "SplashXPath.h" -#include "SplashXPathScanner.h" - -//------------------------------------------------------------------------ - -struct SplashIntersect { - int x0, x1; // intersection of segment with [y, y+1) - int count; // EO/NZWN counter increment -}; - -static int cmpIntersect(const void *p0, const void *p1) { - return ((SplashIntersect *)p0)->x0 - ((SplashIntersect *)p1)->x0; -} - -//------------------------------------------------------------------------ -// SplashXPathScanner -//------------------------------------------------------------------------ - -SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA) { - SplashXPathSeg *seg; - SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP; - int i; - - xPath = xPathA; - eo = eoA; - - // compute the bbox - if (xPath->length == 0) { - xMin = yMin = 1; - xMax = yMax = 0; - } else { - seg = &xPath->segs[0]; - if (seg->x0 <= seg->x1) { - xMinFP = seg->x0; - xMaxFP = seg->x1; - } else { - xMinFP = seg->x1; - xMaxFP = seg->x0; - } - if (seg->flags & splashXPathFlip) { - yMinFP = seg->y1; - yMaxFP = seg->y0; - } else { - yMinFP = seg->y0; - yMaxFP = seg->y1; - } - for (i = 1; i < xPath->length; ++i) { - seg = &xPath->segs[i]; - if (seg->x0 < xMinFP) { - xMinFP = seg->x0; - } else if (seg->x0 > xMaxFP) { - xMaxFP = seg->x0; - } - if (seg->x1 < xMinFP) { - xMinFP = seg->x1; - } else if (seg->x1 > xMaxFP) { - xMaxFP = seg->x1; - } - if (seg->flags & splashXPathFlip) { - if (seg->y0 > yMaxFP) { - yMaxFP = seg->y0; - } - } else { - if (seg->y1 > yMaxFP) { - yMaxFP = seg->y1; - } - } - } - xMin = splashFloor(xMinFP); - xMax = splashFloor(xMaxFP); - yMin = splashFloor(yMinFP); - yMax = splashFloor(yMaxFP); - } - - interY = yMin - 1; - xPathIdx = 0; - inter = NULL; - interLen = interSize = 0; -} - -SplashXPathScanner::~SplashXPathScanner() { - gfree(inter); -} - -void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) { - if (interY != y) { - computeIntersections(y); - } - if (interLen > 0) { - *spanXMin = inter[0].x0; - *spanXMax = inter[interLen - 1].x1; - } else { - *spanXMin = xMax + 1; - *spanXMax = xMax; - } -} - -GBool SplashXPathScanner::test(int x, int y) { - int count, i; - - if (interY != y) { - computeIntersections(y); - } - count = 0; - for (i = 0; i < interLen && inter[i].x0 <= x; ++i) { - if (x <= inter[i].x1) { - return gTrue; - } - count += inter[i].count; - } - return eo ? (count & 1) : (count != 0); -} - -GBool SplashXPathScanner::testSpan(int x0, int x1, int y) { - int count, xx1, i; - - if (interY != y) { - computeIntersections(y); - } - - count = 0; - for (i = 0; i < interLen && inter[i].x1 < x0; ++i) { - count += inter[i].count; - } - - // invariant: the subspan [x0,xx1] is inside the path - xx1 = x0 - 1; - while (xx1 < x1) { - if (i >= interLen) { - return gFalse; - } - if (inter[i].x0 > xx1 + 1 && - !(eo ? (count & 1) : (count != 0))) { - return gFalse; - } - if (inter[i].x1 > xx1) { - xx1 = inter[i].x1; - } - count += inter[i].count; - ++i; - } - - return gTrue; -} - -GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) { - int xx0, xx1; - - if (interY != y) { - computeIntersections(y); - } - if (interIdx >= interLen) { - return gFalse; - } - xx0 = inter[interIdx].x0; - xx1 = inter[interIdx].x1; - interCount += inter[interIdx].count; - ++interIdx; - while (interIdx < interLen && - (inter[interIdx].x0 <= xx1 || - (eo ? (interCount & 1) : (interCount != 0)))) { - if (inter[interIdx].x1 > xx1) { - xx1 = inter[interIdx].x1; - } - interCount += inter[interIdx].count; - ++interIdx; - } - *x0 = xx0; - *x1 = xx1; - return gTrue; -} - -void SplashXPathScanner::computeIntersections(int y) { - SplashCoord xSegMin, xSegMax, ySegMin, ySegMax, xx0, xx1; - SplashXPathSeg *seg; - int i, j; - - // find the first segment that intersects [y, y+1) - i = (y >= interY) ? xPathIdx : 0; - while (i < xPath->length && - xPath->segs[i].y0 < y && xPath->segs[i].y1 < y) { - ++i; - } - xPathIdx = i; - - // find all of the segments that intersect [y, y+1) and create an - // Intersect element for each one - interLen = 0; - for (j = i; j < xPath->length; ++j) { - seg = &xPath->segs[j]; - if (seg->flags & splashXPathFlip) { - ySegMin = seg->y1; - ySegMax = seg->y0; - } else { - ySegMin = seg->y0; - ySegMax = seg->y1; - } - - // ensure that: ySegMin < y+1 - // y <= ySegMax - if (ySegMin >= y + 1) { - break; - } - if (ySegMax < y) { - continue; - } - - if (interLen == interSize) { - if (interSize == 0) { - interSize = 16; - } else { - interSize *= 2; - } - inter = (SplashIntersect *)greallocn(inter, interSize, - sizeof(SplashIntersect)); - } - - if (seg->flags & splashXPathHoriz) { - xx0 = seg->x0; - xx1 = seg->x1; - } else if (seg->flags & splashXPathVert) { - xx0 = xx1 = seg->x0; - } else { - if (seg->x0 < seg->x1) { - xSegMin = seg->x0; - xSegMax = seg->x1; - } else { - xSegMin = seg->x1; - xSegMax = seg->x0; - } - // intersection with top edge - xx0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy; - // intersection with bottom edge - xx1 = seg->x0 + ((SplashCoord)y + 1 - seg->y0) * seg->dxdy; - // the segment may not actually extend to the top and/or bottom edges - if (xx0 < xSegMin) { - xx0 = xSegMin; - } else if (xx0 > xSegMax) { - xx0 = xSegMax; - } - if (xx1 < xSegMin) { - xx1 = xSegMin; - } else if (xx1 > xSegMax) { - xx1 = xSegMax; - } - } - if (xx0 < xx1) { - inter[interLen].x0 = splashFloor(xx0); - inter[interLen].x1 = splashFloor(xx1); - } else { - inter[interLen].x0 = splashFloor(xx1); - inter[interLen].x1 = splashFloor(xx0); - } - if (ySegMin <= y && - (SplashCoord)y < ySegMax && - !(seg->flags & splashXPathHoriz)) { - inter[interLen].count = eo ? 1 - : (seg->flags & splashXPathFlip) ? 1 : -1; - } else { - inter[interLen].count = 0; - } - ++interLen; - } - - qsort(inter, interLen, sizeof(SplashIntersect), &cmpIntersect); - - interY = y; - interIdx = 0; - interCount = 0; -} diff --git a/xpdf/splash/SplashXPathScanner.h b/xpdf/splash/SplashXPathScanner.h deleted file mode 100644 index 62484ba32..000000000 --- a/xpdf/splash/SplashXPathScanner.h +++ /dev/null @@ -1,74 +0,0 @@ -//======================================================================== -// -// SplashXPathScanner.h -// -//======================================================================== - -#ifndef SPLASHXPATHSCANNER_H -#define SPLASHXPATHSCANNER_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "SplashTypes.h" - -class SplashXPath; -struct SplashIntersect; - -//------------------------------------------------------------------------ -// SplashXPathScanner -//------------------------------------------------------------------------ - -class SplashXPathScanner { -public: - - // Create a new SplashXPathScanner object. must be sorted. - SplashXPathScanner(SplashXPath *xPathA, GBool eoA); - - ~SplashXPathScanner(); - - // Return the path's bounding box. - void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) - { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } - - // Return the min/max x values for the span at . - void getSpanBounds(int y, int *spanXMin, int *spanXMax); - - // Returns true if (,) is inside the path. - GBool test(int x, int y); - - // Returns true if the entire span ([,], ) is inside the - // path. - GBool testSpan(int x0, int x1, int y); - - // Returns the next span inside the path at . If is - // different than the previous call to getNextSpan, this returns the - // first span at ; otherwise it returns the next span (relative - // to the previous call to getNextSpan). Returns false if there are - // no more spans at . - GBool getNextSpan(int y, int *x0, int *x1); - -private: - - void computeIntersections(int y); - - SplashXPath *xPath; - GBool eo; - int xMin, yMin, xMax, yMax; - - int interY; // current y value - int interIdx; // current index into - used by - // getNextSpan - int interCount; // current EO/NZWN counter - used by - // getNextSpan - int xPathIdx; // current index into - used by - // computeIntersections - SplashIntersect *inter; // intersections array for - int interLen; // number of intersections in - int interSize; // size of the array -}; - -#endif diff --git a/xpdf/xpdf/Annot.cc b/xpdf/xpdf/Annot.cc deleted file mode 100644 index 4e5041bce..000000000 --- a/xpdf/xpdf/Annot.cc +++ /dev/null @@ -1,316 +0,0 @@ -//======================================================================== -// -// Annot.cc -// -// Copyright 2000-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "Object.h" -#include "Catalog.h" -#include "Gfx.h" -#include "Lexer.h" -#include "Annot.h" -#include "UGString.h" - -//------------------------------------------------------------------------ -// Annot -//------------------------------------------------------------------------ - -Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) { - Object apObj, asObj, obj1, obj2; - GBool regen, isTextField; - double t; - - ok = gFalse; - xref = xrefA; - appearBuf = NULL; - - if (dict->lookup("Rect", &obj1)->isArray() && - obj1.arrayGetLength() == 4) { - //~ should check object types here - obj1.arrayGet(0, &obj2); - xMin = obj2.getNum(); - obj2.free(); - obj1.arrayGet(1, &obj2); - yMin = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2, &obj2); - xMax = obj2.getNum(); - obj2.free(); - obj1.arrayGet(3, &obj2); - yMax = obj2.getNum(); - obj2.free(); - if (xMin > xMax) { - t = xMin; xMin = xMax; xMax = t; - } - if (yMin > yMax) { - t = yMin; yMin = yMax; yMax = t; - } - } else { - //~ this should return an error - xMin = yMin = 0; - xMax = yMax = 1; - } - obj1.free(); - - // check if field apperances need to be regenerated - regen = gFalse; - if (acroForm) { - acroForm->lookup("NeedAppearances", &obj1); - if (obj1.isBool() && obj1.getBool()) { - regen = gTrue; - } - obj1.free(); - } - - // check for a text-type field - isTextField = dict->lookup("FT", &obj1)->isName("Tx"); - obj1.free(); - -#if 0 //~ appearance stream generation is not finished yet - if (regen && isTextField) { - generateAppearance(acroForm, dict); - } else { -#endif - if (dict->lookup("AP", &apObj)->isDict()) { - if (dict->lookup("AS", &asObj)->isName()) { - if (apObj.dictLookup("N", &obj1)->isDict()) { - if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) { - obj2.copy(&appearance); - ok = gTrue; - } else { - obj2.free(); - if (obj1.dictLookupNF("Off", &obj2)->isRef()) { - obj2.copy(&appearance); - ok = gTrue; - } - } - obj2.free(); - } - obj1.free(); - } else { - if (apObj.dictLookupNF("N", &obj1)->isRef()) { - obj1.copy(&appearance); - ok = gTrue; - } - obj1.free(); - } - asObj.free(); - } - apObj.free(); -#if 0 //~ appearance stream generation is not finished yet - } -#endif -} - -Annot::~Annot() { - appearance.free(); - if (appearBuf) { - delete appearBuf; - } -} - -void Annot::generateAppearance(Dict *acroForm, Dict *dict) { - MemStream *appearStream; - Object daObj, vObj, drObj, appearDict, obj1, obj2; - GString *daStr, *daStr1, *vStr, *s; - char buf[256]; - double fontSize; - int c; - int i0, i1; - - //~ DA can be inherited - if (dict->lookup("DA", &daObj)->isString()) { - daStr = daObj.getString(); - - // look for a font size - //~ may want to parse the DS entry in place of this (if it exists) - daStr1 = NULL; - fontSize = 10; - for (i1 = daStr->getLength() - 2; i1 >= 0; --i1) { - if (daStr->getChar(i1) == 'T' && daStr->getChar(i1+1) == 'f') { - for (--i1; i1 >= 0 && Lexer::isSpace(daStr->getChar(i1)); --i1) ; - for (i0 = i1; i0 >= 0 && !Lexer::isSpace(daStr->getChar(i0)); --i0) ; - if (i0 >= 0) { - ++i0; - ++i1; - s = new GString(daStr, i0, i1 - i0); - fontSize = atof(s->getCString()); - delete s; - - // autosize the font - if (fontSize == 0) { - fontSize = 0.67 * (yMax - yMin); - daStr1 = new GString(daStr, 0, i0); - sprintf(buf, "%.2f", fontSize); - daStr1->append(buf); - daStr1->append(daStr->getCString() + i1, - daStr->getLength() - i1); - } - } - break; - } - } - - // build the appearance stream contents - appearBuf = new GString(); - appearBuf->append("/Tx BMC\n"); - appearBuf->append("q BT\n"); - appearBuf->append(daStr1 ? daStr1 : daStr)->append("\n"); - if (dict->lookup("V", &vObj)->isString()) { - //~ handle quadding -- this requires finding the font and using - //~ the encoding and char widths - sprintf(buf, "1 0 0 1 %.2f %.2f Tm\n", 2.0, yMax - yMin - fontSize); - appearBuf->append(buf); - sprintf(buf, "%g TL\n", fontSize); - appearBuf->append(buf); - vStr = vObj.getString(); - i0 = 0; - while (i0 < vStr->getLength()) { - for (i1 = i0; - i1 < vStr->getLength() && - vStr->getChar(i1) != '\n' && vStr->getChar(i1) != '\r'; - ++i1) ; - if (i0 > 0) { - appearBuf->append("T*\n"); - } - appearBuf->append('('); - for (; i0 < i1; ++i0) { - c = vStr->getChar(i0); - if (c == '(' || c == ')' || c == '\\') { - appearBuf->append('\\'); - appearBuf->append(c); - } else if (c < 0x20 || c >= 0x80) { - sprintf(buf, "\\%03o", c); - appearBuf->append(buf); - } else { - appearBuf->append(c); - } - } - appearBuf->append(") Tj\n"); - if (i1 + 1 < vStr->getLength() && - vStr->getChar(i1) == '\r' && vStr->getChar(i1 + 1) == '\n') { - i0 = i1 + 2; - } else { - i0 = i1 + 1; - } - } - } - vObj.free(); - appearBuf->append("ET Q\n"); - appearBuf->append("EMC\n"); - - // build the appearance stream dictionary - appearDict.initDict(xref); - appearDict.dictAdd("Length", - obj1.initInt(appearBuf->getLength())); - appearDict.dictAdd("Subtype", obj1.initName("Form")); - obj1.initArray(xref); - obj1.arrayAdd(obj2.initReal(0)); - obj1.arrayAdd(obj2.initReal(0)); - obj1.arrayAdd(obj2.initReal(xMax - xMin)); - obj1.arrayAdd(obj2.initReal(yMax - yMin)); - appearDict.dictAdd("BBox", &obj1); - - // find the resource dictionary - dict->lookup("DR", &drObj); - if (!drObj.isDict()) { - dict->lookup("Parent", &obj1); - while (obj1.isDict()) { - drObj.free(); - obj1.dictLookup("DR", &drObj); - if (drObj.isDict()) { - break; - } - obj1.dictLookup("Parent", &obj2); - obj1.free(); - obj1 = obj2; - } - obj1.free(); - if (!drObj.isDict()) { - if (acroForm) { - drObj.free(); - acroForm->lookup("DR", &drObj); - } - } - } - if (drObj.isDict()) { - appearDict.dictAdd("Resources", drObj.copy(&obj1)); - } - drObj.free(); - - // build the appearance stream - appearStream = new MemStream(appearBuf->getCString(), 0, - appearBuf->getLength(), &appearDict); - appearance.initStream(appearStream); - ok = gTrue; - - if (daStr1) { - delete daStr1; - } - } - daObj.free(); -} - -void Annot::draw(Gfx *gfx) { - Object obj; - - if (appearance.fetch(xref, &obj)->isStream()) { - gfx->doAnnot(&obj, xMin, yMin, xMax, yMax); - } - obj.free(); -} - -//------------------------------------------------------------------------ -// Annots -//------------------------------------------------------------------------ - -Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) { - Dict *acroForm; - Annot *annot; - Object obj1; - int size; - int i; - - annots = NULL; - size = 0; - nAnnots = 0; - - acroForm = catalog->getAcroForm()->isDict() ? - catalog->getAcroForm()->getDict() : NULL; - if (annotsObj->isArray()) { - for (i = 0; i < annotsObj->arrayGetLength(); ++i) { - if (annotsObj->arrayGet(i, &obj1)->isDict()) { - annot = new Annot(xref, acroForm, obj1.getDict()); - if (annot->isOk()) { - if (nAnnots >= size) { - size += 16; - annots = (Annot **)greallocn(annots, size, sizeof(Annot *)); - } - annots[nAnnots++] = annot; - } else { - delete annot; - } - } - obj1.free(); - } - } -} - -Annots::~Annots() { - int i; - - for (i = 0; i < nAnnots; ++i) { - delete annots[i]; - } - gfree(annots); -} diff --git a/xpdf/xpdf/Annot.h b/xpdf/xpdf/Annot.h deleted file mode 100644 index f10cb0344..000000000 --- a/xpdf/xpdf/Annot.h +++ /dev/null @@ -1,73 +0,0 @@ -//======================================================================== -// -// Annot.h -// -// Copyright 2000-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef ANNOT_H -#define ANNOT_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -class XRef; -class Catalog; -class Gfx; - -//------------------------------------------------------------------------ -// Annot -//------------------------------------------------------------------------ - -class Annot { -public: - - Annot(XRef *xrefA, Dict *acroForm, Dict *dict); - ~Annot(); - GBool isOk() { return ok; } - - void draw(Gfx *gfx); - - // Get appearance object. - Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); } - -private: - - void generateAppearance(Dict *acroForm, Dict *dict); - - XRef *xref; // the xref table for this PDF file - Object appearance; // a reference to the Form XObject stream - // for the normal appearance - GString *appearBuf; - double xMin, yMin, // annotation rectangle - xMax, yMax; - GBool ok; -}; - -//------------------------------------------------------------------------ -// Annots -//------------------------------------------------------------------------ - -class Annots { -public: - - // Extract non-link annotations from array of annotations. - Annots(XRef *xref, Catalog *catalog, Object *annotsObj); - - ~Annots(); - - // Iterate through list of annotations. - int getNumAnnots() { return nAnnots; } - Annot *getAnnot(int i) { return annots[i]; } - -private: - - Annot **annots; - int nAnnots; -}; - -#endif diff --git a/xpdf/xpdf/Array.cc b/xpdf/xpdf/Array.cc deleted file mode 100644 index 8232037b0..000000000 --- a/xpdf/xpdf/Array.cc +++ /dev/null @@ -1,88 +0,0 @@ -//======================================================================== -// -// Array.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "Object.h" -#include "Array.h" - -//------------------------------------------------------------------------ -// Array -//------------------------------------------------------------------------ - -Array::Array(XRef *xrefA) { - xref = xrefA; - elems = NULL; - size = length = 0; - ref = 1; -} - -Array::~Array() { - int i; - - for (i = 0; i < length; ++i) - elems[i].free(); - gfree(elems); -} - -void Array::add(Object *elem) { - if (length == size) { - if (length == 0) { - size = 8; - } else { - size *= 2; - } - elems = (Object *)greallocn(elems, size, sizeof(Object)); - } - elems[length] = *elem; - ++length; -} - -Object *Array::get(int i, Object *obj) { - if (i < 0 || i >= length) { -#ifdef DEBUG_MEM - abort(); -#else - return obj->initNull(); -#endif - } - return elems[i].fetch(xref, obj); -} - -Object *Array::getNF(int i, Object *obj) { - if (i < 0 || i >= length) { -#ifdef DEBUG_MEM - abort(); -#else - return obj->initNull(); -#endif - } - return elems[i].copy(obj); -} - -GBool Array::getString(int i, GString *string) -{ - Object obj; - - if (getNF(i, &obj)->isString()) { - string->clear(); - string->append(obj.getString()); - obj.free(); - return gTrue; - } else { - obj.free(); - return gFalse; - } -} diff --git a/xpdf/xpdf/Array.h b/xpdf/xpdf/Array.h deleted file mode 100644 index 1ef65dba2..000000000 --- a/xpdf/xpdf/Array.h +++ /dev/null @@ -1,59 +0,0 @@ -//======================================================================== -// -// Array.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef ARRAY_H -#define ARRAY_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" - -class XRef; - -//------------------------------------------------------------------------ -// Array -//------------------------------------------------------------------------ - -class Array { -public: - - // Constructor. - Array(XRef *xrefA); - - // Destructor. - ~Array(); - - // Reference counting. - int incRef() { return ++ref; } - int decRef() { return --ref; } - - // Get number of elements. - int getLength() { return length; } - - // Add an element. - void add(Object *elem); - - // Accessors. - Object *get(int i, Object *obj); - Object *getNF(int i, Object *obj); - GBool getString(int i, GString *string); - -private: - - XRef *xref; // the xref table for this PDF file - Object *elems; // array of elements - int size; // size of array - int length; // number of elements in array - int ref; // reference count -}; - -#endif diff --git a/xpdf/xpdf/BuiltinFont.cc b/xpdf/xpdf/BuiltinFont.cc deleted file mode 100644 index 33c9fa5e1..000000000 --- a/xpdf/xpdf/BuiltinFont.cc +++ /dev/null @@ -1,65 +0,0 @@ -//======================================================================== -// -// BuiltinFont.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "FontEncodingTables.h" -#include "BuiltinFont.h" - -//------------------------------------------------------------------------ - -BuiltinFontWidths::BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA) { - int i, h; - - size = sizeA; - tab = (BuiltinFontWidth **)gmallocn(size, sizeof(BuiltinFontWidth *)); - for (i = 0; i < size; ++i) { - tab[i] = NULL; - } - for (i = 0; i < sizeA; ++i) { - h = hash(widths[i].name); - widths[i].next = tab[h]; - tab[h] = &widths[i]; - } -} - -BuiltinFontWidths::~BuiltinFontWidths() { - gfree(tab); -} - -GBool BuiltinFontWidths::getWidth(const char *name, Gushort *width) { - int h; - BuiltinFontWidth *p; - - h = hash(name); - for (p = tab[h]; p; p = p->next) { - if (!strcmp(p->name, name)) { - *width = p->width; - return gTrue; - } - } - return gFalse; -} - -int BuiltinFontWidths::hash(const char *name) { - const char *p; - unsigned int h; - - h = 0; - for (p = name; *p; ++p) { - h = 17 * h + (int)(*p & 0xff); - } - return (int)(h % size); -} diff --git a/xpdf/xpdf/BuiltinFont.h b/xpdf/xpdf/BuiltinFont.h deleted file mode 100644 index 9cddb0cee..000000000 --- a/xpdf/xpdf/BuiltinFont.h +++ /dev/null @@ -1,57 +0,0 @@ -//======================================================================== -// -// BuiltinFont.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef BUILTINFONT_H -#define BUILTINFONT_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -struct BuiltinFont; -class BuiltinFontWidths; - -//------------------------------------------------------------------------ - -struct BuiltinFont { - const char *name; - const char **defaultBaseEnc; - short ascent; - short descent; - short bbox[4]; - BuiltinFontWidths *widths; -}; - -//------------------------------------------------------------------------ - -struct BuiltinFontWidth { - const char *name; - Gushort width; - BuiltinFontWidth *next; -}; - -class BuiltinFontWidths { -public: - - BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA); - ~BuiltinFontWidths(); - GBool getWidth(const char *name, Gushort *width); - -private: - - int hash(const char *name); - - BuiltinFontWidth **tab; - int size; -}; - -#endif diff --git a/xpdf/xpdf/BuiltinFontTables.cc b/xpdf/xpdf/BuiltinFontTables.cc deleted file mode 100644 index 9c362389c..000000000 --- a/xpdf/xpdf/BuiltinFontTables.cc +++ /dev/null @@ -1,4284 +0,0 @@ -//======================================================================== -// -// BuiltinFontTables.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include -#include -#include "FontEncodingTables.h" -#include "BuiltinFontTables.h" - -static BuiltinFontWidth courierWidthsTab[] = { - { "Ntilde", 600, NULL }, - { "rcaron", 600, NULL }, - { "kcommaaccent", 600, NULL }, - { "Ncommaaccent", 600, NULL }, - { "Zacute", 600, NULL }, - { "comma", 600, NULL }, - { "cedilla", 600, NULL }, - { "plusminus", 600, NULL }, - { "circumflex", 600, NULL }, - { "dotaccent", 600, NULL }, - { "edotaccent", 600, NULL }, - { "asciitilde", 600, NULL }, - { "colon", 600, NULL }, - { "onehalf", 600, NULL }, - { "dollar", 600, NULL }, - { "Lcaron", 600, NULL }, - { "ntilde", 600, NULL }, - { "Aogonek", 600, NULL }, - { "ncommaaccent", 600, NULL }, - { "minus", 600, NULL }, - { "Iogonek", 600, NULL }, - { "zacute", 600, NULL }, - { "yen", 600, NULL }, - { "space", 600, NULL }, - { "Omacron", 600, NULL }, - { "questiondown", 600, NULL }, - { "emdash", 600, NULL }, - { "Agrave", 600, NULL }, - { "three", 600, NULL }, - { "numbersign", 600, NULL }, - { "lcaron", 600, NULL }, - { "A", 600, NULL }, - { "B", 600, NULL }, - { "C", 600, NULL }, - { "aogonek", 600, NULL }, - { "D", 600, NULL }, - { "E", 600, NULL }, - { "onequarter", 600, NULL }, - { "F", 600, NULL }, - { "G", 600, NULL }, - { "H", 600, NULL }, - { "I", 600, NULL }, - { "J", 600, NULL }, - { "K", 600, NULL }, - { "iogonek", 600, NULL }, - { "L", 600, NULL }, - { "backslash", 600, NULL }, - { "periodcentered", 600, NULL }, - { "M", 600, NULL }, - { "N", 600, NULL }, - { "omacron", 600, NULL }, - { "Tcommaaccent", 600, NULL }, - { "O", 600, NULL }, - { "P", 600, NULL }, - { "Q", 600, NULL }, - { "Uhungarumlaut", 600, NULL }, - { "R", 600, NULL }, - { "Aacute", 600, NULL }, - { "caron", 600, NULL }, - { "S", 600, NULL }, - { "T", 600, NULL }, - { "U", 600, NULL }, - { "agrave", 600, NULL }, - { "V", 600, NULL }, - { "W", 600, NULL }, - { "equal", 600, NULL }, - { "question", 600, NULL }, - { "X", 600, NULL }, - { "Y", 600, NULL }, - { "Z", 600, NULL }, - { "four", 600, NULL }, - { "a", 600, NULL }, - { "Gcommaaccent", 600, NULL }, - { "b", 600, NULL }, - { "c", 600, NULL }, - { "d", 600, NULL }, - { "e", 600, NULL }, - { "f", 600, NULL }, - { "g", 600, NULL }, - { "bullet", 600, NULL }, - { "h", 600, NULL }, - { "i", 600, NULL }, - { "Oslash", 600, NULL }, - { "dagger", 600, NULL }, - { "j", 600, NULL }, - { "k", 600, NULL }, - { "l", 600, NULL }, - { "m", 600, NULL }, - { "n", 600, NULL }, - { "tcommaaccent", 600, NULL }, - { "o", 600, NULL }, - { "ordfeminine", 600, NULL }, - { "ring", 600, NULL }, - { "p", 600, NULL }, - { "q", 600, NULL }, - { "uhungarumlaut", 600, NULL }, - { "r", 600, NULL }, - { "twosuperior", 600, NULL }, - { "aacute", 600, NULL }, - { "s", 600, NULL }, - { "OE", 600, NULL }, - { "t", 600, NULL }, - { "divide", 600, NULL }, - { "u", 600, NULL }, - { "Ccaron", 600, NULL }, - { "v", 600, NULL }, - { "w", 600, NULL }, - { "x", 600, NULL }, - { "y", 600, NULL }, - { "z", 600, NULL }, - { "Gbreve", 600, NULL }, - { "commaaccent", 600, NULL }, - { "hungarumlaut", 600, NULL }, - { "Idotaccent", 600, NULL }, - { "Nacute", 600, NULL }, - { "quotedbl", 600, NULL }, - { "gcommaaccent", 600, NULL }, - { "mu", 600, NULL }, - { "greaterequal", 600, NULL }, - { "Scaron", 600, NULL }, - { "Lslash", 600, NULL }, - { "semicolon", 600, NULL }, - { "oslash", 600, NULL }, - { "lessequal", 600, NULL }, - { "lozenge", 600, NULL }, - { "parenright", 600, NULL }, - { "ccaron", 600, NULL }, - { "Ecircumflex", 600, NULL }, - { "gbreve", 600, NULL }, - { "trademark", 600, NULL }, - { "daggerdbl", 600, NULL }, - { "nacute", 600, NULL }, - { "macron", 600, NULL }, - { "Otilde", 600, NULL }, - { "Emacron", 600, NULL }, - { "ellipsis", 600, NULL }, - { "scaron", 600, NULL }, - { "AE", 600, NULL }, - { "Ucircumflex", 600, NULL }, - { "lslash", 600, NULL }, - { "quotedblleft", 600, NULL }, - { "hyphen", 600, NULL }, - { "guilsinglright", 600, NULL }, - { "quotesingle", 600, NULL }, - { "eight", 600, NULL }, - { "exclamdown", 600, NULL }, - { "endash", 600, NULL }, - { "oe", 600, NULL }, - { "Abreve", 600, NULL }, - { "Umacron", 600, NULL }, - { "ecircumflex", 600, NULL }, - { "Adieresis", 600, NULL }, - { "copyright", 600, NULL }, - { "Egrave", 600, NULL }, - { "slash", 600, NULL }, - { "Edieresis", 600, NULL }, - { "otilde", 600, NULL }, - { "Idieresis", 600, NULL }, - { "parenleft", 600, NULL }, - { "one", 600, NULL }, - { "emacron", 600, NULL }, - { "Odieresis", 600, NULL }, - { "ucircumflex", 600, NULL }, - { "bracketleft", 600, NULL }, - { "Ugrave", 600, NULL }, - { "quoteright", 600, NULL }, - { "Udieresis", 600, NULL }, - { "perthousand", 600, NULL }, - { "Ydieresis", 600, NULL }, - { "umacron", 600, NULL }, - { "abreve", 600, NULL }, - { "Eacute", 600, NULL }, - { "adieresis", 600, NULL }, - { "egrave", 600, NULL }, - { "edieresis", 600, NULL }, - { "idieresis", 600, NULL }, - { "Eth", 600, NULL }, - { "ae", 600, NULL }, - { "asterisk", 600, NULL }, - { "odieresis", 600, NULL }, - { "Uacute", 600, NULL }, - { "ugrave", 600, NULL }, - { "five", 600, NULL }, - { "nine", 600, NULL }, - { "udieresis", 600, NULL }, - { "Zcaron", 600, NULL }, - { "Scommaaccent", 600, NULL }, - { "threequarters", 600, NULL }, - { "guillemotright", 600, NULL }, - { "Ccedilla", 600, NULL }, - { "ydieresis", 600, NULL }, - { "tilde", 600, NULL }, - { "at", 600, NULL }, - { "eacute", 600, NULL }, - { "underscore", 600, NULL }, - { "Euro", 600, NULL }, - { "Dcroat", 600, NULL }, - { "zero", 600, NULL }, - { "multiply", 600, NULL }, - { "eth", 600, NULL }, - { "Scedilla", 600, NULL }, - { "Racute", 600, NULL }, - { "Ograve", 600, NULL }, - { "partialdiff", 600, NULL }, - { "uacute", 600, NULL }, - { "braceleft", 600, NULL }, - { "Thorn", 600, NULL }, - { "zcaron", 600, NULL }, - { "scommaaccent", 600, NULL }, - { "ccedilla", 600, NULL }, - { "Dcaron", 600, NULL }, - { "dcroat", 600, NULL }, - { "scedilla", 600, NULL }, - { "Oacute", 600, NULL }, - { "Ocircumflex", 600, NULL }, - { "ogonek", 600, NULL }, - { "ograve", 600, NULL }, - { "racute", 600, NULL }, - { "Tcaron", 600, NULL }, - { "Eogonek", 600, NULL }, - { "thorn", 600, NULL }, - { "degree", 600, NULL }, - { "registered", 600, NULL }, - { "radical", 600, NULL }, - { "Aring", 600, NULL }, - { "percent", 600, NULL }, - { "six", 600, NULL }, - { "paragraph", 600, NULL }, - { "dcaron", 600, NULL }, - { "Uogonek", 600, NULL }, - { "two", 600, NULL }, - { "summation", 600, NULL }, - { "Igrave", 600, NULL }, - { "Lacute", 600, NULL }, - { "ocircumflex", 600, NULL }, - { "oacute", 600, NULL }, - { "Uring", 600, NULL }, - { "Lcommaaccent", 600, NULL }, - { "tcaron", 600, NULL }, - { "eogonek", 600, NULL }, - { "Delta", 600, NULL }, - { "Ohungarumlaut", 600, NULL }, - { "asciicircum", 600, NULL }, - { "aring", 600, NULL }, - { "grave", 600, NULL }, - { "uogonek", 600, NULL }, - { "bracketright", 600, NULL }, - { "ampersand", 600, NULL }, - { "Iacute", 600, NULL }, - { "lacute", 600, NULL }, - { "igrave", 600, NULL }, - { "Ncaron", 600, NULL }, - { "plus", 600, NULL }, - { "uring", 600, NULL }, - { "quotesinglbase", 600, NULL }, - { "lcommaaccent", 600, NULL }, - { "Yacute", 600, NULL }, - { "ohungarumlaut", 600, NULL }, - { "threesuperior", 600, NULL }, - { "acute", 600, NULL }, - { "section", 600, NULL }, - { "dieresis", 600, NULL }, - { "quotedblbase", 600, NULL }, - { "iacute", 600, NULL }, - { "ncaron", 600, NULL }, - { "florin", 600, NULL }, - { "yacute", 600, NULL }, - { "Rcommaaccent", 600, NULL }, - { "fi", 600, NULL }, - { "fl", 600, NULL }, - { "Acircumflex", 600, NULL }, - { "Cacute", 600, NULL }, - { "Icircumflex", 600, NULL }, - { "guillemotleft", 600, NULL }, - { "germandbls", 600, NULL }, - { "seven", 600, NULL }, - { "Amacron", 600, NULL }, - { "Sacute", 600, NULL }, - { "ordmasculine", 600, NULL }, - { "dotlessi", 600, NULL }, - { "sterling", 600, NULL }, - { "notequal", 600, NULL }, - { "Imacron", 600, NULL }, - { "rcommaaccent", 600, NULL }, - { "Zdotaccent", 600, NULL }, - { "acircumflex", 600, NULL }, - { "cacute", 600, NULL }, - { "Ecaron", 600, NULL }, - { "braceright", 600, NULL }, - { "icircumflex", 600, NULL }, - { "quotedblright", 600, NULL }, - { "amacron", 600, NULL }, - { "sacute", 600, NULL }, - { "imacron", 600, NULL }, - { "cent", 600, NULL }, - { "currency", 600, NULL }, - { "logicalnot", 600, NULL }, - { "zdotaccent", 600, NULL }, - { "Atilde", 600, NULL }, - { "breve", 600, NULL }, - { "bar", 600, NULL }, - { "fraction", 600, NULL }, - { "less", 600, NULL }, - { "ecaron", 600, NULL }, - { "guilsinglleft", 600, NULL }, - { "exclam", 600, NULL }, - { "period", 600, NULL }, - { "Rcaron", 600, NULL }, - { "Kcommaaccent", 600, NULL }, - { "greater", 600, NULL }, - { "atilde", 600, NULL }, - { "brokenbar", 600, NULL }, - { "quoteleft", 600, NULL }, - { "Edotaccent", 600, NULL }, - { "onesuperior", 600, NULL } -}; - -static BuiltinFontWidth courierBoldWidthsTab[] = { - { "Ntilde", 600, NULL }, - { "rcaron", 600, NULL }, - { "kcommaaccent", 600, NULL }, - { "Ncommaaccent", 600, NULL }, - { "Zacute", 600, NULL }, - { "comma", 600, NULL }, - { "cedilla", 600, NULL }, - { "plusminus", 600, NULL }, - { "circumflex", 600, NULL }, - { "dotaccent", 600, NULL }, - { "edotaccent", 600, NULL }, - { "asciitilde", 600, NULL }, - { "colon", 600, NULL }, - { "onehalf", 600, NULL }, - { "dollar", 600, NULL }, - { "Lcaron", 600, NULL }, - { "ntilde", 600, NULL }, - { "Aogonek", 600, NULL }, - { "ncommaaccent", 600, NULL }, - { "minus", 600, NULL }, - { "Iogonek", 600, NULL }, - { "zacute", 600, NULL }, - { "yen", 600, NULL }, - { "space", 600, NULL }, - { "Omacron", 600, NULL }, - { "questiondown", 600, NULL }, - { "emdash", 600, NULL }, - { "Agrave", 600, NULL }, - { "three", 600, NULL }, - { "numbersign", 600, NULL }, - { "lcaron", 600, NULL }, - { "A", 600, NULL }, - { "B", 600, NULL }, - { "C", 600, NULL }, - { "aogonek", 600, NULL }, - { "D", 600, NULL }, - { "E", 600, NULL }, - { "onequarter", 600, NULL }, - { "F", 600, NULL }, - { "G", 600, NULL }, - { "H", 600, NULL }, - { "I", 600, NULL }, - { "J", 600, NULL }, - { "K", 600, NULL }, - { "iogonek", 600, NULL }, - { "backslash", 600, NULL }, - { "L", 600, NULL }, - { "periodcentered", 600, NULL }, - { "M", 600, NULL }, - { "N", 600, NULL }, - { "omacron", 600, NULL }, - { "Tcommaaccent", 600, NULL }, - { "O", 600, NULL }, - { "P", 600, NULL }, - { "Q", 600, NULL }, - { "Uhungarumlaut", 600, NULL }, - { "R", 600, NULL }, - { "Aacute", 600, NULL }, - { "caron", 600, NULL }, - { "S", 600, NULL }, - { "T", 600, NULL }, - { "U", 600, NULL }, - { "agrave", 600, NULL }, - { "V", 600, NULL }, - { "W", 600, NULL }, - { "X", 600, NULL }, - { "question", 600, NULL }, - { "equal", 600, NULL }, - { "Y", 600, NULL }, - { "Z", 600, NULL }, - { "four", 600, NULL }, - { "a", 600, NULL }, - { "Gcommaaccent", 600, NULL }, - { "b", 600, NULL }, - { "c", 600, NULL }, - { "d", 600, NULL }, - { "e", 600, NULL }, - { "f", 600, NULL }, - { "g", 600, NULL }, - { "bullet", 600, NULL }, - { "h", 600, NULL }, - { "i", 600, NULL }, - { "Oslash", 600, NULL }, - { "dagger", 600, NULL }, - { "j", 600, NULL }, - { "k", 600, NULL }, - { "l", 600, NULL }, - { "m", 600, NULL }, - { "n", 600, NULL }, - { "tcommaaccent", 600, NULL }, - { "o", 600, NULL }, - { "ordfeminine", 600, NULL }, - { "ring", 600, NULL }, - { "p", 600, NULL }, - { "q", 600, NULL }, - { "uhungarumlaut", 600, NULL }, - { "r", 600, NULL }, - { "twosuperior", 600, NULL }, - { "aacute", 600, NULL }, - { "s", 600, NULL }, - { "OE", 600, NULL }, - { "t", 600, NULL }, - { "divide", 600, NULL }, - { "u", 600, NULL }, - { "Ccaron", 600, NULL }, - { "v", 600, NULL }, - { "w", 600, NULL }, - { "x", 600, NULL }, - { "y", 600, NULL }, - { "z", 600, NULL }, - { "Gbreve", 600, NULL }, - { "commaaccent", 600, NULL }, - { "hungarumlaut", 600, NULL }, - { "Idotaccent", 600, NULL }, - { "Nacute", 600, NULL }, - { "quotedbl", 600, NULL }, - { "gcommaaccent", 600, NULL }, - { "mu", 600, NULL }, - { "greaterequal", 600, NULL }, - { "Scaron", 600, NULL }, - { "Lslash", 600, NULL }, - { "semicolon", 600, NULL }, - { "oslash", 600, NULL }, - { "lessequal", 600, NULL }, - { "lozenge", 600, NULL }, - { "parenright", 600, NULL }, - { "ccaron", 600, NULL }, - { "Ecircumflex", 600, NULL }, - { "gbreve", 600, NULL }, - { "trademark", 600, NULL }, - { "daggerdbl", 600, NULL }, - { "nacute", 600, NULL }, - { "macron", 600, NULL }, - { "Otilde", 600, NULL }, - { "Emacron", 600, NULL }, - { "ellipsis", 600, NULL }, - { "scaron", 600, NULL }, - { "AE", 600, NULL }, - { "Ucircumflex", 600, NULL }, - { "lslash", 600, NULL }, - { "quotedblleft", 600, NULL }, - { "guilsinglright", 600, NULL }, - { "hyphen", 600, NULL }, - { "quotesingle", 600, NULL }, - { "eight", 600, NULL }, - { "exclamdown", 600, NULL }, - { "endash", 600, NULL }, - { "oe", 600, NULL }, - { "Abreve", 600, NULL }, - { "Umacron", 600, NULL }, - { "ecircumflex", 600, NULL }, - { "Adieresis", 600, NULL }, - { "copyright", 600, NULL }, - { "Egrave", 600, NULL }, - { "slash", 600, NULL }, - { "Edieresis", 600, NULL }, - { "otilde", 600, NULL }, - { "Idieresis", 600, NULL }, - { "parenleft", 600, NULL }, - { "one", 600, NULL }, - { "emacron", 600, NULL }, - { "Odieresis", 600, NULL }, - { "ucircumflex", 600, NULL }, - { "bracketleft", 600, NULL }, - { "Ugrave", 600, NULL }, - { "quoteright", 600, NULL }, - { "Udieresis", 600, NULL }, - { "perthousand", 600, NULL }, - { "Ydieresis", 600, NULL }, - { "umacron", 600, NULL }, - { "abreve", 600, NULL }, - { "Eacute", 600, NULL }, - { "adieresis", 600, NULL }, - { "egrave", 600, NULL }, - { "edieresis", 600, NULL }, - { "idieresis", 600, NULL }, - { "Eth", 600, NULL }, - { "ae", 600, NULL }, - { "asterisk", 600, NULL }, - { "odieresis", 600, NULL }, - { "Uacute", 600, NULL }, - { "ugrave", 600, NULL }, - { "nine", 600, NULL }, - { "five", 600, NULL }, - { "udieresis", 600, NULL }, - { "Zcaron", 600, NULL }, - { "Scommaaccent", 600, NULL }, - { "threequarters", 600, NULL }, - { "guillemotright", 600, NULL }, - { "Ccedilla", 600, NULL }, - { "ydieresis", 600, NULL }, - { "tilde", 600, NULL }, - { "at", 600, NULL }, - { "eacute", 600, NULL }, - { "underscore", 600, NULL }, - { "Euro", 600, NULL }, - { "Dcroat", 600, NULL }, - { "multiply", 600, NULL }, - { "zero", 600, NULL }, - { "eth", 600, NULL }, - { "Scedilla", 600, NULL }, - { "Ograve", 600, NULL }, - { "Racute", 600, NULL }, - { "partialdiff", 600, NULL }, - { "uacute", 600, NULL }, - { "braceleft", 600, NULL }, - { "Thorn", 600, NULL }, - { "zcaron", 600, NULL }, - { "scommaaccent", 600, NULL }, - { "ccedilla", 600, NULL }, - { "Dcaron", 600, NULL }, - { "dcroat", 600, NULL }, - { "Ocircumflex", 600, NULL }, - { "Oacute", 600, NULL }, - { "scedilla", 600, NULL }, - { "ogonek", 600, NULL }, - { "ograve", 600, NULL }, - { "racute", 600, NULL }, - { "Tcaron", 600, NULL }, - { "Eogonek", 600, NULL }, - { "thorn", 600, NULL }, - { "degree", 600, NULL }, - { "registered", 600, NULL }, - { "radical", 600, NULL }, - { "Aring", 600, NULL }, - { "percent", 600, NULL }, - { "six", 600, NULL }, - { "paragraph", 600, NULL }, - { "dcaron", 600, NULL }, - { "Uogonek", 600, NULL }, - { "two", 600, NULL }, - { "summation", 600, NULL }, - { "Igrave", 600, NULL }, - { "Lacute", 600, NULL }, - { "ocircumflex", 600, NULL }, - { "oacute", 600, NULL }, - { "Uring", 600, NULL }, - { "Lcommaaccent", 600, NULL }, - { "tcaron", 600, NULL }, - { "eogonek", 600, NULL }, - { "Delta", 600, NULL }, - { "Ohungarumlaut", 600, NULL }, - { "asciicircum", 600, NULL }, - { "aring", 600, NULL }, - { "grave", 600, NULL }, - { "uogonek", 600, NULL }, - { "bracketright", 600, NULL }, - { "Iacute", 600, NULL }, - { "ampersand", 600, NULL }, - { "igrave", 600, NULL }, - { "lacute", 600, NULL }, - { "Ncaron", 600, NULL }, - { "plus", 600, NULL }, - { "uring", 600, NULL }, - { "quotesinglbase", 600, NULL }, - { "lcommaaccent", 600, NULL }, - { "Yacute", 600, NULL }, - { "ohungarumlaut", 600, NULL }, - { "threesuperior", 600, NULL }, - { "acute", 600, NULL }, - { "section", 600, NULL }, - { "dieresis", 600, NULL }, - { "iacute", 600, NULL }, - { "quotedblbase", 600, NULL }, - { "ncaron", 600, NULL }, - { "florin", 600, NULL }, - { "yacute", 600, NULL }, - { "Rcommaaccent", 600, NULL }, - { "fi", 600, NULL }, - { "fl", 600, NULL }, - { "Acircumflex", 600, NULL }, - { "Cacute", 600, NULL }, - { "Icircumflex", 600, NULL }, - { "guillemotleft", 600, NULL }, - { "germandbls", 600, NULL }, - { "Amacron", 600, NULL }, - { "seven", 600, NULL }, - { "Sacute", 600, NULL }, - { "ordmasculine", 600, NULL }, - { "dotlessi", 600, NULL }, - { "sterling", 600, NULL }, - { "notequal", 600, NULL }, - { "Imacron", 600, NULL }, - { "rcommaaccent", 600, NULL }, - { "Zdotaccent", 600, NULL }, - { "acircumflex", 600, NULL }, - { "cacute", 600, NULL }, - { "Ecaron", 600, NULL }, - { "icircumflex", 600, NULL }, - { "braceright", 600, NULL }, - { "quotedblright", 600, NULL }, - { "amacron", 600, NULL }, - { "sacute", 600, NULL }, - { "imacron", 600, NULL }, - { "cent", 600, NULL }, - { "currency", 600, NULL }, - { "logicalnot", 600, NULL }, - { "zdotaccent", 600, NULL }, - { "Atilde", 600, NULL }, - { "breve", 600, NULL }, - { "bar", 600, NULL }, - { "fraction", 600, NULL }, - { "less", 600, NULL }, - { "ecaron", 600, NULL }, - { "guilsinglleft", 600, NULL }, - { "exclam", 600, NULL }, - { "period", 600, NULL }, - { "Rcaron", 600, NULL }, - { "Kcommaaccent", 600, NULL }, - { "greater", 600, NULL }, - { "atilde", 600, NULL }, - { "brokenbar", 600, NULL }, - { "quoteleft", 600, NULL }, - { "Edotaccent", 600, NULL }, - { "onesuperior", 600, NULL } -}; - -static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { - { "Ntilde", 600, NULL }, - { "rcaron", 600, NULL }, - { "kcommaaccent", 600, NULL }, - { "Ncommaaccent", 600, NULL }, - { "Zacute", 600, NULL }, - { "comma", 600, NULL }, - { "cedilla", 600, NULL }, - { "plusminus", 600, NULL }, - { "circumflex", 600, NULL }, - { "dotaccent", 600, NULL }, - { "edotaccent", 600, NULL }, - { "asciitilde", 600, NULL }, - { "colon", 600, NULL }, - { "onehalf", 600, NULL }, - { "dollar", 600, NULL }, - { "Lcaron", 600, NULL }, - { "ntilde", 600, NULL }, - { "Aogonek", 600, NULL }, - { "ncommaaccent", 600, NULL }, - { "minus", 600, NULL }, - { "Iogonek", 600, NULL }, - { "zacute", 600, NULL }, - { "yen", 600, NULL }, - { "space", 600, NULL }, - { "Omacron", 600, NULL }, - { "questiondown", 600, NULL }, - { "emdash", 600, NULL }, - { "Agrave", 600, NULL }, - { "three", 600, NULL }, - { "numbersign", 600, NULL }, - { "lcaron", 600, NULL }, - { "A", 600, NULL }, - { "B", 600, NULL }, - { "C", 600, NULL }, - { "aogonek", 600, NULL }, - { "D", 600, NULL }, - { "E", 600, NULL }, - { "onequarter", 600, NULL }, - { "F", 600, NULL }, - { "G", 600, NULL }, - { "H", 600, NULL }, - { "I", 600, NULL }, - { "J", 600, NULL }, - { "K", 600, NULL }, - { "iogonek", 600, NULL }, - { "backslash", 600, NULL }, - { "L", 600, NULL }, - { "periodcentered", 600, NULL }, - { "M", 600, NULL }, - { "N", 600, NULL }, - { "omacron", 600, NULL }, - { "Tcommaaccent", 600, NULL }, - { "O", 600, NULL }, - { "P", 600, NULL }, - { "Q", 600, NULL }, - { "Uhungarumlaut", 600, NULL }, - { "R", 600, NULL }, - { "Aacute", 600, NULL }, - { "caron", 600, NULL }, - { "S", 600, NULL }, - { "T", 600, NULL }, - { "U", 600, NULL }, - { "agrave", 600, NULL }, - { "V", 600, NULL }, - { "W", 600, NULL }, - { "X", 600, NULL }, - { "question", 600, NULL }, - { "equal", 600, NULL }, - { "Y", 600, NULL }, - { "Z", 600, NULL }, - { "four", 600, NULL }, - { "a", 600, NULL }, - { "Gcommaaccent", 600, NULL }, - { "b", 600, NULL }, - { "c", 600, NULL }, - { "d", 600, NULL }, - { "e", 600, NULL }, - { "f", 600, NULL }, - { "g", 600, NULL }, - { "bullet", 600, NULL }, - { "h", 600, NULL }, - { "i", 600, NULL }, - { "Oslash", 600, NULL }, - { "dagger", 600, NULL }, - { "j", 600, NULL }, - { "k", 600, NULL }, - { "l", 600, NULL }, - { "m", 600, NULL }, - { "n", 600, NULL }, - { "tcommaaccent", 600, NULL }, - { "o", 600, NULL }, - { "ordfeminine", 600, NULL }, - { "ring", 600, NULL }, - { "p", 600, NULL }, - { "q", 600, NULL }, - { "uhungarumlaut", 600, NULL }, - { "r", 600, NULL }, - { "twosuperior", 600, NULL }, - { "aacute", 600, NULL }, - { "s", 600, NULL }, - { "OE", 600, NULL }, - { "t", 600, NULL }, - { "divide", 600, NULL }, - { "u", 600, NULL }, - { "Ccaron", 600, NULL }, - { "v", 600, NULL }, - { "w", 600, NULL }, - { "x", 600, NULL }, - { "y", 600, NULL }, - { "z", 600, NULL }, - { "Gbreve", 600, NULL }, - { "commaaccent", 600, NULL }, - { "hungarumlaut", 600, NULL }, - { "Idotaccent", 600, NULL }, - { "Nacute", 600, NULL }, - { "quotedbl", 600, NULL }, - { "gcommaaccent", 600, NULL }, - { "mu", 600, NULL }, - { "greaterequal", 600, NULL }, - { "Scaron", 600, NULL }, - { "Lslash", 600, NULL }, - { "semicolon", 600, NULL }, - { "oslash", 600, NULL }, - { "lessequal", 600, NULL }, - { "lozenge", 600, NULL }, - { "parenright", 600, NULL }, - { "ccaron", 600, NULL }, - { "Ecircumflex", 600, NULL }, - { "gbreve", 600, NULL }, - { "trademark", 600, NULL }, - { "daggerdbl", 600, NULL }, - { "nacute", 600, NULL }, - { "macron", 600, NULL }, - { "Otilde", 600, NULL }, - { "Emacron", 600, NULL }, - { "ellipsis", 600, NULL }, - { "scaron", 600, NULL }, - { "AE", 600, NULL }, - { "Ucircumflex", 600, NULL }, - { "lslash", 600, NULL }, - { "quotedblleft", 600, NULL }, - { "guilsinglright", 600, NULL }, - { "hyphen", 600, NULL }, - { "quotesingle", 600, NULL }, - { "eight", 600, NULL }, - { "exclamdown", 600, NULL }, - { "endash", 600, NULL }, - { "oe", 600, NULL }, - { "Abreve", 600, NULL }, - { "Umacron", 600, NULL }, - { "ecircumflex", 600, NULL }, - { "Adieresis", 600, NULL }, - { "copyright", 600, NULL }, - { "Egrave", 600, NULL }, - { "slash", 600, NULL }, - { "Edieresis", 600, NULL }, - { "otilde", 600, NULL }, - { "Idieresis", 600, NULL }, - { "parenleft", 600, NULL }, - { "one", 600, NULL }, - { "emacron", 600, NULL }, - { "Odieresis", 600, NULL }, - { "ucircumflex", 600, NULL }, - { "bracketleft", 600, NULL }, - { "Ugrave", 600, NULL }, - { "quoteright", 600, NULL }, - { "Udieresis", 600, NULL }, - { "perthousand", 600, NULL }, - { "Ydieresis", 600, NULL }, - { "umacron", 600, NULL }, - { "abreve", 600, NULL }, - { "Eacute", 600, NULL }, - { "adieresis", 600, NULL }, - { "egrave", 600, NULL }, - { "edieresis", 600, NULL }, - { "idieresis", 600, NULL }, - { "Eth", 600, NULL }, - { "ae", 600, NULL }, - { "asterisk", 600, NULL }, - { "odieresis", 600, NULL }, - { "Uacute", 600, NULL }, - { "ugrave", 600, NULL }, - { "nine", 600, NULL }, - { "five", 600, NULL }, - { "udieresis", 600, NULL }, - { "Zcaron", 600, NULL }, - { "Scommaaccent", 600, NULL }, - { "threequarters", 600, NULL }, - { "guillemotright", 600, NULL }, - { "Ccedilla", 600, NULL }, - { "ydieresis", 600, NULL }, - { "tilde", 600, NULL }, - { "at", 600, NULL }, - { "eacute", 600, NULL }, - { "underscore", 600, NULL }, - { "Euro", 600, NULL }, - { "Dcroat", 600, NULL }, - { "multiply", 600, NULL }, - { "zero", 600, NULL }, - { "eth", 600, NULL }, - { "Scedilla", 600, NULL }, - { "Ograve", 600, NULL }, - { "Racute", 600, NULL }, - { "partialdiff", 600, NULL }, - { "uacute", 600, NULL }, - { "braceleft", 600, NULL }, - { "Thorn", 600, NULL }, - { "zcaron", 600, NULL }, - { "scommaaccent", 600, NULL }, - { "ccedilla", 600, NULL }, - { "Dcaron", 600, NULL }, - { "dcroat", 600, NULL }, - { "Ocircumflex", 600, NULL }, - { "Oacute", 600, NULL }, - { "scedilla", 600, NULL }, - { "ogonek", 600, NULL }, - { "ograve", 600, NULL }, - { "racute", 600, NULL }, - { "Tcaron", 600, NULL }, - { "Eogonek", 600, NULL }, - { "thorn", 600, NULL }, - { "degree", 600, NULL }, - { "registered", 600, NULL }, - { "radical", 600, NULL }, - { "Aring", 600, NULL }, - { "percent", 600, NULL }, - { "six", 600, NULL }, - { "paragraph", 600, NULL }, - { "dcaron", 600, NULL }, - { "Uogonek", 600, NULL }, - { "two", 600, NULL }, - { "summation", 600, NULL }, - { "Igrave", 600, NULL }, - { "Lacute", 600, NULL }, - { "ocircumflex", 600, NULL }, - { "oacute", 600, NULL }, - { "Uring", 600, NULL }, - { "Lcommaaccent", 600, NULL }, - { "tcaron", 600, NULL }, - { "eogonek", 600, NULL }, - { "Delta", 600, NULL }, - { "Ohungarumlaut", 600, NULL }, - { "asciicircum", 600, NULL }, - { "aring", 600, NULL }, - { "grave", 600, NULL }, - { "uogonek", 600, NULL }, - { "bracketright", 600, NULL }, - { "Iacute", 600, NULL }, - { "ampersand", 600, NULL }, - { "igrave", 600, NULL }, - { "lacute", 600, NULL }, - { "Ncaron", 600, NULL }, - { "plus", 600, NULL }, - { "uring", 600, NULL }, - { "quotesinglbase", 600, NULL }, - { "lcommaaccent", 600, NULL }, - { "Yacute", 600, NULL }, - { "ohungarumlaut", 600, NULL }, - { "threesuperior", 600, NULL }, - { "acute", 600, NULL }, - { "section", 600, NULL }, - { "dieresis", 600, NULL }, - { "iacute", 600, NULL }, - { "quotedblbase", 600, NULL }, - { "ncaron", 600, NULL }, - { "florin", 600, NULL }, - { "yacute", 600, NULL }, - { "Rcommaaccent", 600, NULL }, - { "fi", 600, NULL }, - { "fl", 600, NULL }, - { "Acircumflex", 600, NULL }, - { "Cacute", 600, NULL }, - { "Icircumflex", 600, NULL }, - { "guillemotleft", 600, NULL }, - { "germandbls", 600, NULL }, - { "Amacron", 600, NULL }, - { "seven", 600, NULL }, - { "Sacute", 600, NULL }, - { "ordmasculine", 600, NULL }, - { "dotlessi", 600, NULL }, - { "sterling", 600, NULL }, - { "notequal", 600, NULL }, - { "Imacron", 600, NULL }, - { "rcommaaccent", 600, NULL }, - { "Zdotaccent", 600, NULL }, - { "acircumflex", 600, NULL }, - { "cacute", 600, NULL }, - { "Ecaron", 600, NULL }, - { "icircumflex", 600, NULL }, - { "braceright", 600, NULL }, - { "quotedblright", 600, NULL }, - { "amacron", 600, NULL }, - { "sacute", 600, NULL }, - { "imacron", 600, NULL }, - { "cent", 600, NULL }, - { "currency", 600, NULL }, - { "logicalnot", 600, NULL }, - { "zdotaccent", 600, NULL }, - { "Atilde", 600, NULL }, - { "breve", 600, NULL }, - { "bar", 600, NULL }, - { "fraction", 600, NULL }, - { "less", 600, NULL }, - { "ecaron", 600, NULL }, - { "guilsinglleft", 600, NULL }, - { "exclam", 600, NULL }, - { "period", 600, NULL }, - { "Rcaron", 600, NULL }, - { "Kcommaaccent", 600, NULL }, - { "greater", 600, NULL }, - { "atilde", 600, NULL }, - { "brokenbar", 600, NULL }, - { "quoteleft", 600, NULL }, - { "Edotaccent", 600, NULL }, - { "onesuperior", 600, NULL } -}; - -static BuiltinFontWidth courierObliqueWidthsTab[] = { - { "Ntilde", 600, NULL }, - { "rcaron", 600, NULL }, - { "kcommaaccent", 600, NULL }, - { "Ncommaaccent", 600, NULL }, - { "Zacute", 600, NULL }, - { "comma", 600, NULL }, - { "cedilla", 600, NULL }, - { "plusminus", 600, NULL }, - { "circumflex", 600, NULL }, - { "dotaccent", 600, NULL }, - { "edotaccent", 600, NULL }, - { "asciitilde", 600, NULL }, - { "colon", 600, NULL }, - { "onehalf", 600, NULL }, - { "dollar", 600, NULL }, - { "Lcaron", 600, NULL }, - { "ntilde", 600, NULL }, - { "Aogonek", 600, NULL }, - { "ncommaaccent", 600, NULL }, - { "minus", 600, NULL }, - { "Iogonek", 600, NULL }, - { "zacute", 600, NULL }, - { "yen", 600, NULL }, - { "space", 600, NULL }, - { "Omacron", 600, NULL }, - { "questiondown", 600, NULL }, - { "emdash", 600, NULL }, - { "Agrave", 600, NULL }, - { "three", 600, NULL }, - { "numbersign", 600, NULL }, - { "lcaron", 600, NULL }, - { "A", 600, NULL }, - { "B", 600, NULL }, - { "C", 600, NULL }, - { "aogonek", 600, NULL }, - { "D", 600, NULL }, - { "E", 600, NULL }, - { "onequarter", 600, NULL }, - { "F", 600, NULL }, - { "G", 600, NULL }, - { "H", 600, NULL }, - { "I", 600, NULL }, - { "J", 600, NULL }, - { "K", 600, NULL }, - { "iogonek", 600, NULL }, - { "backslash", 600, NULL }, - { "L", 600, NULL }, - { "periodcentered", 600, NULL }, - { "M", 600, NULL }, - { "N", 600, NULL }, - { "omacron", 600, NULL }, - { "Tcommaaccent", 600, NULL }, - { "O", 600, NULL }, - { "P", 600, NULL }, - { "Q", 600, NULL }, - { "Uhungarumlaut", 600, NULL }, - { "R", 600, NULL }, - { "Aacute", 600, NULL }, - { "caron", 600, NULL }, - { "S", 600, NULL }, - { "T", 600, NULL }, - { "U", 600, NULL }, - { "agrave", 600, NULL }, - { "V", 600, NULL }, - { "W", 600, NULL }, - { "X", 600, NULL }, - { "question", 600, NULL }, - { "equal", 600, NULL }, - { "Y", 600, NULL }, - { "Z", 600, NULL }, - { "four", 600, NULL }, - { "a", 600, NULL }, - { "Gcommaaccent", 600, NULL }, - { "b", 600, NULL }, - { "c", 600, NULL }, - { "d", 600, NULL }, - { "e", 600, NULL }, - { "f", 600, NULL }, - { "g", 600, NULL }, - { "bullet", 600, NULL }, - { "h", 600, NULL }, - { "i", 600, NULL }, - { "Oslash", 600, NULL }, - { "dagger", 600, NULL }, - { "j", 600, NULL }, - { "k", 600, NULL }, - { "l", 600, NULL }, - { "m", 600, NULL }, - { "n", 600, NULL }, - { "tcommaaccent", 600, NULL }, - { "o", 600, NULL }, - { "ordfeminine", 600, NULL }, - { "ring", 600, NULL }, - { "p", 600, NULL }, - { "q", 600, NULL }, - { "uhungarumlaut", 600, NULL }, - { "r", 600, NULL }, - { "twosuperior", 600, NULL }, - { "aacute", 600, NULL }, - { "s", 600, NULL }, - { "OE", 600, NULL }, - { "t", 600, NULL }, - { "divide", 600, NULL }, - { "u", 600, NULL }, - { "Ccaron", 600, NULL }, - { "v", 600, NULL }, - { "w", 600, NULL }, - { "x", 600, NULL }, - { "y", 600, NULL }, - { "z", 600, NULL }, - { "Gbreve", 600, NULL }, - { "commaaccent", 600, NULL }, - { "hungarumlaut", 600, NULL }, - { "Idotaccent", 600, NULL }, - { "Nacute", 600, NULL }, - { "quotedbl", 600, NULL }, - { "gcommaaccent", 600, NULL }, - { "mu", 600, NULL }, - { "greaterequal", 600, NULL }, - { "Scaron", 600, NULL }, - { "Lslash", 600, NULL }, - { "semicolon", 600, NULL }, - { "oslash", 600, NULL }, - { "lessequal", 600, NULL }, - { "lozenge", 600, NULL }, - { "parenright", 600, NULL }, - { "ccaron", 600, NULL }, - { "Ecircumflex", 600, NULL }, - { "gbreve", 600, NULL }, - { "trademark", 600, NULL }, - { "daggerdbl", 600, NULL }, - { "nacute", 600, NULL }, - { "macron", 600, NULL }, - { "Otilde", 600, NULL }, - { "Emacron", 600, NULL }, - { "ellipsis", 600, NULL }, - { "scaron", 600, NULL }, - { "AE", 600, NULL }, - { "Ucircumflex", 600, NULL }, - { "lslash", 600, NULL }, - { "quotedblleft", 600, NULL }, - { "guilsinglright", 600, NULL }, - { "hyphen", 600, NULL }, - { "quotesingle", 600, NULL }, - { "eight", 600, NULL }, - { "exclamdown", 600, NULL }, - { "endash", 600, NULL }, - { "oe", 600, NULL }, - { "Abreve", 600, NULL }, - { "Umacron", 600, NULL }, - { "ecircumflex", 600, NULL }, - { "Adieresis", 600, NULL }, - { "copyright", 600, NULL }, - { "Egrave", 600, NULL }, - { "slash", 600, NULL }, - { "Edieresis", 600, NULL }, - { "otilde", 600, NULL }, - { "Idieresis", 600, NULL }, - { "parenleft", 600, NULL }, - { "one", 600, NULL }, - { "emacron", 600, NULL }, - { "Odieresis", 600, NULL }, - { "ucircumflex", 600, NULL }, - { "bracketleft", 600, NULL }, - { "Ugrave", 600, NULL }, - { "quoteright", 600, NULL }, - { "Udieresis", 600, NULL }, - { "perthousand", 600, NULL }, - { "Ydieresis", 600, NULL }, - { "umacron", 600, NULL }, - { "abreve", 600, NULL }, - { "Eacute", 600, NULL }, - { "adieresis", 600, NULL }, - { "egrave", 600, NULL }, - { "edieresis", 600, NULL }, - { "idieresis", 600, NULL }, - { "Eth", 600, NULL }, - { "ae", 600, NULL }, - { "asterisk", 600, NULL }, - { "odieresis", 600, NULL }, - { "Uacute", 600, NULL }, - { "ugrave", 600, NULL }, - { "nine", 600, NULL }, - { "five", 600, NULL }, - { "udieresis", 600, NULL }, - { "Zcaron", 600, NULL }, - { "Scommaaccent", 600, NULL }, - { "threequarters", 600, NULL }, - { "guillemotright", 600, NULL }, - { "Ccedilla", 600, NULL }, - { "ydieresis", 600, NULL }, - { "tilde", 600, NULL }, - { "at", 600, NULL }, - { "eacute", 600, NULL }, - { "underscore", 600, NULL }, - { "Euro", 600, NULL }, - { "Dcroat", 600, NULL }, - { "multiply", 600, NULL }, - { "zero", 600, NULL }, - { "eth", 600, NULL }, - { "Scedilla", 600, NULL }, - { "Ograve", 600, NULL }, - { "Racute", 600, NULL }, - { "partialdiff", 600, NULL }, - { "uacute", 600, NULL }, - { "braceleft", 600, NULL }, - { "Thorn", 600, NULL }, - { "zcaron", 600, NULL }, - { "scommaaccent", 600, NULL }, - { "ccedilla", 600, NULL }, - { "Dcaron", 600, NULL }, - { "dcroat", 600, NULL }, - { "Ocircumflex", 600, NULL }, - { "Oacute", 600, NULL }, - { "scedilla", 600, NULL }, - { "ogonek", 600, NULL }, - { "ograve", 600, NULL }, - { "racute", 600, NULL }, - { "Tcaron", 600, NULL }, - { "Eogonek", 600, NULL }, - { "thorn", 600, NULL }, - { "degree", 600, NULL }, - { "registered", 600, NULL }, - { "radical", 600, NULL }, - { "Aring", 600, NULL }, - { "percent", 600, NULL }, - { "six", 600, NULL }, - { "paragraph", 600, NULL }, - { "dcaron", 600, NULL }, - { "Uogonek", 600, NULL }, - { "two", 600, NULL }, - { "summation", 600, NULL }, - { "Igrave", 600, NULL }, - { "Lacute", 600, NULL }, - { "ocircumflex", 600, NULL }, - { "oacute", 600, NULL }, - { "Uring", 600, NULL }, - { "Lcommaaccent", 600, NULL }, - { "tcaron", 600, NULL }, - { "eogonek", 600, NULL }, - { "Delta", 600, NULL }, - { "Ohungarumlaut", 600, NULL }, - { "asciicircum", 600, NULL }, - { "aring", 600, NULL }, - { "grave", 600, NULL }, - { "uogonek", 600, NULL }, - { "bracketright", 600, NULL }, - { "Iacute", 600, NULL }, - { "ampersand", 600, NULL }, - { "igrave", 600, NULL }, - { "lacute", 600, NULL }, - { "Ncaron", 600, NULL }, - { "plus", 600, NULL }, - { "uring", 600, NULL }, - { "quotesinglbase", 600, NULL }, - { "lcommaaccent", 600, NULL }, - { "Yacute", 600, NULL }, - { "ohungarumlaut", 600, NULL }, - { "threesuperior", 600, NULL }, - { "acute", 600, NULL }, - { "section", 600, NULL }, - { "dieresis", 600, NULL }, - { "iacute", 600, NULL }, - { "quotedblbase", 600, NULL }, - { "ncaron", 600, NULL }, - { "florin", 600, NULL }, - { "yacute", 600, NULL }, - { "Rcommaaccent", 600, NULL }, - { "fi", 600, NULL }, - { "fl", 600, NULL }, - { "Acircumflex", 600, NULL }, - { "Cacute", 600, NULL }, - { "Icircumflex", 600, NULL }, - { "guillemotleft", 600, NULL }, - { "germandbls", 600, NULL }, - { "Amacron", 600, NULL }, - { "seven", 600, NULL }, - { "Sacute", 600, NULL }, - { "ordmasculine", 600, NULL }, - { "dotlessi", 600, NULL }, - { "sterling", 600, NULL }, - { "notequal", 600, NULL }, - { "Imacron", 600, NULL }, - { "rcommaaccent", 600, NULL }, - { "Zdotaccent", 600, NULL }, - { "acircumflex", 600, NULL }, - { "cacute", 600, NULL }, - { "Ecaron", 600, NULL }, - { "icircumflex", 600, NULL }, - { "braceright", 600, NULL }, - { "quotedblright", 600, NULL }, - { "amacron", 600, NULL }, - { "sacute", 600, NULL }, - { "imacron", 600, NULL }, - { "cent", 600, NULL }, - { "currency", 600, NULL }, - { "logicalnot", 600, NULL }, - { "zdotaccent", 600, NULL }, - { "Atilde", 600, NULL }, - { "breve", 600, NULL }, - { "bar", 600, NULL }, - { "fraction", 600, NULL }, - { "less", 600, NULL }, - { "ecaron", 600, NULL }, - { "guilsinglleft", 600, NULL }, - { "exclam", 600, NULL }, - { "period", 600, NULL }, - { "Rcaron", 600, NULL }, - { "Kcommaaccent", 600, NULL }, - { "greater", 600, NULL }, - { "atilde", 600, NULL }, - { "brokenbar", 600, NULL }, - { "quoteleft", 600, NULL }, - { "Edotaccent", 600, NULL }, - { "onesuperior", 600, NULL } -}; - -static BuiltinFontWidth helveticaWidthsTab[] = { - { "Ntilde", 722, NULL }, - { "rcaron", 333, NULL }, - { "kcommaaccent", 500, NULL }, - { "Ncommaaccent", 722, NULL }, - { "Zacute", 611, NULL }, - { "comma", 278, NULL }, - { "cedilla", 333, NULL }, - { "plusminus", 584, NULL }, - { "circumflex", 333, NULL }, - { "dotaccent", 333, NULL }, - { "edotaccent", 556, NULL }, - { "asciitilde", 584, NULL }, - { "colon", 278, NULL }, - { "onehalf", 834, NULL }, - { "dollar", 556, NULL }, - { "Lcaron", 556, NULL }, - { "ntilde", 556, NULL }, - { "Aogonek", 667, NULL }, - { "ncommaaccent", 556, NULL }, - { "minus", 584, NULL }, - { "Iogonek", 278, NULL }, - { "zacute", 500, NULL }, - { "yen", 556, NULL }, - { "space", 278, NULL }, - { "Omacron", 778, NULL }, - { "questiondown", 611, NULL }, - { "emdash", 1000, NULL }, - { "Agrave", 667, NULL }, - { "three", 556, NULL }, - { "numbersign", 556, NULL }, - { "lcaron", 299, NULL }, - { "A", 667, NULL }, - { "B", 667, NULL }, - { "C", 722, NULL }, - { "aogonek", 556, NULL }, - { "D", 722, NULL }, - { "E", 667, NULL }, - { "onequarter", 834, NULL }, - { "F", 611, NULL }, - { "G", 778, NULL }, - { "H", 722, NULL }, - { "I", 278, NULL }, - { "J", 500, NULL }, - { "K", 667, NULL }, - { "iogonek", 222, NULL }, - { "backslash", 278, NULL }, - { "L", 556, NULL }, - { "periodcentered", 278, NULL }, - { "M", 833, NULL }, - { "N", 722, NULL }, - { "omacron", 556, NULL }, - { "Tcommaaccent", 611, NULL }, - { "O", 778, NULL }, - { "P", 667, NULL }, - { "Q", 778, NULL }, - { "Uhungarumlaut", 722, NULL }, - { "R", 722, NULL }, - { "Aacute", 667, NULL }, - { "caron", 333, NULL }, - { "S", 667, NULL }, - { "T", 611, NULL }, - { "U", 722, NULL }, - { "agrave", 556, NULL }, - { "V", 667, NULL }, - { "W", 944, NULL }, - { "X", 667, NULL }, - { "question", 556, NULL }, - { "equal", 584, NULL }, - { "Y", 667, NULL }, - { "Z", 611, NULL }, - { "four", 556, NULL }, - { "a", 556, NULL }, - { "Gcommaaccent", 778, NULL }, - { "b", 556, NULL }, - { "c", 500, NULL }, - { "d", 556, NULL }, - { "e", 556, NULL }, - { "f", 278, NULL }, - { "g", 556, NULL }, - { "bullet", 350, NULL }, - { "h", 556, NULL }, - { "i", 222, NULL }, - { "Oslash", 778, NULL }, - { "dagger", 556, NULL }, - { "j", 222, NULL }, - { "k", 500, NULL }, - { "l", 222, NULL }, - { "m", 833, NULL }, - { "n", 556, NULL }, - { "tcommaaccent", 278, NULL }, - { "o", 556, NULL }, - { "ordfeminine", 370, NULL }, - { "ring", 333, NULL }, - { "p", 556, NULL }, - { "q", 556, NULL }, - { "uhungarumlaut", 556, NULL }, - { "r", 333, NULL }, - { "twosuperior", 333, NULL }, - { "aacute", 556, NULL }, - { "s", 500, NULL }, - { "OE", 1000, NULL }, - { "t", 278, NULL }, - { "divide", 584, NULL }, - { "u", 556, NULL }, - { "Ccaron", 722, NULL }, - { "v", 500, NULL }, - { "w", 722, NULL }, - { "x", 500, NULL }, - { "y", 500, NULL }, - { "z", 500, NULL }, - { "Gbreve", 778, NULL }, - { "commaaccent", 250, NULL }, - { "hungarumlaut", 333, NULL }, - { "Idotaccent", 278, NULL }, - { "Nacute", 722, NULL }, - { "quotedbl", 355, NULL }, - { "gcommaaccent", 556, NULL }, - { "mu", 556, NULL }, - { "greaterequal", 549, NULL }, - { "Scaron", 667, NULL }, - { "Lslash", 556, NULL }, - { "semicolon", 278, NULL }, - { "oslash", 611, NULL }, - { "lessequal", 549, NULL }, - { "lozenge", 471, NULL }, - { "parenright", 333, NULL }, - { "ccaron", 500, NULL }, - { "Ecircumflex", 667, NULL }, - { "gbreve", 556, NULL }, - { "trademark", 1000, NULL }, - { "daggerdbl", 556, NULL }, - { "nacute", 556, NULL }, - { "macron", 333, NULL }, - { "Otilde", 778, NULL }, - { "Emacron", 667, NULL }, - { "ellipsis", 1000, NULL }, - { "scaron", 500, NULL }, - { "AE", 1000, NULL }, - { "Ucircumflex", 722, NULL }, - { "lslash", 222, NULL }, - { "quotedblleft", 333, NULL }, - { "guilsinglright", 333, NULL }, - { "hyphen", 333, NULL }, - { "quotesingle", 191, NULL }, - { "eight", 556, NULL }, - { "exclamdown", 333, NULL }, - { "endash", 556, NULL }, - { "oe", 944, NULL }, - { "Abreve", 667, NULL }, - { "Umacron", 722, NULL }, - { "ecircumflex", 556, NULL }, - { "Adieresis", 667, NULL }, - { "copyright", 737, NULL }, - { "Egrave", 667, NULL }, - { "slash", 278, NULL }, - { "Edieresis", 667, NULL }, - { "otilde", 556, NULL }, - { "Idieresis", 278, NULL }, - { "parenleft", 333, NULL }, - { "one", 556, NULL }, - { "emacron", 556, NULL }, - { "Odieresis", 778, NULL }, - { "ucircumflex", 556, NULL }, - { "bracketleft", 278, NULL }, - { "Ugrave", 722, NULL }, - { "quoteright", 222, NULL }, - { "Udieresis", 722, NULL }, - { "perthousand", 1000, NULL }, - { "Ydieresis", 667, NULL }, - { "umacron", 556, NULL }, - { "abreve", 556, NULL }, - { "Eacute", 667, NULL }, - { "adieresis", 556, NULL }, - { "egrave", 556, NULL }, - { "edieresis", 556, NULL }, - { "idieresis", 278, NULL }, - { "Eth", 722, NULL }, - { "ae", 889, NULL }, - { "asterisk", 389, NULL }, - { "odieresis", 556, NULL }, - { "Uacute", 722, NULL }, - { "ugrave", 556, NULL }, - { "nine", 556, NULL }, - { "five", 556, NULL }, - { "udieresis", 556, NULL }, - { "Zcaron", 611, NULL }, - { "Scommaaccent", 667, NULL }, - { "threequarters", 834, NULL }, - { "guillemotright", 556, NULL }, - { "Ccedilla", 722, NULL }, - { "ydieresis", 500, NULL }, - { "tilde", 333, NULL }, - { "at", 1015, NULL }, - { "eacute", 556, NULL }, - { "underscore", 556, NULL }, - { "Euro", 556, NULL }, - { "Dcroat", 722, NULL }, - { "multiply", 584, NULL }, - { "zero", 556, NULL }, - { "eth", 556, NULL }, - { "Scedilla", 667, NULL }, - { "Ograve", 778, NULL }, - { "Racute", 722, NULL }, - { "partialdiff", 476, NULL }, - { "uacute", 556, NULL }, - { "braceleft", 334, NULL }, - { "Thorn", 667, NULL }, - { "zcaron", 500, NULL }, - { "scommaaccent", 500, NULL }, - { "ccedilla", 500, NULL }, - { "Dcaron", 722, NULL }, - { "dcroat", 556, NULL }, - { "Ocircumflex", 778, NULL }, - { "Oacute", 778, NULL }, - { "scedilla", 500, NULL }, - { "ogonek", 333, NULL }, - { "ograve", 556, NULL }, - { "racute", 333, NULL }, - { "Tcaron", 611, NULL }, - { "Eogonek", 667, NULL }, - { "thorn", 556, NULL }, - { "degree", 400, NULL }, - { "registered", 737, NULL }, - { "radical", 453, NULL }, - { "Aring", 667, NULL }, - { "percent", 889, NULL }, - { "six", 556, NULL }, - { "paragraph", 537, NULL }, - { "dcaron", 643, NULL }, - { "Uogonek", 722, NULL }, - { "two", 556, NULL }, - { "summation", 600, NULL }, - { "Igrave", 278, NULL }, - { "Lacute", 556, NULL }, - { "ocircumflex", 556, NULL }, - { "oacute", 556, NULL }, - { "Uring", 722, NULL }, - { "Lcommaaccent", 556, NULL }, - { "tcaron", 317, NULL }, - { "eogonek", 556, NULL }, - { "Delta", 612, NULL }, - { "Ohungarumlaut", 778, NULL }, - { "asciicircum", 469, NULL }, - { "aring", 556, NULL }, - { "grave", 333, NULL }, - { "uogonek", 556, NULL }, - { "bracketright", 278, NULL }, - { "Iacute", 278, NULL }, - { "ampersand", 667, NULL }, - { "igrave", 278, NULL }, - { "lacute", 222, NULL }, - { "Ncaron", 722, NULL }, - { "plus", 584, NULL }, - { "uring", 556, NULL }, - { "quotesinglbase", 222, NULL }, - { "lcommaaccent", 222, NULL }, - { "Yacute", 667, NULL }, - { "ohungarumlaut", 556, NULL }, - { "threesuperior", 333, NULL }, - { "acute", 333, NULL }, - { "section", 556, NULL }, - { "dieresis", 333, NULL }, - { "iacute", 278, NULL }, - { "quotedblbase", 333, NULL }, - { "ncaron", 556, NULL }, - { "florin", 556, NULL }, - { "yacute", 500, NULL }, - { "Rcommaaccent", 722, NULL }, - { "fi", 500, NULL }, - { "fl", 500, NULL }, - { "Acircumflex", 667, NULL }, - { "Cacute", 722, NULL }, - { "Icircumflex", 278, NULL }, - { "guillemotleft", 556, NULL }, - { "germandbls", 611, NULL }, - { "Amacron", 667, NULL }, - { "seven", 556, NULL }, - { "Sacute", 667, NULL }, - { "ordmasculine", 365, NULL }, - { "dotlessi", 278, NULL }, - { "sterling", 556, NULL }, - { "notequal", 549, NULL }, - { "Imacron", 278, NULL }, - { "rcommaaccent", 333, NULL }, - { "Zdotaccent", 611, NULL }, - { "acircumflex", 556, NULL }, - { "cacute", 500, NULL }, - { "Ecaron", 667, NULL }, - { "icircumflex", 278, NULL }, - { "braceright", 334, NULL }, - { "quotedblright", 333, NULL }, - { "amacron", 556, NULL }, - { "sacute", 500, NULL }, - { "imacron", 278, NULL }, - { "cent", 556, NULL }, - { "currency", 556, NULL }, - { "logicalnot", 584, NULL }, - { "zdotaccent", 500, NULL }, - { "Atilde", 667, NULL }, - { "breve", 333, NULL }, - { "bar", 260, NULL }, - { "fraction", 167, NULL }, - { "less", 584, NULL }, - { "ecaron", 556, NULL }, - { "guilsinglleft", 333, NULL }, - { "exclam", 278, NULL }, - { "period", 278, NULL }, - { "Rcaron", 722, NULL }, - { "Kcommaaccent", 667, NULL }, - { "greater", 584, NULL }, - { "atilde", 556, NULL }, - { "brokenbar", 260, NULL }, - { "quoteleft", 222, NULL }, - { "Edotaccent", 667, NULL }, - { "onesuperior", 333, NULL } -}; - -static BuiltinFontWidth helveticaBoldWidthsTab[] = { - { "Ntilde", 722, NULL }, - { "rcaron", 389, NULL }, - { "kcommaaccent", 556, NULL }, - { "Ncommaaccent", 722, NULL }, - { "Zacute", 611, NULL }, - { "comma", 278, NULL }, - { "cedilla", 333, NULL }, - { "plusminus", 584, NULL }, - { "circumflex", 333, NULL }, - { "dotaccent", 333, NULL }, - { "edotaccent", 556, NULL }, - { "asciitilde", 584, NULL }, - { "colon", 333, NULL }, - { "onehalf", 834, NULL }, - { "dollar", 556, NULL }, - { "Lcaron", 611, NULL }, - { "ntilde", 611, NULL }, - { "Aogonek", 722, NULL }, - { "ncommaaccent", 611, NULL }, - { "minus", 584, NULL }, - { "Iogonek", 278, NULL }, - { "zacute", 500, NULL }, - { "yen", 556, NULL }, - { "space", 278, NULL }, - { "Omacron", 778, NULL }, - { "questiondown", 611, NULL }, - { "emdash", 1000, NULL }, - { "Agrave", 722, NULL }, - { "three", 556, NULL }, - { "numbersign", 556, NULL }, - { "lcaron", 400, NULL }, - { "A", 722, NULL }, - { "B", 722, NULL }, - { "C", 722, NULL }, - { "aogonek", 556, NULL }, - { "D", 722, NULL }, - { "E", 667, NULL }, - { "onequarter", 834, NULL }, - { "F", 611, NULL }, - { "G", 778, NULL }, - { "H", 722, NULL }, - { "I", 278, NULL }, - { "J", 556, NULL }, - { "K", 722, NULL }, - { "iogonek", 278, NULL }, - { "backslash", 278, NULL }, - { "L", 611, NULL }, - { "periodcentered", 278, NULL }, - { "M", 833, NULL }, - { "N", 722, NULL }, - { "omacron", 611, NULL }, - { "Tcommaaccent", 611, NULL }, - { "O", 778, NULL }, - { "P", 667, NULL }, - { "Q", 778, NULL }, - { "Uhungarumlaut", 722, NULL }, - { "R", 722, NULL }, - { "Aacute", 722, NULL }, - { "caron", 333, NULL }, - { "S", 667, NULL }, - { "T", 611, NULL }, - { "U", 722, NULL }, - { "agrave", 556, NULL }, - { "V", 667, NULL }, - { "W", 944, NULL }, - { "X", 667, NULL }, - { "question", 611, NULL }, - { "equal", 584, NULL }, - { "Y", 667, NULL }, - { "Z", 611, NULL }, - { "four", 556, NULL }, - { "a", 556, NULL }, - { "Gcommaaccent", 778, NULL }, - { "b", 611, NULL }, - { "c", 556, NULL }, - { "d", 611, NULL }, - { "e", 556, NULL }, - { "f", 333, NULL }, - { "g", 611, NULL }, - { "bullet", 350, NULL }, - { "h", 611, NULL }, - { "i", 278, NULL }, - { "Oslash", 778, NULL }, - { "dagger", 556, NULL }, - { "j", 278, NULL }, - { "k", 556, NULL }, - { "l", 278, NULL }, - { "m", 889, NULL }, - { "n", 611, NULL }, - { "tcommaaccent", 333, NULL }, - { "o", 611, NULL }, - { "ordfeminine", 370, NULL }, - { "ring", 333, NULL }, - { "p", 611, NULL }, - { "q", 611, NULL }, - { "uhungarumlaut", 611, NULL }, - { "r", 389, NULL }, - { "twosuperior", 333, NULL }, - { "aacute", 556, NULL }, - { "s", 556, NULL }, - { "OE", 1000, NULL }, - { "t", 333, NULL }, - { "divide", 584, NULL }, - { "u", 611, NULL }, - { "Ccaron", 722, NULL }, - { "v", 556, NULL }, - { "w", 778, NULL }, - { "x", 556, NULL }, - { "y", 556, NULL }, - { "z", 500, NULL }, - { "Gbreve", 778, NULL }, - { "commaaccent", 250, NULL }, - { "hungarumlaut", 333, NULL }, - { "Idotaccent", 278, NULL }, - { "Nacute", 722, NULL }, - { "quotedbl", 474, NULL }, - { "gcommaaccent", 611, NULL }, - { "mu", 611, NULL }, - { "greaterequal", 549, NULL }, - { "Scaron", 667, NULL }, - { "Lslash", 611, NULL }, - { "semicolon", 333, NULL }, - { "oslash", 611, NULL }, - { "lessequal", 549, NULL }, - { "lozenge", 494, NULL }, - { "parenright", 333, NULL }, - { "ccaron", 556, NULL }, - { "Ecircumflex", 667, NULL }, - { "gbreve", 611, NULL }, - { "trademark", 1000, NULL }, - { "daggerdbl", 556, NULL }, - { "nacute", 611, NULL }, - { "macron", 333, NULL }, - { "Otilde", 778, NULL }, - { "Emacron", 667, NULL }, - { "ellipsis", 1000, NULL }, - { "scaron", 556, NULL }, - { "AE", 1000, NULL }, - { "Ucircumflex", 722, NULL }, - { "lslash", 278, NULL }, - { "quotedblleft", 500, NULL }, - { "guilsinglright", 333, NULL }, - { "hyphen", 333, NULL }, - { "quotesingle", 238, NULL }, - { "eight", 556, NULL }, - { "exclamdown", 333, NULL }, - { "endash", 556, NULL }, - { "oe", 944, NULL }, - { "Abreve", 722, NULL }, - { "Umacron", 722, NULL }, - { "ecircumflex", 556, NULL }, - { "Adieresis", 722, NULL }, - { "copyright", 737, NULL }, - { "Egrave", 667, NULL }, - { "slash", 278, NULL }, - { "Edieresis", 667, NULL }, - { "otilde", 611, NULL }, - { "Idieresis", 278, NULL }, - { "parenleft", 333, NULL }, - { "one", 556, NULL }, - { "emacron", 556, NULL }, - { "Odieresis", 778, NULL }, - { "ucircumflex", 611, NULL }, - { "bracketleft", 333, NULL }, - { "Ugrave", 722, NULL }, - { "quoteright", 278, NULL }, - { "Udieresis", 722, NULL }, - { "perthousand", 1000, NULL }, - { "Ydieresis", 667, NULL }, - { "umacron", 611, NULL }, - { "abreve", 556, NULL }, - { "Eacute", 667, NULL }, - { "adieresis", 556, NULL }, - { "egrave", 556, NULL }, - { "edieresis", 556, NULL }, - { "idieresis", 278, NULL }, - { "Eth", 722, NULL }, - { "ae", 889, NULL }, - { "asterisk", 389, NULL }, - { "odieresis", 611, NULL }, - { "Uacute", 722, NULL }, - { "ugrave", 611, NULL }, - { "nine", 556, NULL }, - { "five", 556, NULL }, - { "udieresis", 611, NULL }, - { "Zcaron", 611, NULL }, - { "Scommaaccent", 667, NULL }, - { "threequarters", 834, NULL }, - { "guillemotright", 556, NULL }, - { "Ccedilla", 722, NULL }, - { "ydieresis", 556, NULL }, - { "tilde", 333, NULL }, - { "dbldaggerumlaut", 556, NULL }, - { "at", 975, NULL }, - { "eacute", 556, NULL }, - { "underscore", 556, NULL }, - { "Euro", 556, NULL }, - { "Dcroat", 722, NULL }, - { "multiply", 584, NULL }, - { "zero", 556, NULL }, - { "eth", 611, NULL }, - { "Scedilla", 667, NULL }, - { "Ograve", 778, NULL }, - { "Racute", 722, NULL }, - { "partialdiff", 494, NULL }, - { "uacute", 611, NULL }, - { "braceleft", 389, NULL }, - { "Thorn", 667, NULL }, - { "zcaron", 500, NULL }, - { "scommaaccent", 556, NULL }, - { "ccedilla", 556, NULL }, - { "Dcaron", 722, NULL }, - { "dcroat", 611, NULL }, - { "Ocircumflex", 778, NULL }, - { "Oacute", 778, NULL }, - { "scedilla", 556, NULL }, - { "ogonek", 333, NULL }, - { "ograve", 611, NULL }, - { "racute", 389, NULL }, - { "Tcaron", 611, NULL }, - { "Eogonek", 667, NULL }, - { "thorn", 611, NULL }, - { "degree", 400, NULL }, - { "registered", 737, NULL }, - { "radical", 549, NULL }, - { "Aring", 722, NULL }, - { "percent", 889, NULL }, - { "six", 556, NULL }, - { "paragraph", 556, NULL }, - { "dcaron", 743, NULL }, - { "Uogonek", 722, NULL }, - { "two", 556, NULL }, - { "summation", 600, NULL }, - { "Igrave", 278, NULL }, - { "Lacute", 611, NULL }, - { "ocircumflex", 611, NULL }, - { "oacute", 611, NULL }, - { "Uring", 722, NULL }, - { "Lcommaaccent", 611, NULL }, - { "tcaron", 389, NULL }, - { "eogonek", 556, NULL }, - { "Delta", 612, NULL }, - { "Ohungarumlaut", 778, NULL }, - { "asciicircum", 584, NULL }, - { "aring", 556, NULL }, - { "grave", 333, NULL }, - { "uogonek", 611, NULL }, - { "bracketright", 333, NULL }, - { "Iacute", 278, NULL }, - { "ampersand", 722, NULL }, - { "igrave", 278, NULL }, - { "lacute", 278, NULL }, - { "Ncaron", 722, NULL }, - { "plus", 584, NULL }, - { "uring", 611, NULL }, - { "quotesinglbase", 278, NULL }, - { "lcommaaccent", 278, NULL }, - { "Yacute", 667, NULL }, - { "ohungarumlaut", 611, NULL }, - { "threesuperior", 333, NULL }, - { "acute", 333, NULL }, - { "section", 556, NULL }, - { "dieresis", 333, NULL }, - { "iacute", 278, NULL }, - { "quotedblbase", 500, NULL }, - { "ncaron", 611, NULL }, - { "florin", 556, NULL }, - { "yacute", 556, NULL }, - { "Rcommaaccent", 722, NULL }, - { "fi", 611, NULL }, - { "fl", 611, NULL }, - { "Acircumflex", 722, NULL }, - { "Cacute", 722, NULL }, - { "Icircumflex", 278, NULL }, - { "guillemotleft", 556, NULL }, - { "germandbls", 611, NULL }, - { "Amacron", 722, NULL }, - { "seven", 556, NULL }, - { "Sacute", 667, NULL }, - { "ordmasculine", 365, NULL }, - { "dotlessi", 278, NULL }, - { "sterling", 556, NULL }, - { "notequal", 549, NULL }, - { "Imacron", 278, NULL }, - { "rcommaaccent", 389, NULL }, - { "Zdotaccent", 611, NULL }, - { "acircumflex", 556, NULL }, - { "cacute", 556, NULL }, - { "Ecaron", 667, NULL }, - { "icircumflex", 278, NULL }, - { "braceright", 389, NULL }, - { "quotedblright", 500, NULL }, - { "amacron", 556, NULL }, - { "sacute", 556, NULL }, - { "imacron", 278, NULL }, - { "cent", 556, NULL }, - { "currency", 556, NULL }, - { "logicalnot", 584, NULL }, - { "zdotaccent", 500, NULL }, - { "Atilde", 722, NULL }, - { "breve", 333, NULL }, - { "bar", 280, NULL }, - { "fraction", 167, NULL }, - { "less", 584, NULL }, - { "ecaron", 556, NULL }, - { "guilsinglleft", 333, NULL }, - { "exclam", 333, NULL }, - { "period", 278, NULL }, - { "Rcaron", 722, NULL }, - { "Kcommaaccent", 722, NULL }, - { "greater", 584, NULL }, - { "atilde", 556, NULL }, - { "brokenbar", 280, NULL }, - { "quoteleft", 278, NULL }, - { "Edotaccent", 667, NULL }, - { "onesuperior", 333, NULL } -}; - -static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { - { "Ntilde", 722, NULL }, - { "rcaron", 389, NULL }, - { "kcommaaccent", 556, NULL }, - { "Ncommaaccent", 722, NULL }, - { "Zacute", 611, NULL }, - { "comma", 278, NULL }, - { "cedilla", 333, NULL }, - { "plusminus", 584, NULL }, - { "circumflex", 333, NULL }, - { "dotaccent", 333, NULL }, - { "edotaccent", 556, NULL }, - { "asciitilde", 584, NULL }, - { "colon", 333, NULL }, - { "onehalf", 834, NULL }, - { "dollar", 556, NULL }, - { "Lcaron", 611, NULL }, - { "ntilde", 611, NULL }, - { "Aogonek", 722, NULL }, - { "ncommaaccent", 611, NULL }, - { "minus", 584, NULL }, - { "Iogonek", 278, NULL }, - { "zacute", 500, NULL }, - { "yen", 556, NULL }, - { "space", 278, NULL }, - { "Omacron", 778, NULL }, - { "questiondown", 611, NULL }, - { "emdash", 1000, NULL }, - { "Agrave", 722, NULL }, - { "three", 556, NULL }, - { "numbersign", 556, NULL }, - { "lcaron", 400, NULL }, - { "A", 722, NULL }, - { "B", 722, NULL }, - { "C", 722, NULL }, - { "aogonek", 556, NULL }, - { "D", 722, NULL }, - { "E", 667, NULL }, - { "onequarter", 834, NULL }, - { "F", 611, NULL }, - { "G", 778, NULL }, - { "H", 722, NULL }, - { "I", 278, NULL }, - { "J", 556, NULL }, - { "K", 722, NULL }, - { "iogonek", 278, NULL }, - { "backslash", 278, NULL }, - { "L", 611, NULL }, - { "periodcentered", 278, NULL }, - { "M", 833, NULL }, - { "N", 722, NULL }, - { "omacron", 611, NULL }, - { "Tcommaaccent", 611, NULL }, - { "O", 778, NULL }, - { "P", 667, NULL }, - { "Q", 778, NULL }, - { "Uhungarumlaut", 722, NULL }, - { "R", 722, NULL }, - { "Aacute", 722, NULL }, - { "caron", 333, NULL }, - { "S", 667, NULL }, - { "T", 611, NULL }, - { "U", 722, NULL }, - { "agrave", 556, NULL }, - { "V", 667, NULL }, - { "W", 944, NULL }, - { "X", 667, NULL }, - { "question", 611, NULL }, - { "equal", 584, NULL }, - { "Y", 667, NULL }, - { "Z", 611, NULL }, - { "four", 556, NULL }, - { "a", 556, NULL }, - { "Gcommaaccent", 778, NULL }, - { "b", 611, NULL }, - { "c", 556, NULL }, - { "d", 611, NULL }, - { "e", 556, NULL }, - { "f", 333, NULL }, - { "g", 611, NULL }, - { "bullet", 350, NULL }, - { "h", 611, NULL }, - { "i", 278, NULL }, - { "Oslash", 778, NULL }, - { "dagger", 556, NULL }, - { "j", 278, NULL }, - { "k", 556, NULL }, - { "l", 278, NULL }, - { "m", 889, NULL }, - { "n", 611, NULL }, - { "tcommaaccent", 333, NULL }, - { "o", 611, NULL }, - { "ordfeminine", 370, NULL }, - { "ring", 333, NULL }, - { "p", 611, NULL }, - { "q", 611, NULL }, - { "uhungarumlaut", 611, NULL }, - { "r", 389, NULL }, - { "twosuperior", 333, NULL }, - { "aacute", 556, NULL }, - { "s", 556, NULL }, - { "OE", 1000, NULL }, - { "t", 333, NULL }, - { "divide", 584, NULL }, - { "u", 611, NULL }, - { "Ccaron", 722, NULL }, - { "v", 556, NULL }, - { "w", 778, NULL }, - { "x", 556, NULL }, - { "y", 556, NULL }, - { "z", 500, NULL }, - { "Gbreve", 778, NULL }, - { "commaaccent", 250, NULL }, - { "hungarumlaut", 333, NULL }, - { "Idotaccent", 278, NULL }, - { "Nacute", 722, NULL }, - { "quotedbl", 474, NULL }, - { "gcommaaccent", 611, NULL }, - { "mu", 611, NULL }, - { "greaterequal", 549, NULL }, - { "Scaron", 667, NULL }, - { "Lslash", 611, NULL }, - { "semicolon", 333, NULL }, - { "oslash", 611, NULL }, - { "lessequal", 549, NULL }, - { "lozenge", 494, NULL }, - { "parenright", 333, NULL }, - { "ccaron", 556, NULL }, - { "Ecircumflex", 667, NULL }, - { "gbreve", 611, NULL }, - { "trademark", 1000, NULL }, - { "daggerdbl", 556, NULL }, - { "nacute", 611, NULL }, - { "macron", 333, NULL }, - { "Otilde", 778, NULL }, - { "Emacron", 667, NULL }, - { "ellipsis", 1000, NULL }, - { "scaron", 556, NULL }, - { "AE", 1000, NULL }, - { "Ucircumflex", 722, NULL }, - { "lslash", 278, NULL }, - { "quotedblleft", 500, NULL }, - { "guilsinglright", 333, NULL }, - { "hyphen", 333, NULL }, - { "quotesingle", 238, NULL }, - { "eight", 556, NULL }, - { "exclamdown", 333, NULL }, - { "endash", 556, NULL }, - { "oe", 944, NULL }, - { "Abreve", 722, NULL }, - { "Umacron", 722, NULL }, - { "ecircumflex", 556, NULL }, - { "Adieresis", 722, NULL }, - { "copyright", 737, NULL }, - { "Egrave", 667, NULL }, - { "slash", 278, NULL }, - { "Edieresis", 667, NULL }, - { "otilde", 611, NULL }, - { "Idieresis", 278, NULL }, - { "parenleft", 333, NULL }, - { "one", 556, NULL }, - { "emacron", 556, NULL }, - { "Odieresis", 778, NULL }, - { "ucircumflex", 611, NULL }, - { "bracketleft", 333, NULL }, - { "Ugrave", 722, NULL }, - { "quoteright", 278, NULL }, - { "Udieresis", 722, NULL }, - { "perthousand", 1000, NULL }, - { "Ydieresis", 667, NULL }, - { "umacron", 611, NULL }, - { "abreve", 556, NULL }, - { "Eacute", 667, NULL }, - { "adieresis", 556, NULL }, - { "egrave", 556, NULL }, - { "edieresis", 556, NULL }, - { "idieresis", 278, NULL }, - { "Eth", 722, NULL }, - { "ae", 889, NULL }, - { "asterisk", 389, NULL }, - { "odieresis", 611, NULL }, - { "Uacute", 722, NULL }, - { "ugrave", 611, NULL }, - { "nine", 556, NULL }, - { "five", 556, NULL }, - { "udieresis", 611, NULL }, - { "Zcaron", 611, NULL }, - { "Scommaaccent", 667, NULL }, - { "threequarters", 834, NULL }, - { "guillemotright", 556, NULL }, - { "Ccedilla", 722, NULL }, - { "ydieresis", 556, NULL }, - { "tilde", 333, NULL }, - { "at", 975, NULL }, - { "eacute", 556, NULL }, - { "underscore", 556, NULL }, - { "Euro", 556, NULL }, - { "Dcroat", 722, NULL }, - { "multiply", 584, NULL }, - { "zero", 556, NULL }, - { "eth", 611, NULL }, - { "Scedilla", 667, NULL }, - { "Ograve", 778, NULL }, - { "Racute", 722, NULL }, - { "partialdiff", 494, NULL }, - { "uacute", 611, NULL }, - { "braceleft", 389, NULL }, - { "Thorn", 667, NULL }, - { "zcaron", 500, NULL }, - { "scommaaccent", 556, NULL }, - { "ccedilla", 556, NULL }, - { "Dcaron", 722, NULL }, - { "dcroat", 611, NULL }, - { "Ocircumflex", 778, NULL }, - { "Oacute", 778, NULL }, - { "scedilla", 556, NULL }, - { "ogonek", 333, NULL }, - { "ograve", 611, NULL }, - { "racute", 389, NULL }, - { "Tcaron", 611, NULL }, - { "Eogonek", 667, NULL }, - { "thorn", 611, NULL }, - { "degree", 400, NULL }, - { "registered", 737, NULL }, - { "radical", 549, NULL }, - { "Aring", 722, NULL }, - { "percent", 889, NULL }, - { "six", 556, NULL }, - { "paragraph", 556, NULL }, - { "dcaron", 743, NULL }, - { "Uogonek", 722, NULL }, - { "two", 556, NULL }, - { "summation", 600, NULL }, - { "Igrave", 278, NULL }, - { "Lacute", 611, NULL }, - { "ocircumflex", 611, NULL }, - { "oacute", 611, NULL }, - { "Uring", 722, NULL }, - { "Lcommaaccent", 611, NULL }, - { "tcaron", 389, NULL }, - { "eogonek", 556, NULL }, - { "Delta", 612, NULL }, - { "Ohungarumlaut", 778, NULL }, - { "asciicircum", 584, NULL }, - { "aring", 556, NULL }, - { "grave", 333, NULL }, - { "uogonek", 611, NULL }, - { "bracketright", 333, NULL }, - { "Iacute", 278, NULL }, - { "ampersand", 722, NULL }, - { "igrave", 278, NULL }, - { "lacute", 278, NULL }, - { "Ncaron", 722, NULL }, - { "plus", 584, NULL }, - { "uring", 611, NULL }, - { "quotesinglbase", 278, NULL }, - { "lcommaaccent", 278, NULL }, - { "Yacute", 667, NULL }, - { "ohungarumlaut", 611, NULL }, - { "threesuperior", 333, NULL }, - { "acute", 333, NULL }, - { "section", 556, NULL }, - { "dieresis", 333, NULL }, - { "iacute", 278, NULL }, - { "quotedblbase", 500, NULL }, - { "ncaron", 611, NULL }, - { "florin", 556, NULL }, - { "yacute", 556, NULL }, - { "Rcommaaccent", 722, NULL }, - { "fi", 611, NULL }, - { "fl", 611, NULL }, - { "Acircumflex", 722, NULL }, - { "Cacute", 722, NULL }, - { "Icircumflex", 278, NULL }, - { "guillemotleft", 556, NULL }, - { "germandbls", 611, NULL }, - { "Amacron", 722, NULL }, - { "seven", 556, NULL }, - { "Sacute", 667, NULL }, - { "ordmasculine", 365, NULL }, - { "dotlessi", 278, NULL }, - { "sterling", 556, NULL }, - { "notequal", 549, NULL }, - { "Imacron", 278, NULL }, - { "rcommaaccent", 389, NULL }, - { "Zdotaccent", 611, NULL }, - { "acircumflex", 556, NULL }, - { "cacute", 556, NULL }, - { "Ecaron", 667, NULL }, - { "icircumflex", 278, NULL }, - { "braceright", 389, NULL }, - { "quotedblright", 500, NULL }, - { "amacron", 556, NULL }, - { "sacute", 556, NULL }, - { "imacron", 278, NULL }, - { "cent", 556, NULL }, - { "currency", 556, NULL }, - { "logicalnot", 584, NULL }, - { "zdotaccent", 500, NULL }, - { "Atilde", 722, NULL }, - { "breve", 333, NULL }, - { "bar", 280, NULL }, - { "fraction", 167, NULL }, - { "less", 584, NULL }, - { "ecaron", 556, NULL }, - { "guilsinglleft", 333, NULL }, - { "exclam", 333, NULL }, - { "period", 278, NULL }, - { "Rcaron", 722, NULL }, - { "Kcommaaccent", 722, NULL }, - { "greater", 584, NULL }, - { "atilde", 556, NULL }, - { "brokenbar", 280, NULL }, - { "quoteleft", 278, NULL }, - { "Edotaccent", 667, NULL }, - { "onesuperior", 333, NULL } -}; - -static BuiltinFontWidth helveticaObliqueWidthsTab[] = { - { "Ntilde", 722, NULL }, - { "rcaron", 333, NULL }, - { "kcommaaccent", 500, NULL }, - { "Ncommaaccent", 722, NULL }, - { "Zacute", 611, NULL }, - { "comma", 278, NULL }, - { "cedilla", 333, NULL }, - { "plusminus", 584, NULL }, - { "circumflex", 333, NULL }, - { "dotaccent", 333, NULL }, - { "edotaccent", 556, NULL }, - { "asciitilde", 584, NULL }, - { "colon", 278, NULL }, - { "onehalf", 834, NULL }, - { "dollar", 556, NULL }, - { "Lcaron", 556, NULL }, - { "ntilde", 556, NULL }, - { "Aogonek", 667, NULL }, - { "ncommaaccent", 556, NULL }, - { "minus", 584, NULL }, - { "Iogonek", 278, NULL }, - { "zacute", 500, NULL }, - { "yen", 556, NULL }, - { "space", 278, NULL }, - { "Omacron", 778, NULL }, - { "questiondown", 611, NULL }, - { "emdash", 1000, NULL }, - { "Agrave", 667, NULL }, - { "three", 556, NULL }, - { "numbersign", 556, NULL }, - { "lcaron", 299, NULL }, - { "A", 667, NULL }, - { "B", 667, NULL }, - { "C", 722, NULL }, - { "aogonek", 556, NULL }, - { "D", 722, NULL }, - { "E", 667, NULL }, - { "onequarter", 834, NULL }, - { "F", 611, NULL }, - { "G", 778, NULL }, - { "H", 722, NULL }, - { "I", 278, NULL }, - { "J", 500, NULL }, - { "K", 667, NULL }, - { "iogonek", 222, NULL }, - { "backslash", 278, NULL }, - { "L", 556, NULL }, - { "periodcentered", 278, NULL }, - { "M", 833, NULL }, - { "N", 722, NULL }, - { "omacron", 556, NULL }, - { "Tcommaaccent", 611, NULL }, - { "O", 778, NULL }, - { "P", 667, NULL }, - { "Q", 778, NULL }, - { "Uhungarumlaut", 722, NULL }, - { "R", 722, NULL }, - { "Aacute", 667, NULL }, - { "caron", 333, NULL }, - { "S", 667, NULL }, - { "T", 611, NULL }, - { "U", 722, NULL }, - { "agrave", 556, NULL }, - { "V", 667, NULL }, - { "W", 944, NULL }, - { "X", 667, NULL }, - { "question", 556, NULL }, - { "equal", 584, NULL }, - { "Y", 667, NULL }, - { "Z", 611, NULL }, - { "four", 556, NULL }, - { "a", 556, NULL }, - { "Gcommaaccent", 778, NULL }, - { "b", 556, NULL }, - { "c", 500, NULL }, - { "d", 556, NULL }, - { "e", 556, NULL }, - { "f", 278, NULL }, - { "g", 556, NULL }, - { "bullet", 350, NULL }, - { "h", 556, NULL }, - { "i", 222, NULL }, - { "Oslash", 778, NULL }, - { "dagger", 556, NULL }, - { "j", 222, NULL }, - { "k", 500, NULL }, - { "l", 222, NULL }, - { "m", 833, NULL }, - { "n", 556, NULL }, - { "tcommaaccent", 278, NULL }, - { "o", 556, NULL }, - { "ordfeminine", 370, NULL }, - { "ring", 333, NULL }, - { "p", 556, NULL }, - { "q", 556, NULL }, - { "uhungarumlaut", 556, NULL }, - { "r", 333, NULL }, - { "twosuperior", 333, NULL }, - { "aacute", 556, NULL }, - { "s", 500, NULL }, - { "OE", 1000, NULL }, - { "t", 278, NULL }, - { "divide", 584, NULL }, - { "u", 556, NULL }, - { "Ccaron", 722, NULL }, - { "v", 500, NULL }, - { "w", 722, NULL }, - { "x", 500, NULL }, - { "y", 500, NULL }, - { "z", 500, NULL }, - { "Gbreve", 778, NULL }, - { "commaaccent", 250, NULL }, - { "hungarumlaut", 333, NULL }, - { "Idotaccent", 278, NULL }, - { "Nacute", 722, NULL }, - { "quotedbl", 355, NULL }, - { "gcommaaccent", 556, NULL }, - { "mu", 556, NULL }, - { "greaterequal", 549, NULL }, - { "Scaron", 667, NULL }, - { "Lslash", 556, NULL }, - { "semicolon", 278, NULL }, - { "oslash", 611, NULL }, - { "lessequal", 549, NULL }, - { "lozenge", 471, NULL }, - { "parenright", 333, NULL }, - { "ccaron", 500, NULL }, - { "Ecircumflex", 667, NULL }, - { "gbreve", 556, NULL }, - { "trademark", 1000, NULL }, - { "daggerdbl", 556, NULL }, - { "nacute", 556, NULL }, - { "macron", 333, NULL }, - { "Otilde", 778, NULL }, - { "Emacron", 667, NULL }, - { "ellipsis", 1000, NULL }, - { "scaron", 500, NULL }, - { "AE", 1000, NULL }, - { "Ucircumflex", 722, NULL }, - { "lslash", 222, NULL }, - { "quotedblleft", 333, NULL }, - { "guilsinglright", 333, NULL }, - { "hyphen", 333, NULL }, - { "quotesingle", 191, NULL }, - { "eight", 556, NULL }, - { "exclamdown", 333, NULL }, - { "endash", 556, NULL }, - { "oe", 944, NULL }, - { "Abreve", 667, NULL }, - { "Umacron", 722, NULL }, - { "ecircumflex", 556, NULL }, - { "Adieresis", 667, NULL }, - { "copyright", 737, NULL }, - { "Egrave", 667, NULL }, - { "slash", 278, NULL }, - { "Edieresis", 667, NULL }, - { "otilde", 556, NULL }, - { "Idieresis", 278, NULL }, - { "parenleft", 333, NULL }, - { "one", 556, NULL }, - { "emacron", 556, NULL }, - { "Odieresis", 778, NULL }, - { "ucircumflex", 556, NULL }, - { "bracketleft", 278, NULL }, - { "Ugrave", 722, NULL }, - { "quoteright", 222, NULL }, - { "Udieresis", 722, NULL }, - { "perthousand", 1000, NULL }, - { "Ydieresis", 667, NULL }, - { "umacron", 556, NULL }, - { "abreve", 556, NULL }, - { "Eacute", 667, NULL }, - { "adieresis", 556, NULL }, - { "egrave", 556, NULL }, - { "edieresis", 556, NULL }, - { "idieresis", 278, NULL }, - { "Eth", 722, NULL }, - { "ae", 889, NULL }, - { "asterisk", 389, NULL }, - { "odieresis", 556, NULL }, - { "Uacute", 722, NULL }, - { "ugrave", 556, NULL }, - { "nine", 556, NULL }, - { "five", 556, NULL }, - { "udieresis", 556, NULL }, - { "Zcaron", 611, NULL }, - { "Scommaaccent", 667, NULL }, - { "threequarters", 834, NULL }, - { "guillemotright", 556, NULL }, - { "Ccedilla", 722, NULL }, - { "ydieresis", 500, NULL }, - { "tilde", 333, NULL }, - { "at", 1015, NULL }, - { "eacute", 556, NULL }, - { "underscore", 556, NULL }, - { "Euro", 556, NULL }, - { "Dcroat", 722, NULL }, - { "multiply", 584, NULL }, - { "zero", 556, NULL }, - { "eth", 556, NULL }, - { "Scedilla", 667, NULL }, - { "Ograve", 778, NULL }, - { "Racute", 722, NULL }, - { "partialdiff", 476, NULL }, - { "uacute", 556, NULL }, - { "braceleft", 334, NULL }, - { "Thorn", 667, NULL }, - { "zcaron", 500, NULL }, - { "scommaaccent", 500, NULL }, - { "ccedilla", 500, NULL }, - { "Dcaron", 722, NULL }, - { "dcroat", 556, NULL }, - { "Ocircumflex", 778, NULL }, - { "Oacute", 778, NULL }, - { "scedilla", 500, NULL }, - { "ogonek", 333, NULL }, - { "ograve", 556, NULL }, - { "racute", 333, NULL }, - { "Tcaron", 611, NULL }, - { "Eogonek", 667, NULL }, - { "thorn", 556, NULL }, - { "degree", 400, NULL }, - { "registered", 737, NULL }, - { "radical", 453, NULL }, - { "Aring", 667, NULL }, - { "percent", 889, NULL }, - { "six", 556, NULL }, - { "paragraph", 537, NULL }, - { "dcaron", 643, NULL }, - { "Uogonek", 722, NULL }, - { "two", 556, NULL }, - { "summation", 600, NULL }, - { "Igrave", 278, NULL }, - { "Lacute", 556, NULL }, - { "ocircumflex", 556, NULL }, - { "oacute", 556, NULL }, - { "Uring", 722, NULL }, - { "Lcommaaccent", 556, NULL }, - { "tcaron", 317, NULL }, - { "eogonek", 556, NULL }, - { "Delta", 612, NULL }, - { "Ohungarumlaut", 778, NULL }, - { "asciicircum", 469, NULL }, - { "aring", 556, NULL }, - { "grave", 333, NULL }, - { "uogonek", 556, NULL }, - { "bracketright", 278, NULL }, - { "Iacute", 278, NULL }, - { "ampersand", 667, NULL }, - { "igrave", 278, NULL }, - { "lacute", 222, NULL }, - { "Ncaron", 722, NULL }, - { "plus", 584, NULL }, - { "uring", 556, NULL }, - { "quotesinglbase", 222, NULL }, - { "lcommaaccent", 222, NULL }, - { "Yacute", 667, NULL }, - { "ohungarumlaut", 556, NULL }, - { "threesuperior", 333, NULL }, - { "acute", 333, NULL }, - { "section", 556, NULL }, - { "dieresis", 333, NULL }, - { "iacute", 278, NULL }, - { "quotedblbase", 333, NULL }, - { "ncaron", 556, NULL }, - { "florin", 556, NULL }, - { "yacute", 500, NULL }, - { "Rcommaaccent", 722, NULL }, - { "fi", 500, NULL }, - { "fl", 500, NULL }, - { "Acircumflex", 667, NULL }, - { "Cacute", 722, NULL }, - { "Icircumflex", 278, NULL }, - { "guillemotleft", 556, NULL }, - { "germandbls", 611, NULL }, - { "Amacron", 667, NULL }, - { "seven", 556, NULL }, - { "Sacute", 667, NULL }, - { "ordmasculine", 365, NULL }, - { "dotlessi", 278, NULL }, - { "sterling", 556, NULL }, - { "notequal", 549, NULL }, - { "Imacron", 278, NULL }, - { "rcommaaccent", 333, NULL }, - { "Zdotaccent", 611, NULL }, - { "acircumflex", 556, NULL }, - { "cacute", 500, NULL }, - { "Ecaron", 667, NULL }, - { "icircumflex", 278, NULL }, - { "braceright", 334, NULL }, - { "quotedblright", 333, NULL }, - { "amacron", 556, NULL }, - { "sacute", 500, NULL }, - { "imacron", 278, NULL }, - { "cent", 556, NULL }, - { "currency", 556, NULL }, - { "logicalnot", 584, NULL }, - { "zdotaccent", 500, NULL }, - { "Atilde", 667, NULL }, - { "breve", 333, NULL }, - { "bar", 260, NULL }, - { "fraction", 167, NULL }, - { "less", 584, NULL }, - { "ecaron", 556, NULL }, - { "guilsinglleft", 333, NULL }, - { "exclam", 278, NULL }, - { "period", 278, NULL }, - { "Rcaron", 722, NULL }, - { "Kcommaaccent", 667, NULL }, - { "greater", 584, NULL }, - { "atilde", 556, NULL }, - { "brokenbar", 260, NULL }, - { "quoteleft", 222, NULL }, - { "Edotaccent", 667, NULL }, - { "onesuperior", 333, NULL } -}; - -static BuiltinFontWidth symbolWidthsTab[] = { - { "bracketleftex", 384, NULL }, - { "alpha", 631, NULL }, - { "union", 768, NULL }, - { "infinity", 713, NULL }, - { "comma", 250, NULL }, - { "copyrightsans", 790, NULL }, - { "plusminus", 549, NULL }, - { "arrowup", 603, NULL }, - { "apple", 790, NULL }, - { "parenleftbt", 384, NULL }, - { "notelement", 713, NULL }, - { "colon", 278, NULL }, - { "beta", 549, NULL }, - { "braceleftbt", 494, NULL }, - { "Lambda", 686, NULL }, - { "Phi", 763, NULL }, - { "minus", 549, NULL }, - { "space", 250, NULL }, - { "Sigma", 592, NULL }, - { "approxequal", 549, NULL }, - { "minute", 247, NULL }, - { "circleplus", 768, NULL }, - { "Omicron", 722, NULL }, - { "three", 500, NULL }, - { "numbersign", 500, NULL }, - { "lambda", 549, NULL }, - { "phi", 521, NULL }, - { "aleph", 823, NULL }, - { "Tau", 611, NULL }, - { "spade", 753, NULL }, - { "logicaland", 603, NULL }, - { "sigma", 603, NULL }, - { "propersuperset", 713, NULL }, - { "omicron", 549, NULL }, - { "question", 444, NULL }, - { "equal", 549, NULL }, - { "Epsilon", 611, NULL }, - { "emptyset", 823, NULL }, - { "diamond", 753, NULL }, - { "four", 500, NULL }, - { "Mu", 889, NULL }, - { "parenlefttp", 384, NULL }, - { "club", 753, NULL }, - { "bullet", 460, NULL }, - { "Omega", 768, NULL }, - { "tau", 439, NULL }, - { "Upsilon", 690, NULL }, - { "bracelefttp", 494, NULL }, - { "heart", 753, NULL }, - { "divide", 549, NULL }, - { "epsilon", 439, NULL }, - { "logicalor", 603, NULL }, - { "parenleftex", 384, NULL }, - { "greaterequal", 549, NULL }, - { "mu", 576, NULL }, - { "Nu", 722, NULL }, - { "therefore", 863, NULL }, - { "notsubset", 713, NULL }, - { "omega", 686, NULL }, - { "semicolon", 278, NULL }, - { "element", 713, NULL }, - { "upsilon", 576, NULL }, - { "existential", 549, NULL }, - { "integralbt", 686, NULL }, - { "lessequal", 549, NULL }, - { "phi1", 603, NULL }, - { "lozenge", 494, NULL }, - { "trademarkserif", 890, NULL }, - { "parenright", 333, NULL }, - { "reflexsuperset", 713, NULL }, - { "sigma1", 439, NULL }, - { "nu", 521, NULL }, - { "Gamma", 603, NULL }, - { "angleright", 329, NULL }, - { "ellipsis", 1000, NULL }, - { "Rho", 556, NULL }, - { "parenrightbt", 384, NULL }, - { "radicalex", 500, NULL }, - { "eight", 500, NULL }, - { "angleleft", 329, NULL }, - { "arrowdbldown", 603, NULL }, - { "congruent", 549, NULL }, - { "Theta", 741, NULL }, - { "intersection", 768, NULL }, - { "Pi", 768, NULL }, - { "slash", 278, NULL }, - { "registerserif", 790, NULL }, - { "parenleft", 333, NULL }, - { "one", 500, NULL }, - { "gamma", 411, NULL }, - { "bracketleft", 333, NULL }, - { "rho", 549, NULL }, - { "circlemultiply", 768, NULL }, - { "Chi", 722, NULL }, - { "theta", 521, NULL }, - { "pi", 549, NULL }, - { "integraltp", 686, NULL }, - { "Eta", 722, NULL }, - { "product", 823, NULL }, - { "nine", 500, NULL }, - { "five", 500, NULL }, - { "propersubset", 713, NULL }, - { "bracketrightbt", 384, NULL }, - { "trademarksans", 786, NULL }, - { "dotmath", 250, NULL }, - { "integralex", 686, NULL }, - { "chi", 549, NULL }, - { "parenrighttp", 384, NULL }, - { "eta", 603, NULL }, - { "underscore", 500, NULL }, - { "Euro", 750, NULL }, - { "multiply", 549, NULL }, - { "zero", 500, NULL }, - { "partialdiff", 494, NULL }, - { "angle", 768, NULL }, - { "arrowdblleft", 987, NULL }, - { "braceleft", 480, NULL }, - { "parenrightex", 384, NULL }, - { "Rfraktur", 795, NULL }, - { "Zeta", 611, NULL }, - { "braceex", 494, NULL }, - { "arrowdblup", 603, NULL }, - { "arrowdown", 603, NULL }, - { "Ifraktur", 686, NULL }, - { "degree", 400, NULL }, - { "Iota", 333, NULL }, - { "perpendicular", 658, NULL }, - { "radical", 549, NULL }, - { "asteriskmath", 500, NULL }, - { "percent", 833, NULL }, - { "zeta", 494, NULL }, - { "six", 500, NULL }, - { "two", 500, NULL }, - { "weierstrass", 987, NULL }, - { "summation", 713, NULL }, - { "bracketrighttp", 384, NULL }, - { "carriagereturn", 658, NULL }, - { "suchthat", 439, NULL }, - { "arrowvertex", 603, NULL }, - { "Delta", 612, NULL }, - { "iota", 329, NULL }, - { "arrowhorizex", 1000, NULL }, - { "bracketrightex", 384, NULL }, - { "bracketright", 333, NULL }, - { "ampersand", 778, NULL }, - { "plus", 549, NULL }, - { "proportional", 713, NULL }, - { "delta", 494, NULL }, - { "copyrightserif", 790, NULL }, - { "bracerightmid", 494, NULL }, - { "arrowleft", 987, NULL }, - { "second", 411, NULL }, - { "arrowdblboth", 1042, NULL }, - { "florin", 500, NULL }, - { "Psi", 795, NULL }, - { "bracerightbt", 494, NULL }, - { "bracketleftbt", 384, NULL }, - { "seven", 500, NULL }, - { "braceleftmid", 494, NULL }, - { "notequal", 549, NULL }, - { "psi", 686, NULL }, - { "equivalence", 549, NULL }, - { "universal", 713, NULL }, - { "arrowdblright", 987, NULL }, - { "braceright", 480, NULL }, - { "reflexsubset", 713, NULL }, - { "Xi", 645, NULL }, - { "theta1", 631, NULL }, - { "logicalnot", 713, NULL }, - { "Kappa", 722, NULL }, - { "similar", 549, NULL }, - { "bar", 200, NULL }, - { "fraction", 167, NULL }, - { "less", 549, NULL }, - { "registersans", 790, NULL }, - { "omega1", 713, NULL }, - { "exclam", 333, NULL }, - { "Upsilon1", 620, NULL }, - { "bracerighttp", 494, NULL }, - { "xi", 493, NULL }, - { "period", 250, NULL }, - { "Alpha", 722, NULL }, - { "arrowright", 987, NULL }, - { "greater", 549, NULL }, - { "bracketlefttp", 384, NULL }, - { "kappa", 549, NULL }, - { "gradient", 713, NULL }, - { "integral", 274, NULL }, - { "arrowboth", 1042, NULL }, - { "Beta", 667, NULL } -}; - -static BuiltinFontWidth timesBoldWidthsTab[] = { - { "Ntilde", 722, NULL }, - { "rcaron", 444, NULL }, - { "kcommaaccent", 556, NULL }, - { "Ncommaaccent", 722, NULL }, - { "Zacute", 667, NULL }, - { "comma", 250, NULL }, - { "cedilla", 333, NULL }, - { "plusminus", 570, NULL }, - { "circumflex", 333, NULL }, - { "dotaccent", 333, NULL }, - { "edotaccent", 444, NULL }, - { "asciitilde", 520, NULL }, - { "colon", 333, NULL }, - { "onehalf", 750, NULL }, - { "dollar", 500, NULL }, - { "Lcaron", 667, NULL }, - { "ntilde", 556, NULL }, - { "Aogonek", 722, NULL }, - { "ncommaaccent", 556, NULL }, - { "minus", 570, NULL }, - { "Iogonek", 389, NULL }, - { "zacute", 444, NULL }, - { "yen", 500, NULL }, - { "space", 250, NULL }, - { "Omacron", 778, NULL }, - { "questiondown", 500, NULL }, - { "emdash", 1000, NULL }, - { "Agrave", 722, NULL }, - { "three", 500, NULL }, - { "numbersign", 500, NULL }, - { "lcaron", 394, NULL }, - { "A", 722, NULL }, - { "B", 667, NULL }, - { "C", 722, NULL }, - { "aogonek", 500, NULL }, - { "D", 722, NULL }, - { "E", 667, NULL }, - { "onequarter", 750, NULL }, - { "F", 611, NULL }, - { "G", 778, NULL }, - { "H", 778, NULL }, - { "I", 389, NULL }, - { "J", 500, NULL }, - { "K", 778, NULL }, - { "iogonek", 278, NULL }, - { "backslash", 278, NULL }, - { "L", 667, NULL }, - { "periodcentered", 250, NULL }, - { "M", 944, NULL }, - { "N", 722, NULL }, - { "omacron", 500, NULL }, - { "Tcommaaccent", 667, NULL }, - { "O", 778, NULL }, - { "P", 611, NULL }, - { "Q", 778, NULL }, - { "Uhungarumlaut", 722, NULL }, - { "R", 722, NULL }, - { "Aacute", 722, NULL }, - { "caron", 333, NULL }, - { "S", 556, NULL }, - { "T", 667, NULL }, - { "U", 722, NULL }, - { "agrave", 500, NULL }, - { "V", 722, NULL }, - { "W", 1000, NULL }, - { "X", 722, NULL }, - { "question", 500, NULL }, - { "equal", 570, NULL }, - { "Y", 722, NULL }, - { "Z", 667, NULL }, - { "four", 500, NULL }, - { "a", 500, NULL }, - { "Gcommaaccent", 778, NULL }, - { "b", 556, NULL }, - { "c", 444, NULL }, - { "d", 556, NULL }, - { "e", 444, NULL }, - { "f", 333, NULL }, - { "g", 500, NULL }, - { "bullet", 350, NULL }, - { "h", 556, NULL }, - { "i", 278, NULL }, - { "Oslash", 778, NULL }, - { "dagger", 500, NULL }, - { "j", 333, NULL }, - { "k", 556, NULL }, - { "l", 278, NULL }, - { "m", 833, NULL }, - { "n", 556, NULL }, - { "tcommaaccent", 333, NULL }, - { "o", 500, NULL }, - { "ordfeminine", 300, NULL }, - { "ring", 333, NULL }, - { "p", 556, NULL }, - { "q", 556, NULL }, - { "uhungarumlaut", 556, NULL }, - { "r", 444, NULL }, - { "twosuperior", 300, NULL }, - { "aacute", 500, NULL }, - { "s", 389, NULL }, - { "OE", 1000, NULL }, - { "t", 333, NULL }, - { "divide", 570, NULL }, - { "u", 556, NULL }, - { "Ccaron", 722, NULL }, - { "v", 500, NULL }, - { "w", 722, NULL }, - { "x", 500, NULL }, - { "y", 500, NULL }, - { "z", 444, NULL }, - { "Gbreve", 778, NULL }, - { "commaaccent", 250, NULL }, - { "hungarumlaut", 333, NULL }, - { "Idotaccent", 389, NULL }, - { "Nacute", 722, NULL }, - { "quotedbl", 555, NULL }, - { "gcommaaccent", 500, NULL }, - { "mu", 556, NULL }, - { "greaterequal", 549, NULL }, - { "Scaron", 556, NULL }, - { "Lslash", 667, NULL }, - { "semicolon", 333, NULL }, - { "oslash", 500, NULL }, - { "lessequal", 549, NULL }, - { "lozenge", 494, NULL }, - { "parenright", 333, NULL }, - { "ccaron", 444, NULL }, - { "Ecircumflex", 667, NULL }, - { "gbreve", 500, NULL }, - { "trademark", 1000, NULL }, - { "daggerdbl", 500, NULL }, - { "nacute", 556, NULL }, - { "macron", 333, NULL }, - { "Otilde", 778, NULL }, - { "Emacron", 667, NULL }, - { "ellipsis", 1000, NULL }, - { "scaron", 389, NULL }, - { "AE", 1000, NULL }, - { "Ucircumflex", 722, NULL }, - { "lslash", 278, NULL }, - { "quotedblleft", 500, NULL }, - { "guilsinglright", 333, NULL }, - { "hyphen", 333, NULL }, - { "quotesingle", 278, NULL }, - { "eight", 500, NULL }, - { "exclamdown", 333, NULL }, - { "endash", 500, NULL }, - { "oe", 722, NULL }, - { "Abreve", 722, NULL }, - { "Umacron", 722, NULL }, - { "ecircumflex", 444, NULL }, - { "Adieresis", 722, NULL }, - { "copyright", 747, NULL }, - { "Egrave", 667, NULL }, - { "slash", 278, NULL }, - { "Edieresis", 667, NULL }, - { "otilde", 500, NULL }, - { "Idieresis", 389, NULL }, - { "parenleft", 333, NULL }, - { "one", 500, NULL }, - { "emacron", 444, NULL }, - { "Odieresis", 778, NULL }, - { "ucircumflex", 556, NULL }, - { "bracketleft", 333, NULL }, - { "Ugrave", 722, NULL }, - { "quoteright", 333, NULL }, - { "Udieresis", 722, NULL }, - { "perthousand", 1000, NULL }, - { "Ydieresis", 722, NULL }, - { "umacron", 556, NULL }, - { "abreve", 500, NULL }, - { "Eacute", 667, NULL }, - { "adieresis", 500, NULL }, - { "egrave", 444, NULL }, - { "edieresis", 444, NULL }, - { "idieresis", 278, NULL }, - { "Eth", 722, NULL }, - { "ae", 722, NULL }, - { "asterisk", 500, NULL }, - { "odieresis", 500, NULL }, - { "Uacute", 722, NULL }, - { "ugrave", 556, NULL }, - { "nine", 500, NULL }, - { "five", 500, NULL }, - { "udieresis", 556, NULL }, - { "Zcaron", 667, NULL }, - { "Scommaaccent", 556, NULL }, - { "threequarters", 750, NULL }, - { "guillemotright", 500, NULL }, - { "Ccedilla", 722, NULL }, - { "ydieresis", 500, NULL }, - { "tilde", 333, NULL }, - { "at", 930, NULL }, - { "eacute", 444, NULL }, - { "underscore", 500, NULL }, - { "Euro", 500, NULL }, - { "Dcroat", 722, NULL }, - { "multiply", 570, NULL }, - { "zero", 500, NULL }, - { "eth", 500, NULL }, - { "Scedilla", 556, NULL }, - { "Ograve", 778, NULL }, - { "Racute", 722, NULL }, - { "partialdiff", 494, NULL }, - { "uacute", 556, NULL }, - { "braceleft", 394, NULL }, - { "Thorn", 611, NULL }, - { "zcaron", 444, NULL }, - { "scommaaccent", 389, NULL }, - { "ccedilla", 444, NULL }, - { "Dcaron", 722, NULL }, - { "dcroat", 556, NULL }, - { "Ocircumflex", 778, NULL }, - { "Oacute", 778, NULL }, - { "scedilla", 389, NULL }, - { "ogonek", 333, NULL }, - { "ograve", 500, NULL }, - { "racute", 444, NULL }, - { "Tcaron", 667, NULL }, - { "Eogonek", 667, NULL }, - { "thorn", 556, NULL }, - { "degree", 400, NULL }, - { "registered", 747, NULL }, - { "radical", 549, NULL }, - { "Aring", 722, NULL }, - { "percent", 1000, NULL }, - { "six", 500, NULL }, - { "paragraph", 540, NULL }, - { "dcaron", 672, NULL }, - { "Uogonek", 722, NULL }, - { "two", 500, NULL }, - { "summation", 600, NULL }, - { "Igrave", 389, NULL }, - { "Lacute", 667, NULL }, - { "ocircumflex", 500, NULL }, - { "oacute", 500, NULL }, - { "Uring", 722, NULL }, - { "Lcommaaccent", 667, NULL }, - { "tcaron", 416, NULL }, - { "eogonek", 444, NULL }, - { "Delta", 612, NULL }, - { "Ohungarumlaut", 778, NULL }, - { "asciicircum", 581, NULL }, - { "aring", 500, NULL }, - { "grave", 333, NULL }, - { "uogonek", 556, NULL }, - { "bracketright", 333, NULL }, - { "Iacute", 389, NULL }, - { "ampersand", 833, NULL }, - { "igrave", 278, NULL }, - { "lacute", 278, NULL }, - { "Ncaron", 722, NULL }, - { "plus", 570, NULL }, - { "uring", 556, NULL }, - { "quotesinglbase", 333, NULL }, - { "lcommaaccent", 278, NULL }, - { "Yacute", 722, NULL }, - { "ohungarumlaut", 500, NULL }, - { "threesuperior", 300, NULL }, - { "acute", 333, NULL }, - { "section", 500, NULL }, - { "dieresis", 333, NULL }, - { "iacute", 278, NULL }, - { "quotedblbase", 500, NULL }, - { "ncaron", 556, NULL }, - { "florin", 500, NULL }, - { "yacute", 500, NULL }, - { "Rcommaaccent", 722, NULL }, - { "fi", 556, NULL }, - { "fl", 556, NULL }, - { "Acircumflex", 722, NULL }, - { "Cacute", 722, NULL }, - { "Icircumflex", 389, NULL }, - { "guillemotleft", 500, NULL }, - { "germandbls", 556, NULL }, - { "Amacron", 722, NULL }, - { "seven", 500, NULL }, - { "Sacute", 556, NULL }, - { "ordmasculine", 330, NULL }, - { "dotlessi", 278, NULL }, - { "sterling", 500, NULL }, - { "notequal", 549, NULL }, - { "Imacron", 389, NULL }, - { "rcommaaccent", 444, NULL }, - { "Zdotaccent", 667, NULL }, - { "acircumflex", 500, NULL }, - { "cacute", 444, NULL }, - { "Ecaron", 667, NULL }, - { "icircumflex", 278, NULL }, - { "braceright", 394, NULL }, - { "quotedblright", 500, NULL }, - { "amacron", 500, NULL }, - { "sacute", 389, NULL }, - { "imacron", 278, NULL }, - { "cent", 500, NULL }, - { "currency", 500, NULL }, - { "logicalnot", 570, NULL }, - { "zdotaccent", 444, NULL }, - { "Atilde", 722, NULL }, - { "breve", 333, NULL }, - { "bar", 220, NULL }, - { "fraction", 167, NULL }, - { "less", 570, NULL }, - { "ecaron", 444, NULL }, - { "guilsinglleft", 333, NULL }, - { "exclam", 333, NULL }, - { "period", 250, NULL }, - { "Rcaron", 722, NULL }, - { "Kcommaaccent", 778, NULL }, - { "greater", 570, NULL }, - { "atilde", 500, NULL }, - { "brokenbar", 220, NULL }, - { "quoteleft", 333, NULL }, - { "Edotaccent", 667, NULL }, - { "onesuperior", 300, NULL } -}; - -static BuiltinFontWidth timesBoldItalicWidthsTab[] = { - { "Ntilde", 722, NULL }, - { "rcaron", 389, NULL }, - { "kcommaaccent", 500, NULL }, - { "Ncommaaccent", 722, NULL }, - { "Zacute", 611, NULL }, - { "comma", 250, NULL }, - { "cedilla", 333, NULL }, - { "plusminus", 570, NULL }, - { "circumflex", 333, NULL }, - { "dotaccent", 333, NULL }, - { "edotaccent", 444, NULL }, - { "asciitilde", 570, NULL }, - { "colon", 333, NULL }, - { "onehalf", 750, NULL }, - { "dollar", 500, NULL }, - { "Lcaron", 611, NULL }, - { "ntilde", 556, NULL }, - { "Aogonek", 667, NULL }, - { "ncommaaccent", 556, NULL }, - { "minus", 606, NULL }, - { "Iogonek", 389, NULL }, - { "zacute", 389, NULL }, - { "yen", 500, NULL }, - { "space", 250, NULL }, - { "Omacron", 722, NULL }, - { "questiondown", 500, NULL }, - { "emdash", 1000, NULL }, - { "Agrave", 667, NULL }, - { "three", 500, NULL }, - { "numbersign", 500, NULL }, - { "lcaron", 382, NULL }, - { "A", 667, NULL }, - { "B", 667, NULL }, - { "C", 667, NULL }, - { "aogonek", 500, NULL }, - { "D", 722, NULL }, - { "E", 667, NULL }, - { "onequarter", 750, NULL }, - { "F", 667, NULL }, - { "G", 722, NULL }, - { "H", 778, NULL }, - { "I", 389, NULL }, - { "J", 500, NULL }, - { "K", 667, NULL }, - { "iogonek", 278, NULL }, - { "backslash", 278, NULL }, - { "L", 611, NULL }, - { "periodcentered", 250, NULL }, - { "M", 889, NULL }, - { "N", 722, NULL }, - { "omacron", 500, NULL }, - { "Tcommaaccent", 611, NULL }, - { "O", 722, NULL }, - { "P", 611, NULL }, - { "Q", 722, NULL }, - { "Uhungarumlaut", 722, NULL }, - { "R", 667, NULL }, - { "Aacute", 667, NULL }, - { "caron", 333, NULL }, - { "S", 556, NULL }, - { "T", 611, NULL }, - { "U", 722, NULL }, - { "agrave", 500, NULL }, - { "V", 667, NULL }, - { "W", 889, NULL }, - { "X", 667, NULL }, - { "question", 500, NULL }, - { "equal", 570, NULL }, - { "Y", 611, NULL }, - { "Z", 611, NULL }, - { "four", 500, NULL }, - { "a", 500, NULL }, - { "Gcommaaccent", 722, NULL }, - { "b", 500, NULL }, - { "c", 444, NULL }, - { "d", 500, NULL }, - { "e", 444, NULL }, - { "f", 333, NULL }, - { "g", 500, NULL }, - { "bullet", 350, NULL }, - { "h", 556, NULL }, - { "i", 278, NULL }, - { "Oslash", 722, NULL }, - { "dagger", 500, NULL }, - { "j", 278, NULL }, - { "k", 500, NULL }, - { "l", 278, NULL }, - { "m", 778, NULL }, - { "n", 556, NULL }, - { "tcommaaccent", 278, NULL }, - { "o", 500, NULL }, - { "ordfeminine", 266, NULL }, - { "ring", 333, NULL }, - { "p", 500, NULL }, - { "q", 500, NULL }, - { "uhungarumlaut", 556, NULL }, - { "r", 389, NULL }, - { "twosuperior", 300, NULL }, - { "aacute", 500, NULL }, - { "s", 389, NULL }, - { "OE", 944, NULL }, - { "t", 278, NULL }, - { "divide", 570, NULL }, - { "u", 556, NULL }, - { "Ccaron", 667, NULL }, - { "v", 444, NULL }, - { "w", 667, NULL }, - { "x", 500, NULL }, - { "y", 444, NULL }, - { "z", 389, NULL }, - { "Gbreve", 722, NULL }, - { "commaaccent", 250, NULL }, - { "hungarumlaut", 333, NULL }, - { "Idotaccent", 389, NULL }, - { "Nacute", 722, NULL }, - { "quotedbl", 555, NULL }, - { "gcommaaccent", 500, NULL }, - { "mu", 576, NULL }, - { "greaterequal", 549, NULL }, - { "Scaron", 556, NULL }, - { "Lslash", 611, NULL }, - { "semicolon", 333, NULL }, - { "oslash", 500, NULL }, - { "lessequal", 549, NULL }, - { "lozenge", 494, NULL }, - { "parenright", 333, NULL }, - { "ccaron", 444, NULL }, - { "Ecircumflex", 667, NULL }, - { "gbreve", 500, NULL }, - { "trademark", 1000, NULL }, - { "daggerdbl", 500, NULL }, - { "nacute", 556, NULL }, - { "macron", 333, NULL }, - { "Otilde", 722, NULL }, - { "Emacron", 667, NULL }, - { "ellipsis", 1000, NULL }, - { "scaron", 389, NULL }, - { "AE", 944, NULL }, - { "Ucircumflex", 722, NULL }, - { "lslash", 278, NULL }, - { "quotedblleft", 500, NULL }, - { "guilsinglright", 333, NULL }, - { "hyphen", 333, NULL }, - { "quotesingle", 278, NULL }, - { "eight", 500, NULL }, - { "exclamdown", 389, NULL }, - { "endash", 500, NULL }, - { "oe", 722, NULL }, - { "Abreve", 667, NULL }, - { "Umacron", 722, NULL }, - { "ecircumflex", 444, NULL }, - { "Adieresis", 667, NULL }, - { "copyright", 747, NULL }, - { "Egrave", 667, NULL }, - { "slash", 278, NULL }, - { "Edieresis", 667, NULL }, - { "otilde", 500, NULL }, - { "Idieresis", 389, NULL }, - { "parenleft", 333, NULL }, - { "one", 500, NULL }, - { "emacron", 444, NULL }, - { "Odieresis", 722, NULL }, - { "ucircumflex", 556, NULL }, - { "bracketleft", 333, NULL }, - { "Ugrave", 722, NULL }, - { "quoteright", 333, NULL }, - { "Udieresis", 722, NULL }, - { "perthousand", 1000, NULL }, - { "Ydieresis", 611, NULL }, - { "umacron", 556, NULL }, - { "abreve", 500, NULL }, - { "Eacute", 667, NULL }, - { "adieresis", 500, NULL }, - { "egrave", 444, NULL }, - { "edieresis", 444, NULL }, - { "idieresis", 278, NULL }, - { "Eth", 722, NULL }, - { "ae", 722, NULL }, - { "asterisk", 500, NULL }, - { "odieresis", 500, NULL }, - { "Uacute", 722, NULL }, - { "ugrave", 556, NULL }, - { "nine", 500, NULL }, - { "five", 500, NULL }, - { "udieresis", 556, NULL }, - { "Zcaron", 611, NULL }, - { "Scommaaccent", 556, NULL }, - { "threequarters", 750, NULL }, - { "guillemotright", 500, NULL }, - { "Ccedilla", 667, NULL }, - { "ydieresis", 444, NULL }, - { "tilde", 333, NULL }, - { "at", 832, NULL }, - { "eacute", 444, NULL }, - { "underscore", 500, NULL }, - { "Euro", 500, NULL }, - { "Dcroat", 722, NULL }, - { "multiply", 570, NULL }, - { "zero", 500, NULL }, - { "eth", 500, NULL }, - { "Scedilla", 556, NULL }, - { "Ograve", 722, NULL }, - { "Racute", 667, NULL }, - { "partialdiff", 494, NULL }, - { "uacute", 556, NULL }, - { "braceleft", 348, NULL }, - { "Thorn", 611, NULL }, - { "zcaron", 389, NULL }, - { "scommaaccent", 389, NULL }, - { "ccedilla", 444, NULL }, - { "Dcaron", 722, NULL }, - { "dcroat", 500, NULL }, - { "Ocircumflex", 722, NULL }, - { "Oacute", 722, NULL }, - { "scedilla", 389, NULL }, - { "ogonek", 333, NULL }, - { "ograve", 500, NULL }, - { "racute", 389, NULL }, - { "Tcaron", 611, NULL }, - { "Eogonek", 667, NULL }, - { "thorn", 500, NULL }, - { "degree", 400, NULL }, - { "registered", 747, NULL }, - { "radical", 549, NULL }, - { "Aring", 667, NULL }, - { "percent", 833, NULL }, - { "six", 500, NULL }, - { "paragraph", 500, NULL }, - { "dcaron", 608, NULL }, - { "Uogonek", 722, NULL }, - { "two", 500, NULL }, - { "summation", 600, NULL }, - { "Igrave", 389, NULL }, - { "Lacute", 611, NULL }, - { "ocircumflex", 500, NULL }, - { "oacute", 500, NULL }, - { "Uring", 722, NULL }, - { "Lcommaaccent", 611, NULL }, - { "tcaron", 366, NULL }, - { "eogonek", 444, NULL }, - { "Delta", 612, NULL }, - { "Ohungarumlaut", 722, NULL }, - { "asciicircum", 570, NULL }, - { "aring", 500, NULL }, - { "grave", 333, NULL }, - { "uogonek", 556, NULL }, - { "bracketright", 333, NULL }, - { "Iacute", 389, NULL }, - { "ampersand", 778, NULL }, - { "igrave", 278, NULL }, - { "lacute", 278, NULL }, - { "Ncaron", 722, NULL }, - { "plus", 570, NULL }, - { "uring", 556, NULL }, - { "quotesinglbase", 333, NULL }, - { "lcommaaccent", 278, NULL }, - { "Yacute", 611, NULL }, - { "ohungarumlaut", 500, NULL }, - { "threesuperior", 300, NULL }, - { "acute", 333, NULL }, - { "section", 500, NULL }, - { "dieresis", 333, NULL }, - { "iacute", 278, NULL }, - { "quotedblbase", 500, NULL }, - { "ncaron", 556, NULL }, - { "florin", 500, NULL }, - { "yacute", 444, NULL }, - { "Rcommaaccent", 667, NULL }, - { "fi", 556, NULL }, - { "fl", 556, NULL }, - { "Acircumflex", 667, NULL }, - { "Cacute", 667, NULL }, - { "Icircumflex", 389, NULL }, - { "guillemotleft", 500, NULL }, - { "germandbls", 500, NULL }, - { "Amacron", 667, NULL }, - { "seven", 500, NULL }, - { "Sacute", 556, NULL }, - { "ordmasculine", 300, NULL }, - { "dotlessi", 278, NULL }, - { "sterling", 500, NULL }, - { "notequal", 549, NULL }, - { "Imacron", 389, NULL }, - { "rcommaaccent", 389, NULL }, - { "Zdotaccent", 611, NULL }, - { "acircumflex", 500, NULL }, - { "cacute", 444, NULL }, - { "Ecaron", 667, NULL }, - { "icircumflex", 278, NULL }, - { "braceright", 348, NULL }, - { "quotedblright", 500, NULL }, - { "amacron", 500, NULL }, - { "sacute", 389, NULL }, - { "imacron", 278, NULL }, - { "cent", 500, NULL }, - { "currency", 500, NULL }, - { "logicalnot", 606, NULL }, - { "zdotaccent", 389, NULL }, - { "Atilde", 667, NULL }, - { "breve", 333, NULL }, - { "bar", 220, NULL }, - { "fraction", 167, NULL }, - { "less", 570, NULL }, - { "ecaron", 444, NULL }, - { "guilsinglleft", 333, NULL }, - { "exclam", 389, NULL }, - { "period", 250, NULL }, - { "Rcaron", 667, NULL }, - { "Kcommaaccent", 667, NULL }, - { "greater", 570, NULL }, - { "atilde", 500, NULL }, - { "brokenbar", 220, NULL }, - { "quoteleft", 333, NULL }, - { "Edotaccent", 667, NULL }, - { "onesuperior", 300, NULL } -}; - -static BuiltinFontWidth timesItalicWidthsTab[] = { - { "Ntilde", 667, NULL }, - { "rcaron", 389, NULL }, - { "kcommaaccent", 444, NULL }, - { "Ncommaaccent", 667, NULL }, - { "Zacute", 556, NULL }, - { "comma", 250, NULL }, - { "cedilla", 333, NULL }, - { "plusminus", 675, NULL }, - { "circumflex", 333, NULL }, - { "dotaccent", 333, NULL }, - { "edotaccent", 444, NULL }, - { "asciitilde", 541, NULL }, - { "colon", 333, NULL }, - { "onehalf", 750, NULL }, - { "dollar", 500, NULL }, - { "Lcaron", 611, NULL }, - { "ntilde", 500, NULL }, - { "Aogonek", 611, NULL }, - { "ncommaaccent", 500, NULL }, - { "minus", 675, NULL }, - { "Iogonek", 333, NULL }, - { "zacute", 389, NULL }, - { "yen", 500, NULL }, - { "space", 250, NULL }, - { "Omacron", 722, NULL }, - { "questiondown", 500, NULL }, - { "emdash", 889, NULL }, - { "Agrave", 611, NULL }, - { "three", 500, NULL }, - { "numbersign", 500, NULL }, - { "lcaron", 300, NULL }, - { "A", 611, NULL }, - { "B", 611, NULL }, - { "C", 667, NULL }, - { "aogonek", 500, NULL }, - { "D", 722, NULL }, - { "E", 611, NULL }, - { "onequarter", 750, NULL }, - { "F", 611, NULL }, - { "G", 722, NULL }, - { "H", 722, NULL }, - { "I", 333, NULL }, - { "J", 444, NULL }, - { "K", 667, NULL }, - { "iogonek", 278, NULL }, - { "backslash", 278, NULL }, - { "L", 556, NULL }, - { "periodcentered", 250, NULL }, - { "M", 833, NULL }, - { "N", 667, NULL }, - { "omacron", 500, NULL }, - { "Tcommaaccent", 556, NULL }, - { "O", 722, NULL }, - { "P", 611, NULL }, - { "Q", 722, NULL }, - { "Uhungarumlaut", 722, NULL }, - { "R", 611, NULL }, - { "Aacute", 611, NULL }, - { "caron", 333, NULL }, - { "S", 500, NULL }, - { "T", 556, NULL }, - { "U", 722, NULL }, - { "agrave", 500, NULL }, - { "V", 611, NULL }, - { "W", 833, NULL }, - { "X", 611, NULL }, - { "question", 500, NULL }, - { "equal", 675, NULL }, - { "Y", 556, NULL }, - { "Z", 556, NULL }, - { "four", 500, NULL }, - { "a", 500, NULL }, - { "Gcommaaccent", 722, NULL }, - { "b", 500, NULL }, - { "c", 444, NULL }, - { "d", 500, NULL }, - { "e", 444, NULL }, - { "f", 278, NULL }, - { "g", 500, NULL }, - { "bullet", 350, NULL }, - { "h", 500, NULL }, - { "i", 278, NULL }, - { "Oslash", 722, NULL }, - { "dagger", 500, NULL }, - { "j", 278, NULL }, - { "k", 444, NULL }, - { "l", 278, NULL }, - { "m", 722, NULL }, - { "n", 500, NULL }, - { "tcommaaccent", 278, NULL }, - { "o", 500, NULL }, - { "ordfeminine", 276, NULL }, - { "ring", 333, NULL }, - { "p", 500, NULL }, - { "q", 500, NULL }, - { "uhungarumlaut", 500, NULL }, - { "r", 389, NULL }, - { "twosuperior", 300, NULL }, - { "aacute", 500, NULL }, - { "s", 389, NULL }, - { "OE", 944, NULL }, - { "t", 278, NULL }, - { "divide", 675, NULL }, - { "u", 500, NULL }, - { "Ccaron", 667, NULL }, - { "v", 444, NULL }, - { "w", 667, NULL }, - { "x", 444, NULL }, - { "y", 444, NULL }, - { "z", 389, NULL }, - { "Gbreve", 722, NULL }, - { "commaaccent", 250, NULL }, - { "hungarumlaut", 333, NULL }, - { "Idotaccent", 333, NULL }, - { "Nacute", 667, NULL }, - { "quotedbl", 420, NULL }, - { "gcommaaccent", 500, NULL }, - { "mu", 500, NULL }, - { "greaterequal", 549, NULL }, - { "Scaron", 500, NULL }, - { "Lslash", 556, NULL }, - { "semicolon", 333, NULL }, - { "oslash", 500, NULL }, - { "lessequal", 549, NULL }, - { "lozenge", 471, NULL }, - { "parenright", 333, NULL }, - { "ccaron", 444, NULL }, - { "Ecircumflex", 611, NULL }, - { "gbreve", 500, NULL }, - { "trademark", 980, NULL }, - { "daggerdbl", 500, NULL }, - { "nacute", 500, NULL }, - { "macron", 333, NULL }, - { "Otilde", 722, NULL }, - { "Emacron", 611, NULL }, - { "ellipsis", 889, NULL }, - { "scaron", 389, NULL }, - { "AE", 889, NULL }, - { "Ucircumflex", 722, NULL }, - { "lslash", 278, NULL }, - { "quotedblleft", 556, NULL }, - { "guilsinglright", 333, NULL }, - { "hyphen", 333, NULL }, - { "quotesingle", 214, NULL }, - { "eight", 500, NULL }, - { "exclamdown", 389, NULL }, - { "endash", 500, NULL }, - { "oe", 667, NULL }, - { "Abreve", 611, NULL }, - { "Umacron", 722, NULL }, - { "ecircumflex", 444, NULL }, - { "Adieresis", 611, NULL }, - { "copyright", 760, NULL }, - { "Egrave", 611, NULL }, - { "slash", 278, NULL }, - { "Edieresis", 611, NULL }, - { "otilde", 500, NULL }, - { "Idieresis", 333, NULL }, - { "parenleft", 333, NULL }, - { "one", 500, NULL }, - { "emacron", 444, NULL }, - { "Odieresis", 722, NULL }, - { "ucircumflex", 500, NULL }, - { "bracketleft", 389, NULL }, - { "Ugrave", 722, NULL }, - { "quoteright", 333, NULL }, - { "Udieresis", 722, NULL }, - { "perthousand", 1000, NULL }, - { "Ydieresis", 556, NULL }, - { "umacron", 500, NULL }, - { "abreve", 500, NULL }, - { "Eacute", 611, NULL }, - { "adieresis", 500, NULL }, - { "egrave", 444, NULL }, - { "edieresis", 444, NULL }, - { "idieresis", 278, NULL }, - { "Eth", 722, NULL }, - { "ae", 667, NULL }, - { "asterisk", 500, NULL }, - { "odieresis", 500, NULL }, - { "Uacute", 722, NULL }, - { "ugrave", 500, NULL }, - { "nine", 500, NULL }, - { "five", 500, NULL }, - { "udieresis", 500, NULL }, - { "Zcaron", 556, NULL }, - { "Scommaaccent", 500, NULL }, - { "threequarters", 750, NULL }, - { "guillemotright", 500, NULL }, - { "Ccedilla", 667, NULL }, - { "ydieresis", 444, NULL }, - { "tilde", 333, NULL }, - { "at", 920, NULL }, - { "eacute", 444, NULL }, - { "underscore", 500, NULL }, - { "Euro", 500, NULL }, - { "Dcroat", 722, NULL }, - { "multiply", 675, NULL }, - { "zero", 500, NULL }, - { "eth", 500, NULL }, - { "Scedilla", 500, NULL }, - { "Ograve", 722, NULL }, - { "Racute", 611, NULL }, - { "partialdiff", 476, NULL }, - { "uacute", 500, NULL }, - { "braceleft", 400, NULL }, - { "Thorn", 611, NULL }, - { "zcaron", 389, NULL }, - { "scommaaccent", 389, NULL }, - { "ccedilla", 444, NULL }, - { "Dcaron", 722, NULL }, - { "dcroat", 500, NULL }, - { "Ocircumflex", 722, NULL }, - { "Oacute", 722, NULL }, - { "scedilla", 389, NULL }, - { "ogonek", 333, NULL }, - { "ograve", 500, NULL }, - { "racute", 389, NULL }, - { "Tcaron", 556, NULL }, - { "Eogonek", 611, NULL }, - { "thorn", 500, NULL }, - { "degree", 400, NULL }, - { "registered", 760, NULL }, - { "radical", 453, NULL }, - { "Aring", 611, NULL }, - { "percent", 833, NULL }, - { "six", 500, NULL }, - { "paragraph", 523, NULL }, - { "dcaron", 544, NULL }, - { "Uogonek", 722, NULL }, - { "two", 500, NULL }, - { "summation", 600, NULL }, - { "Igrave", 333, NULL }, - { "Lacute", 556, NULL }, - { "ocircumflex", 500, NULL }, - { "oacute", 500, NULL }, - { "Uring", 722, NULL }, - { "Lcommaaccent", 556, NULL }, - { "tcaron", 300, NULL }, - { "eogonek", 444, NULL }, - { "Delta", 612, NULL }, - { "Ohungarumlaut", 722, NULL }, - { "asciicircum", 422, NULL }, - { "aring", 500, NULL }, - { "grave", 333, NULL }, - { "uogonek", 500, NULL }, - { "bracketright", 389, NULL }, - { "Iacute", 333, NULL }, - { "ampersand", 778, NULL }, - { "igrave", 278, NULL }, - { "lacute", 278, NULL }, - { "Ncaron", 667, NULL }, - { "plus", 675, NULL }, - { "uring", 500, NULL }, - { "quotesinglbase", 333, NULL }, - { "lcommaaccent", 278, NULL }, - { "Yacute", 556, NULL }, - { "ohungarumlaut", 500, NULL }, - { "threesuperior", 300, NULL }, - { "acute", 333, NULL }, - { "section", 500, NULL }, - { "dieresis", 333, NULL }, - { "iacute", 278, NULL }, - { "quotedblbase", 556, NULL }, - { "ncaron", 500, NULL }, - { "florin", 500, NULL }, - { "yacute", 444, NULL }, - { "Rcommaaccent", 611, NULL }, - { "fi", 500, NULL }, - { "fl", 500, NULL }, - { "Acircumflex", 611, NULL }, - { "Cacute", 667, NULL }, - { "Icircumflex", 333, NULL }, - { "guillemotleft", 500, NULL }, - { "germandbls", 500, NULL }, - { "Amacron", 611, NULL }, - { "seven", 500, NULL }, - { "Sacute", 500, NULL }, - { "ordmasculine", 310, NULL }, - { "dotlessi", 278, NULL }, - { "sterling", 500, NULL }, - { "notequal", 549, NULL }, - { "Imacron", 333, NULL }, - { "rcommaaccent", 389, NULL }, - { "Zdotaccent", 556, NULL }, - { "acircumflex", 500, NULL }, - { "cacute", 444, NULL }, - { "Ecaron", 611, NULL }, - { "icircumflex", 278, NULL }, - { "braceright", 400, NULL }, - { "quotedblright", 556, NULL }, - { "amacron", 500, NULL }, - { "sacute", 389, NULL }, - { "imacron", 278, NULL }, - { "cent", 500, NULL }, - { "currency", 500, NULL }, - { "logicalnot", 675, NULL }, - { "zdotaccent", 389, NULL }, - { "Atilde", 611, NULL }, - { "breve", 333, NULL }, - { "bar", 275, NULL }, - { "fraction", 167, NULL }, - { "less", 675, NULL }, - { "ecaron", 444, NULL }, - { "guilsinglleft", 333, NULL }, - { "exclam", 333, NULL }, - { "period", 250, NULL }, - { "Rcaron", 611, NULL }, - { "Kcommaaccent", 667, NULL }, - { "greater", 675, NULL }, - { "atilde", 500, NULL }, - { "brokenbar", 275, NULL }, - { "quoteleft", 333, NULL }, - { "Edotaccent", 611, NULL }, - { "onesuperior", 300, NULL } -}; - -static BuiltinFontWidth timesRomanWidthsTab[] = { - { "Ntilde", 722, NULL }, - { "rcaron", 333, NULL }, - { "kcommaaccent", 500, NULL }, - { "Ncommaaccent", 722, NULL }, - { "Zacute", 611, NULL }, - { "comma", 250, NULL }, - { "cedilla", 333, NULL }, - { "plusminus", 564, NULL }, - { "circumflex", 333, NULL }, - { "dotaccent", 333, NULL }, - { "edotaccent", 444, NULL }, - { "asciitilde", 541, NULL }, - { "colon", 278, NULL }, - { "onehalf", 750, NULL }, - { "dollar", 500, NULL }, - { "Lcaron", 611, NULL }, - { "ntilde", 500, NULL }, - { "Aogonek", 722, NULL }, - { "ncommaaccent", 500, NULL }, - { "minus", 564, NULL }, - { "Iogonek", 333, NULL }, - { "zacute", 444, NULL }, - { "yen", 500, NULL }, - { "space", 250, NULL }, - { "Omacron", 722, NULL }, - { "questiondown", 444, NULL }, - { "emdash", 1000, NULL }, - { "Agrave", 722, NULL }, - { "three", 500, NULL }, - { "numbersign", 500, NULL }, - { "lcaron", 344, NULL }, - { "A", 722, NULL }, - { "B", 667, NULL }, - { "C", 667, NULL }, - { "aogonek", 444, NULL }, - { "D", 722, NULL }, - { "E", 611, NULL }, - { "onequarter", 750, NULL }, - { "F", 556, NULL }, - { "G", 722, NULL }, - { "H", 722, NULL }, - { "I", 333, NULL }, - { "J", 389, NULL }, - { "K", 722, NULL }, - { "iogonek", 278, NULL }, - { "backslash", 278, NULL }, - { "L", 611, NULL }, - { "periodcentered", 250, NULL }, - { "M", 889, NULL }, - { "N", 722, NULL }, - { "omacron", 500, NULL }, - { "Tcommaaccent", 611, NULL }, - { "O", 722, NULL }, - { "P", 556, NULL }, - { "Q", 722, NULL }, - { "Uhungarumlaut", 722, NULL }, - { "R", 667, NULL }, - { "Aacute", 722, NULL }, - { "caron", 333, NULL }, - { "S", 556, NULL }, - { "T", 611, NULL }, - { "U", 722, NULL }, - { "agrave", 444, NULL }, - { "V", 722, NULL }, - { "W", 944, NULL }, - { "X", 722, NULL }, - { "question", 444, NULL }, - { "equal", 564, NULL }, - { "Y", 722, NULL }, - { "Z", 611, NULL }, - { "four", 500, NULL }, - { "a", 444, NULL }, - { "Gcommaaccent", 722, NULL }, - { "b", 500, NULL }, - { "c", 444, NULL }, - { "d", 500, NULL }, - { "e", 444, NULL }, - { "f", 333, NULL }, - { "g", 500, NULL }, - { "bullet", 350, NULL }, - { "h", 500, NULL }, - { "i", 278, NULL }, - { "Oslash", 722, NULL }, - { "dagger", 500, NULL }, - { "j", 278, NULL }, - { "k", 500, NULL }, - { "l", 278, NULL }, - { "m", 778, NULL }, - { "n", 500, NULL }, - { "tcommaaccent", 278, NULL }, - { "o", 500, NULL }, - { "ordfeminine", 276, NULL }, - { "ring", 333, NULL }, - { "p", 500, NULL }, - { "q", 500, NULL }, - { "uhungarumlaut", 500, NULL }, - { "r", 333, NULL }, - { "twosuperior", 300, NULL }, - { "aacute", 444, NULL }, - { "s", 389, NULL }, - { "OE", 889, NULL }, - { "t", 278, NULL }, - { "divide", 564, NULL }, - { "u", 500, NULL }, - { "Ccaron", 667, NULL }, - { "v", 500, NULL }, - { "w", 722, NULL }, - { "x", 500, NULL }, - { "y", 500, NULL }, - { "z", 444, NULL }, - { "Gbreve", 722, NULL }, - { "commaaccent", 250, NULL }, - { "hungarumlaut", 333, NULL }, - { "Idotaccent", 333, NULL }, - { "Nacute", 722, NULL }, - { "quotedbl", 408, NULL }, - { "gcommaaccent", 500, NULL }, - { "mu", 500, NULL }, - { "greaterequal", 549, NULL }, - { "Scaron", 556, NULL }, - { "Lslash", 611, NULL }, - { "semicolon", 278, NULL }, - { "oslash", 500, NULL }, - { "lessequal", 549, NULL }, - { "lozenge", 471, NULL }, - { "parenright", 333, NULL }, - { "ccaron", 444, NULL }, - { "Ecircumflex", 611, NULL }, - { "gbreve", 500, NULL }, - { "trademark", 980, NULL }, - { "daggerdbl", 500, NULL }, - { "nacute", 500, NULL }, - { "macron", 333, NULL }, - { "Otilde", 722, NULL }, - { "Emacron", 611, NULL }, - { "ellipsis", 1000, NULL }, - { "scaron", 389, NULL }, - { "AE", 889, NULL }, - { "Ucircumflex", 722, NULL }, - { "lslash", 278, NULL }, - { "quotedblleft", 444, NULL }, - { "guilsinglright", 333, NULL }, - { "hyphen", 333, NULL }, - { "quotesingle", 180, NULL }, - { "eight", 500, NULL }, - { "exclamdown", 333, NULL }, - { "endash", 500, NULL }, - { "oe", 722, NULL }, - { "Abreve", 722, NULL }, - { "Umacron", 722, NULL }, - { "ecircumflex", 444, NULL }, - { "Adieresis", 722, NULL }, - { "copyright", 760, NULL }, - { "Egrave", 611, NULL }, - { "slash", 278, NULL }, - { "Edieresis", 611, NULL }, - { "otilde", 500, NULL }, - { "Idieresis", 333, NULL }, - { "parenleft", 333, NULL }, - { "one", 500, NULL }, - { "emacron", 444, NULL }, - { "Odieresis", 722, NULL }, - { "ucircumflex", 500, NULL }, - { "bracketleft", 333, NULL }, - { "Ugrave", 722, NULL }, - { "quoteright", 333, NULL }, - { "Udieresis", 722, NULL }, - { "perthousand", 1000, NULL }, - { "Ydieresis", 722, NULL }, - { "umacron", 500, NULL }, - { "abreve", 444, NULL }, - { "Eacute", 611, NULL }, - { "adieresis", 444, NULL }, - { "egrave", 444, NULL }, - { "edieresis", 444, NULL }, - { "idieresis", 278, NULL }, - { "Eth", 722, NULL }, - { "ae", 667, NULL }, - { "asterisk", 500, NULL }, - { "odieresis", 500, NULL }, - { "Uacute", 722, NULL }, - { "ugrave", 500, NULL }, - { "nine", 500, NULL }, - { "five", 500, NULL }, - { "udieresis", 500, NULL }, - { "Zcaron", 611, NULL }, - { "Scommaaccent", 556, NULL }, - { "threequarters", 750, NULL }, - { "guillemotright", 500, NULL }, - { "Ccedilla", 667, NULL }, - { "ydieresis", 500, NULL }, - { "tilde", 333, NULL }, - { "at", 921, NULL }, - { "eacute", 444, NULL }, - { "underscore", 500, NULL }, - { "Euro", 500, NULL }, - { "Dcroat", 722, NULL }, - { "multiply", 564, NULL }, - { "zero", 500, NULL }, - { "eth", 500, NULL }, - { "Scedilla", 556, NULL }, - { "Ograve", 722, NULL }, - { "Racute", 667, NULL }, - { "partialdiff", 476, NULL }, - { "uacute", 500, NULL }, - { "braceleft", 480, NULL }, - { "Thorn", 556, NULL }, - { "zcaron", 444, NULL }, - { "scommaaccent", 389, NULL }, - { "ccedilla", 444, NULL }, - { "Dcaron", 722, NULL }, - { "dcroat", 500, NULL }, - { "Ocircumflex", 722, NULL }, - { "Oacute", 722, NULL }, - { "scedilla", 389, NULL }, - { "ogonek", 333, NULL }, - { "ograve", 500, NULL }, - { "racute", 333, NULL }, - { "Tcaron", 611, NULL }, - { "Eogonek", 611, NULL }, - { "thorn", 500, NULL }, - { "degree", 400, NULL }, - { "registered", 760, NULL }, - { "radical", 453, NULL }, - { "Aring", 722, NULL }, - { "percent", 833, NULL }, - { "six", 500, NULL }, - { "paragraph", 453, NULL }, - { "dcaron", 588, NULL }, - { "Uogonek", 722, NULL }, - { "two", 500, NULL }, - { "summation", 600, NULL }, - { "Igrave", 333, NULL }, - { "Lacute", 611, NULL }, - { "ocircumflex", 500, NULL }, - { "oacute", 500, NULL }, - { "Uring", 722, NULL }, - { "Lcommaaccent", 611, NULL }, - { "tcaron", 326, NULL }, - { "eogonek", 444, NULL }, - { "Delta", 612, NULL }, - { "Ohungarumlaut", 722, NULL }, - { "asciicircum", 469, NULL }, - { "aring", 444, NULL }, - { "grave", 333, NULL }, - { "uogonek", 500, NULL }, - { "bracketright", 333, NULL }, - { "Iacute", 333, NULL }, - { "ampersand", 778, NULL }, - { "igrave", 278, NULL }, - { "lacute", 278, NULL }, - { "Ncaron", 722, NULL }, - { "plus", 564, NULL }, - { "uring", 500, NULL }, - { "quotesinglbase", 333, NULL }, - { "lcommaaccent", 278, NULL }, - { "Yacute", 722, NULL }, - { "ohungarumlaut", 500, NULL }, - { "threesuperior", 300, NULL }, - { "acute", 333, NULL }, - { "section", 500, NULL }, - { "dieresis", 333, NULL }, - { "iacute", 278, NULL }, - { "quotedblbase", 444, NULL }, - { "ncaron", 500, NULL }, - { "florin", 500, NULL }, - { "yacute", 500, NULL }, - { "Rcommaaccent", 667, NULL }, - { "fi", 556, NULL }, - { "fl", 556, NULL }, - { "Acircumflex", 722, NULL }, - { "Cacute", 667, NULL }, - { "Icircumflex", 333, NULL }, - { "guillemotleft", 500, NULL }, - { "germandbls", 500, NULL }, - { "Amacron", 722, NULL }, - { "seven", 500, NULL }, - { "Sacute", 556, NULL }, - { "ordmasculine", 310, NULL }, - { "dotlessi", 278, NULL }, - { "sterling", 500, NULL }, - { "notequal", 549, NULL }, - { "Imacron", 333, NULL }, - { "rcommaaccent", 333, NULL }, - { "Zdotaccent", 611, NULL }, - { "acircumflex", 444, NULL }, - { "cacute", 444, NULL }, - { "Ecaron", 611, NULL }, - { "icircumflex", 278, NULL }, - { "braceright", 480, NULL }, - { "quotedblright", 444, NULL }, - { "amacron", 444, NULL }, - { "sacute", 389, NULL }, - { "imacron", 278, NULL }, - { "cent", 500, NULL }, - { "currency", 500, NULL }, - { "logicalnot", 564, NULL }, - { "zdotaccent", 444, NULL }, - { "Atilde", 722, NULL }, - { "breve", 333, NULL }, - { "bar", 200, NULL }, - { "fraction", 167, NULL }, - { "less", 564, NULL }, - { "ecaron", 444, NULL }, - { "guilsinglleft", 333, NULL }, - { "exclam", 333, NULL }, - { "period", 250, NULL }, - { "Rcaron", 667, NULL }, - { "Kcommaaccent", 722, NULL }, - { "greater", 564, NULL }, - { "atilde", 444, NULL }, - { "brokenbar", 200, NULL }, - { "quoteleft", 333, NULL }, - { "Edotaccent", 611, NULL }, - { "onesuperior", 300, NULL } -}; - -static BuiltinFontWidth zapfDingbatsWidthsTab[] = { - { "a81", 438, NULL }, - { "a82", 138, NULL }, - { "a83", 277, NULL }, - { "a84", 415, NULL }, - { "a85", 509, NULL }, - { "a86", 410, NULL }, - { "a87", 234, NULL }, - { "a88", 234, NULL }, - { "a89", 390, NULL }, - { "a140", 788, NULL }, - { "a141", 788, NULL }, - { "a142", 788, NULL }, - { "a143", 788, NULL }, - { "a144", 788, NULL }, - { "a145", 788, NULL }, - { "a146", 788, NULL }, - { "a147", 788, NULL }, - { "a148", 788, NULL }, - { "a149", 788, NULL }, - { "a90", 390, NULL }, - { "a91", 276, NULL }, - { "a92", 276, NULL }, - { "space", 278, NULL }, - { "a93", 317, NULL }, - { "a94", 317, NULL }, - { "a95", 334, NULL }, - { "a96", 334, NULL }, - { "a97", 392, NULL }, - { "a98", 392, NULL }, - { "a99", 668, NULL }, - { "a150", 788, NULL }, - { "a151", 788, NULL }, - { "a152", 788, NULL }, - { "a153", 788, NULL }, - { "a154", 788, NULL }, - { "a155", 788, NULL }, - { "a156", 788, NULL }, - { "a157", 788, NULL }, - { "a158", 788, NULL }, - { "a159", 788, NULL }, - { "a160", 894, NULL }, - { "a161", 838, NULL }, - { "a162", 924, NULL }, - { "a163", 1016, NULL }, - { "a164", 458, NULL }, - { "a165", 924, NULL }, - { "a166", 918, NULL }, - { "a167", 927, NULL }, - { "a168", 928, NULL }, - { "a169", 928, NULL }, - { "a170", 834, NULL }, - { "a171", 873, NULL }, - { "a172", 828, NULL }, - { "a173", 924, NULL }, - { "a174", 917, NULL }, - { "a175", 930, NULL }, - { "a176", 931, NULL }, - { "a177", 463, NULL }, - { "a178", 883, NULL }, - { "a179", 836, NULL }, - { "a180", 867, NULL }, - { "a181", 696, NULL }, - { "a182", 874, NULL }, - { "a183", 760, NULL }, - { "a184", 946, NULL }, - { "a185", 865, NULL }, - { "a186", 967, NULL }, - { "a187", 831, NULL }, - { "a188", 873, NULL }, - { "a189", 927, NULL }, - { "a1", 974, NULL }, - { "a2", 961, NULL }, - { "a3", 980, NULL }, - { "a4", 719, NULL }, - { "a5", 789, NULL }, - { "a6", 494, NULL }, - { "a7", 552, NULL }, - { "a8", 537, NULL }, - { "a9", 577, NULL }, - { "a190", 970, NULL }, - { "a191", 918, NULL }, - { "a192", 748, NULL }, - { "a193", 836, NULL }, - { "a194", 771, NULL }, - { "a195", 888, NULL }, - { "a196", 748, NULL }, - { "a197", 771, NULL }, - { "a198", 888, NULL }, - { "a199", 867, NULL }, - { "a10", 692, NULL }, - { "a11", 960, NULL }, - { "a12", 939, NULL }, - { "a13", 549, NULL }, - { "a14", 855, NULL }, - { "a15", 911, NULL }, - { "a16", 933, NULL }, - { "a17", 945, NULL }, - { "a18", 974, NULL }, - { "a19", 755, NULL }, - { "a20", 846, NULL }, - { "a21", 762, NULL }, - { "a22", 761, NULL }, - { "a23", 571, NULL }, - { "a24", 677, NULL }, - { "a25", 763, NULL }, - { "a26", 760, NULL }, - { "a27", 759, NULL }, - { "a28", 754, NULL }, - { "a29", 786, NULL }, - { "a30", 788, NULL }, - { "a31", 788, NULL }, - { "a32", 790, NULL }, - { "a33", 793, NULL }, - { "a34", 794, NULL }, - { "a35", 816, NULL }, - { "a36", 823, NULL }, - { "a37", 789, NULL }, - { "a38", 841, NULL }, - { "a39", 823, NULL }, - { "a40", 833, NULL }, - { "a41", 816, NULL }, - { "a42", 831, NULL }, - { "a43", 923, NULL }, - { "a44", 744, NULL }, - { "a45", 723, NULL }, - { "a46", 749, NULL }, - { "a47", 790, NULL }, - { "a48", 792, NULL }, - { "a49", 695, NULL }, - { "a100", 668, NULL }, - { "a101", 732, NULL }, - { "a102", 544, NULL }, - { "a103", 544, NULL }, - { "a104", 910, NULL }, - { "a105", 911, NULL }, - { "a106", 667, NULL }, - { "a107", 760, NULL }, - { "a108", 760, NULL }, - { "a109", 626, NULL }, - { "a50", 776, NULL }, - { "a51", 768, NULL }, - { "a52", 792, NULL }, - { "a53", 759, NULL }, - { "a54", 707, NULL }, - { "a55", 708, NULL }, - { "a56", 682, NULL }, - { "a57", 701, NULL }, - { "a58", 826, NULL }, - { "a59", 815, NULL }, - { "a110", 694, NULL }, - { "a111", 595, NULL }, - { "a112", 776, NULL }, - { "a117", 690, NULL }, - { "a118", 791, NULL }, - { "a119", 790, NULL }, - { "a60", 789, NULL }, - { "a61", 789, NULL }, - { "a62", 707, NULL }, - { "a63", 687, NULL }, - { "a64", 696, NULL }, - { "a65", 689, NULL }, - { "a66", 786, NULL }, - { "a67", 787, NULL }, - { "a68", 713, NULL }, - { "a69", 791, NULL }, - { "a200", 696, NULL }, - { "a201", 874, NULL }, - { "a120", 788, NULL }, - { "a121", 788, NULL }, - { "a202", 974, NULL }, - { "a122", 788, NULL }, - { "a203", 762, NULL }, - { "a123", 788, NULL }, - { "a204", 759, NULL }, - { "a124", 788, NULL }, - { "a205", 509, NULL }, - { "a125", 788, NULL }, - { "a206", 410, NULL }, - { "a126", 788, NULL }, - { "a127", 788, NULL }, - { "a128", 788, NULL }, - { "a129", 788, NULL }, - { "a70", 785, NULL }, - { "a71", 791, NULL }, - { "a72", 873, NULL }, - { "a73", 761, NULL }, - { "a74", 762, NULL }, - { "a75", 759, NULL }, - { "a76", 892, NULL }, - { "a77", 892, NULL }, - { "a78", 788, NULL }, - { "a79", 784, NULL }, - { "a130", 788, NULL }, - { "a131", 788, NULL }, - { "a132", 788, NULL }, - { "a133", 788, NULL }, - { "a134", 788, NULL }, - { "a135", 788, NULL }, - { "a136", 788, NULL }, - { "a137", 788, NULL }, - { "a138", 788, NULL }, - { "a139", 788, NULL } -}; - -BuiltinFont builtinFonts[] = { - { "Courier", standardEncoding, 629, -157, { -23, -250, 715, 805}, NULL }, - { "Courier-Bold", standardEncoding, 629, -157, {-113, -250, 749, 801}, NULL }, - { "Courier-BoldOblique", standardEncoding, 629, -157, { -57, -250, 869, 801}, NULL }, - { "Courier-Oblique", standardEncoding, 629, -157, { -27, -250, 849, 805}, NULL }, - { "Helvetica", standardEncoding, 718, -207, {-166, -225, 1000, 931}, NULL }, - { "Helvetica-Bold", standardEncoding, 718, -207, {-170, -228, 1003, 962}, NULL }, - { "Helvetica-BoldOblique", standardEncoding, 718, -207, {-174, -228, 1114, 962}, NULL }, - { "Helvetica-Oblique", standardEncoding, 718, -207, {-170, -225, 1116, 931}, NULL }, - { "Symbol", symbolEncoding, 1010, -293, {-180, -293, 1090, 1010}, NULL }, - { "Times-Bold", standardEncoding, 683, -217, {-168, -218, 1000, 935}, NULL }, - { "Times-BoldItalic", standardEncoding, 683, -217, {-200, -218, 996, 921}, NULL }, - { "Times-Italic", standardEncoding, 683, -217, {-169, -217, 1010, 883}, NULL }, - { "Times-Roman", standardEncoding, 683, -217, {-168, -218, 1000, 898}, NULL }, - { "ZapfDingbats", zapfDingbatsEncoding, 820, -143, { -1, -143, 981, 820}, NULL } -}; - -BuiltinFont *builtinFontSubst[] = { - &builtinFonts[0], - &builtinFonts[3], - &builtinFonts[1], - &builtinFonts[2], - &builtinFonts[4], - &builtinFonts[7], - &builtinFonts[5], - &builtinFonts[6], - &builtinFonts[12], - &builtinFonts[11], - &builtinFonts[9], - &builtinFonts[10] -}; - -void initBuiltinFontTables() { - builtinFonts[0].widths = new BuiltinFontWidths(courierWidthsTab, 315); - builtinFonts[1].widths = new BuiltinFontWidths(courierBoldWidthsTab, 315); - builtinFonts[2].widths = new BuiltinFontWidths(courierBoldObliqueWidthsTab, 315); - builtinFonts[3].widths = new BuiltinFontWidths(courierObliqueWidthsTab, 315); - builtinFonts[4].widths = new BuiltinFontWidths(helveticaWidthsTab, 315); - builtinFonts[5].widths = new BuiltinFontWidths(helveticaBoldWidthsTab, 316); - builtinFonts[6].widths = new BuiltinFontWidths(helveticaBoldObliqueWidthsTab, 315); - builtinFonts[7].widths = new BuiltinFontWidths(helveticaObliqueWidthsTab, 315); - builtinFonts[8].widths = new BuiltinFontWidths(symbolWidthsTab, 190); - builtinFonts[9].widths = new BuiltinFontWidths(timesBoldWidthsTab, 315); - builtinFonts[10].widths = new BuiltinFontWidths(timesBoldItalicWidthsTab, 315); - builtinFonts[11].widths = new BuiltinFontWidths(timesItalicWidthsTab, 315); - builtinFonts[12].widths = new BuiltinFontWidths(timesRomanWidthsTab, 315); - builtinFonts[13].widths = new BuiltinFontWidths(zapfDingbatsWidthsTab, 202); -} - -void freeBuiltinFontTables() { - int i; - - for (i = 0; i < 14; ++i) { - delete builtinFonts[i].widths; - } -} diff --git a/xpdf/xpdf/BuiltinFontTables.h b/xpdf/xpdf/BuiltinFontTables.h deleted file mode 100644 index eb45549ef..000000000 --- a/xpdf/xpdf/BuiltinFontTables.h +++ /dev/null @@ -1,23 +0,0 @@ -//======================================================================== -// -// BuiltinFontTables.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef BUILTINFONTTABLES_H -#define BUILTINFONTTABLES_H - -#include "BuiltinFont.h" - -#define nBuiltinFonts 14 -#define nBuiltinFontSubsts 12 - -extern BuiltinFont builtinFonts[nBuiltinFonts]; -extern BuiltinFont *builtinFontSubst[nBuiltinFontSubsts]; - -extern void initBuiltinFontTables(); -extern void freeBuiltinFontTables(); - -#endif diff --git a/xpdf/xpdf/CMap.cc b/xpdf/xpdf/CMap.cc deleted file mode 100644 index 89905a8c3..000000000 --- a/xpdf/xpdf/CMap.cc +++ /dev/null @@ -1,408 +0,0 @@ -//======================================================================== -// -// CMap.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include "gmem.h" -#include "gfile.h" -#include "GString.h" -#include "Error.h" -#include "GlobalParams.h" -#include "PSTokenizer.h" -#include "CMap.h" - -//------------------------------------------------------------------------ - -struct CMapVectorEntry { - GBool isVector; - union { - CMapVectorEntry *vector; - CID cid; - }; -}; - -//------------------------------------------------------------------------ - -static int CMap_getCharFromFile(void *data) { - return fgetc((FILE *)data); -} - -//------------------------------------------------------------------------ - -CMap *CMap::parse(CMapCache *cache, GString *collectionA, - GString *cMapNameA) { - FILE *f; - CMap *cmap; - PSTokenizer *pst; - char tok1[256], tok2[256], tok3[256]; - int n1, n2, n3; - Guint start, end, code; - - if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) { - - // Check for an identity CMap. - if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) { - return new CMap(collectionA->copy(), cMapNameA->copy(), 0); - } - if (!cMapNameA->cmp("Identity-V")) { - return new CMap(collectionA->copy(), cMapNameA->copy(), 1); - } - - error(-1, "Couldn't find '%s' CMap file for '%s' collection", - cMapNameA->getCString(), collectionA->getCString()); - return NULL; - } - - cmap = new CMap(collectionA->copy(), cMapNameA->copy()); - - pst = new PSTokenizer(&CMap_getCharFromFile, f); - pst->getToken(tok1, sizeof(tok1), &n1); - while (pst->getToken(tok2, sizeof(tok2), &n2)) { - if (!strcmp(tok2, "usecmap")) { - if (tok1[0] == '/') { - cmap->useCMap(cache, tok1 + 1); - } - pst->getToken(tok1, sizeof(tok1), &n1); - } else if (!strcmp(tok1, "/WMode")) { - cmap->wMode = atoi(tok2); - pst->getToken(tok1, sizeof(tok1), &n1); - } else if (!strcmp(tok2, "begincodespacerange")) { - while (pst->getToken(tok1, sizeof(tok1), &n1)) { - if (!strcmp(tok1, "endcodespacerange")) { - break; - } - if (!pst->getToken(tok2, sizeof(tok2), &n2) || - !strcmp(tok2, "endcodespacerange")) { - error(-1, "Illegal entry in codespacerange block in CMap"); - break; - } - if (tok1[0] == '<' && tok2[0] == '<' && - n1 == n2 && n1 >= 4 && (n1 & 1) == 0) { - tok1[n1 - 1] = tok2[n1 - 1] = '\0'; - sscanf(tok1 + 1, "%x", &start); - sscanf(tok2 + 1, "%x", &end); - n1 = (n1 - 2) / 2; - cmap->addCodeSpace(cmap->vector, start, end, n1); - } - } - pst->getToken(tok1, sizeof(tok1), &n1); - } else if (!strcmp(tok2, "begincidchar")) { - while (pst->getToken(tok1, sizeof(tok1), &n1)) { - if (!strcmp(tok1, "endcidchar")) { - break; - } - if (!pst->getToken(tok2, sizeof(tok2), &n2) || - !strcmp(tok2, "endcidchar")) { - error(-1, "Illegal entry in cidchar block in CMap"); - break; - } - if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' && - n1 >= 4 && (n1 & 1) == 0)) { - error(-1, "Illegal entry in cidchar block in CMap"); - continue; - } - tok1[n1 - 1] = '\0'; - if (sscanf(tok1 + 1, "%x", &code) != 1) { - error(-1, "Illegal entry in cidchar block in CMap"); - continue; - } - n1 = (n1 - 2) / 2; - cmap->addCIDs(code, code, n1, (CID)atoi(tok2)); - } - pst->getToken(tok1, sizeof(tok1), &n1); - } else if (!strcmp(tok2, "begincidrange")) { - while (pst->getToken(tok1, sizeof(tok1), &n1)) { - if (!strcmp(tok1, "endcidrange")) { - break; - } - if (!pst->getToken(tok2, sizeof(tok2), &n2) || - !strcmp(tok2, "endcidrange") || - !pst->getToken(tok3, sizeof(tok3), &n3) || - !strcmp(tok3, "endcidrange")) { - error(-1, "Illegal entry in cidrange block in CMap"); - break; - } - if (tok1[0] == '<' && tok2[0] == '<' && - n1 == n2 && n1 >= 4 && (n1 & 1) == 0) { - tok1[n1 - 1] = tok2[n1 - 1] = '\0'; - sscanf(tok1 + 1, "%x", &start); - sscanf(tok2 + 1, "%x", &end); - n1 = (n1 - 2) / 2; - cmap->addCIDs(start, end, n1, (CID)atoi(tok3)); - } - } - pst->getToken(tok1, sizeof(tok1), &n1); - } else { - strcpy(tok1, tok2); - } - } - delete pst; - - fclose(f); - - return cmap; -} - -CMap::CMap(GString *collectionA, GString *cMapNameA) { - int i; - - collection = collectionA; - cMapName = cMapNameA; - wMode = 0; - vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); - for (i = 0; i < 256; ++i) { - vector[i].isVector = gFalse; - vector[i].cid = 0; - } - refCnt = 1; -#if MULTITHREADED - gInitMutex(&mutex); -#endif -} - -CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) { - collection = collectionA; - cMapName = cMapNameA; - wMode = wModeA; - vector = NULL; - refCnt = 1; -#if MULTITHREADED - gInitMutex(&mutex); -#endif -} - -void CMap::useCMap(CMapCache *cache, char *useName) { - GString *useNameStr; - CMap *subCMap; - - useNameStr = new GString(useName); - subCMap = cache->getCMap(collection, useNameStr); - delete useNameStr; - if (!subCMap) { - return; - } - copyVector(vector, subCMap->vector); - subCMap->decRefCnt(); -} - -void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) { - int i, j; - - for (i = 0; i < 256; ++i) { - if (src[i].isVector) { - if (!dest[i].isVector) { - dest[i].isVector = gTrue; - dest[i].vector = - (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); - for (j = 0; j < 256; ++j) { - dest[i].vector[j].isVector = gFalse; - dest[i].vector[j].cid = 0; - } - } - copyVector(dest[i].vector, src[i].vector); - } else { - if (dest[i].isVector) { - error(-1, "Collision in usecmap"); - } else { - dest[i].cid = src[i].cid; - } - } - } -} - -void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end, - Guint nBytes) { - Guint start2, end2; - int startByte, endByte, i, j; - - if (nBytes > 1) { - startByte = (start >> (8 * (nBytes - 1))) & 0xff; - endByte = (end >> (8 * (nBytes - 1))) & 0xff; - start2 = start & ((1 << (8 * (nBytes - 1))) - 1); - end2 = end & ((1 << (8 * (nBytes - 1))) - 1); - for (i = startByte; i <= endByte; ++i) { - if (!vec[i].isVector) { - vec[i].isVector = gTrue; - vec[i].vector = - (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); - for (j = 0; j < 256; ++j) { - vec[i].vector[j].isVector = gFalse; - vec[i].vector[j].cid = 0; - } - } - addCodeSpace(vec[i].vector, start2, end2, nBytes - 1); - } - } -} - -void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) { - CMapVectorEntry *vec; - CID cid; - int byte; - Guint i; - - vec = vector; - for (i = nBytes - 1; i >= 1; --i) { - byte = (start >> (8 * i)) & 0xff; - if (!vec[byte].isVector) { - error(-1, "Invalid CID (%0*x - %0*x) in CMap", - 2*nBytes, start, 2*nBytes, end); - return; - } - vec = vec[byte].vector; - } - cid = firstCID; - for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) { - if (vec[byte].isVector) { - error(-1, "Invalid CID (%0*x - %0*x) in CMap", - 2*nBytes, start, 2*nBytes, end); - } else { - vec[byte].cid = cid; - } - ++cid; - } -} - -CMap::~CMap() { - delete collection; - delete cMapName; - if (vector) { - freeCMapVector(vector); - } -#if MULTITHREADED - gDestroyMutex(&mutex); -#endif -} - -void CMap::freeCMapVector(CMapVectorEntry *vec) { - int i; - - for (i = 0; i < 256; ++i) { - if (vec[i].isVector) { - freeCMapVector(vec[i].vector); - } - } - gfree(vec); -} - -void CMap::incRefCnt() { -#if MULTITHREADED - gLockMutex(&mutex); -#endif - ++refCnt; -#if MULTITHREADED - gUnlockMutex(&mutex); -#endif -} - -void CMap::decRefCnt() { - GBool done; - -#if MULTITHREADED - gLockMutex(&mutex); -#endif - done = --refCnt == 0; -#if MULTITHREADED - gUnlockMutex(&mutex); -#endif - if (done) { - delete this; - } -} - -GBool CMap::match(GString *collectionA, GString *cMapNameA) { - return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA); -} - -CID CMap::getCID(char *s, int len, int *nUsed) { - CMapVectorEntry *vec; - int n, i; - - if (!(vec = vector)) { - // identity CMap - *nUsed = 2; - if (len < 2) { - return 0; - } - return ((s[0] & 0xff) << 8) + (s[1] & 0xff); - } - n = 0; - while (1) { - if (n >= len) { - *nUsed = n; - return 0; - } - i = s[n++] & 0xff; - if (!vec[i].isVector) { - *nUsed = n; - return vec[i].cid; - } - vec = vec[i].vector; - } -} - -//------------------------------------------------------------------------ - -CMapCache::CMapCache() { - int i; - - for (i = 0; i < cMapCacheSize; ++i) { - cache[i] = NULL; - } -} - -CMapCache::~CMapCache() { - int i; - - for (i = 0; i < cMapCacheSize; ++i) { - if (cache[i]) { - cache[i]->decRefCnt(); - } - } -} - -CMap *CMapCache::getCMap(GString *collection, GString *cMapName) { - CMap *cmap; - int i, j; - - if (cache[0] && cache[0]->match(collection, cMapName)) { - cache[0]->incRefCnt(); - return cache[0]; - } - for (i = 1; i < cMapCacheSize; ++i) { - if (cache[i] && cache[i]->match(collection, cMapName)) { - cmap = cache[i]; - for (j = i; j >= 1; --j) { - cache[j] = cache[j - 1]; - } - cache[0] = cmap; - cmap->incRefCnt(); - return cmap; - } - } - if ((cmap = CMap::parse(this, collection, cMapName))) { - if (cache[cMapCacheSize - 1]) { - cache[cMapCacheSize - 1]->decRefCnt(); - } - for (j = cMapCacheSize - 1; j >= 1; --j) { - cache[j] = cache[j - 1]; - } - cache[0] = cmap; - cmap->incRefCnt(); - return cmap; - } - return NULL; -} diff --git a/xpdf/xpdf/CMap.h b/xpdf/xpdf/CMap.h deleted file mode 100644 index c321a57ab..000000000 --- a/xpdf/xpdf/CMap.h +++ /dev/null @@ -1,102 +0,0 @@ -//======================================================================== -// -// CMap.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef CMAP_H -#define CMAP_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "CharTypes.h" - -#if MULTITHREADED -#include "GMutex.h" -#endif - -class GString; -struct CMapVectorEntry; -class CMapCache; - -//------------------------------------------------------------------------ - -class CMap { -public: - - // Create the CMap specified by and . Sets - // the initial reference count to 1. Returns NULL on failure. - static CMap *parse(CMapCache *cache, GString *collectionA, - GString *cMapNameA); - - ~CMap(); - - void incRefCnt(); - void decRefCnt(); - - // Return collection name (-). - GString *getCollection() { return collection; } - - // Return true if this CMap matches the specified , and - // . - GBool match(GString *collectionA, GString *cMapNameA); - - // Return the CID corresponding to the character code starting at - // , which contains bytes. Sets * to the number of - // bytes used by the char code. - CID getCID(char *s, int len, int *nUsed); - - // Return the writing mode (0=horizontal, 1=vertical). - int getWMode() { return wMode; } - -private: - - CMap(GString *collectionA, GString *cMapNameA); - CMap(GString *collectionA, GString *cMapNameA, int wModeA); - void useCMap(CMapCache *cache, char *useName); - void copyVector(CMapVectorEntry *dest, CMapVectorEntry *src); - void addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end, - Guint nBytes); - void addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID); - void freeCMapVector(CMapVectorEntry *vec); - - GString *collection; - GString *cMapName; - int wMode; // writing mode (0=horizontal, 1=vertical) - CMapVectorEntry *vector; // vector for first byte (NULL for - // identity CMap) - int refCnt; -#if MULTITHREADED - GMutex mutex; -#endif -}; - -//------------------------------------------------------------------------ - -#define cMapCacheSize 4 - -class CMapCache { -public: - - CMapCache(); - ~CMapCache(); - - // Get the CMap for the specified character collection. - // Increments its reference count; there will be one reference for - // the cache plus one for the caller of this function. Returns NULL - // on failure. - CMap *getCMap(GString *collection, GString *cMapName); - -private: - - CMap *cache[cMapCacheSize]; -}; - -#endif diff --git a/xpdf/xpdf/Catalog.cc b/xpdf/xpdf/Catalog.cc deleted file mode 100644 index 097d5094e..000000000 --- a/xpdf/xpdf/Catalog.cc +++ /dev/null @@ -1,426 +0,0 @@ -//======================================================================== -// -// Catalog.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include "gmem.h" -#include "Object.h" -#include "XRef.h" -#include "Array.h" -#include "Dict.h" -#include "Page.h" -#include "Error.h" -#include "Link.h" -#include "UGString.h" -#include "Catalog.h" - -//------------------------------------------------------------------------ -// Catalog -//------------------------------------------------------------------------ - -Catalog::Catalog(XRef *xrefA) { - Object catDict, pagesDict; - Object obj, obj2; - int numPages0; - int i; - - ok = gTrue; - xref = xrefA; - pages = NULL; - pageRefs = NULL; - numPages = pagesSize = 0; - baseURI = NULL; - pageMode = UseNone; - - xref->getCatalog(&catDict); - if (!catDict.isDict()) { - error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName()); - goto err1; - } - - // read page tree - catDict.dictLookup("Pages", &pagesDict); - // This should really be isDict("Pages"), but I've seen at least one - // PDF file where the /Type entry is missing. - if (!pagesDict.isDict()) { - error(-1, "Top-level pages object is wrong type (%s)", - pagesDict.getTypeName()); - goto err2; - } - pagesDict.dictLookup("Count", &obj); - // some PDF files actually use real numbers here ("/Count 9.0") - if (!obj.isNum()) { - error(-1, "Page count in top-level pages object is wrong type (%s)", - obj.getTypeName()); - goto err3; - } - pagesSize = numPages0 = (int)obj.getNum(); - obj.free(); - - pages = (Page **)gmallocn(pagesSize, sizeof(Page *)); - pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref)); - for (i = 0; i < pagesSize; ++i) { - pages[i] = NULL; - pageRefs[i].num = -1; - pageRefs[i].gen = -1; - } - numPages = readPageTree(pagesDict.getDict(), NULL, 0); - if (numPages != numPages0) { - error(-1, "Page count in top-level pages object is incorrect"); - } - pagesDict.free(); - - // read named destination dictionary - catDict.dictLookup("Dests", &dests); - - // read root of named destination tree - if (catDict.dictLookup("Names", &obj)->isDict()) { - obj.dictLookup("Dests", &obj2); - destNameTree.init(xref, &obj2); - obj2.free(); - } - obj.free(); - - // read base URI - if (catDict.dictLookup("URI", &obj)->isDict()) { - if (obj.dictLookup("Base", &obj2)->isString()) { - baseURI = obj2.getString()->copy(); - } - obj2.free(); - } - obj.free(); - - // read page mode - if (catDict.dictLookup("PageMode", &obj)->isName()) { - if (strcmp(obj.getName(), "UseNone") == 0) - pageMode = UseNone; - else if (strcmp(obj.getName(), "UseOutlines") == 0) - pageMode = UseOutlines; - else if (strcmp(obj.getName(), "UseThumbs") == 0) - pageMode = UseThumbs; - else if (strcmp(obj.getName(), "FullScreen") == 0) - pageMode = FullScreen; - else if (strcmp(obj.getName(), "UseOC") == 0) - pageMode = UseOC; - } else { - pageMode = UseNone; - } - obj.free(); - - // get the metadata stream - catDict.dictLookup("Metadata", &metadata); - - // get the structure tree root - catDict.dictLookup("StructTreeRoot", &structTreeRoot); - - // get the outline dictionary - catDict.dictLookup("Outlines", &outline); - - // get the AcroForm dictionary - catDict.dictLookup("AcroForm", &acroForm); - - catDict.free(); - return; - - err3: - obj.free(); - err2: - pagesDict.free(); - err1: - catDict.free(); - dests.initNull(); - ok = gFalse; -} - -Catalog::~Catalog() { - int i; - - if (pages) { - for (i = 0; i < pagesSize; ++i) { - if (pages[i]) { - delete pages[i]; - } - } - gfree(pages); - gfree(pageRefs); - } - dests.free(); - destNameTree.free(); - if (baseURI) { - delete baseURI; - } - metadata.free(); - structTreeRoot.free(); - outline.free(); - acroForm.free(); -} - -GString *Catalog::readMetadata() { - GString *s; - Dict *dict; - Object obj; - int c; - - if (!metadata.isStream()) { - return NULL; - } - dict = metadata.streamGetDict(); - if (!dict->lookup("Subtype", &obj)->isName("XML")) { - error(-1, "Unknown Metadata type: '%s'", - obj.isName() ? obj.getName() : "???"); - } - obj.free(); - s = new GString(); - metadata.streamReset(); - while ((c = metadata.streamGetChar()) != EOF) { - s->append(c); - } - metadata.streamClose(); - return s; -} - -int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { - Object kids; - Object kid; - Object kidRef; - PageAttrs *attrs1, *attrs2; - Page *page; - int i, j; - - attrs1 = new PageAttrs(attrs, pagesDict); - pagesDict->lookup("Kids", &kids); - if (!kids.isArray()) { - error(-1, "Kids object (page %d) is wrong type (%s)", - start+1, kids.getTypeName()); - goto err1; - } - for (i = 0; i < kids.arrayGetLength(); ++i) { - kids.arrayGet(i, &kid); - if (kid.isDict("Page")) { - attrs2 = new PageAttrs(attrs1, kid.getDict()); - page = new Page(xref, start+1, kid.getDict(), attrs2); - if (!page->isOk()) { - ++start; - goto err3; - } - if (start >= pagesSize) { - pagesSize += 32; - pages = (Page **)greallocn(pages, pagesSize, sizeof(Page *)); - pageRefs = (Ref *)greallocn(pageRefs, pagesSize, sizeof(Ref)); - for (j = pagesSize - 32; j < pagesSize; ++j) { - pages[j] = NULL; - pageRefs[j].num = -1; - pageRefs[j].gen = -1; - } - } - pages[start] = page; - kids.arrayGetNF(i, &kidRef); - if (kidRef.isRef()) { - pageRefs[start].num = kidRef.getRefNum(); - pageRefs[start].gen = kidRef.getRefGen(); - } - kidRef.free(); - ++start; - // This should really be isDict("Pages"), but I've seen at least one - // PDF file where the /Type entry is missing. - } else if (kid.isDict()) { - if ((start = readPageTree(kid.getDict(), attrs1, start)) - < 0) - goto err2; - } else { - error(-1, "Kid object (page %d) is wrong type (%s)", - start+1, kid.getTypeName()); - } - kid.free(); - } - delete attrs1; - kids.free(); - return start; - - err3: - delete page; - err2: - kid.free(); - err1: - kids.free(); - delete attrs1; - ok = gFalse; - return -1; -} - -int Catalog::findPage(int num, int gen) { - int i; - - for (i = 0; i < numPages; ++i) { - if (pageRefs[i].num == num && pageRefs[i].gen == gen) - return i + 1; - } - return 0; -} - -LinkDest *Catalog::findDest(UGString *name) { - LinkDest *dest; - Object obj1, obj2; - GBool found; - - // try named destination dictionary then name tree - found = gFalse; - if (dests.isDict()) { - if (!dests.dictLookup(*name, &obj1)->isNull()) - found = gTrue; - else - obj1.free(); - } - if (!found) { - if (destNameTree.lookup(name, &obj1)) - found = gTrue; - else - obj1.free(); - } - if (!found) - return NULL; - - // construct LinkDest - dest = NULL; - if (obj1.isArray()) { - dest = new LinkDest(obj1.getArray()); - } else if (obj1.isDict()) { - if (obj1.dictLookup("D", &obj2)->isArray()) - dest = new LinkDest(obj2.getArray()); - else - error(-1, "Bad named destination value"); - obj2.free(); - } else { - error(-1, "Bad named destination value"); - } - obj1.free(); - if (dest && !dest->isOk()) { - delete dest; - dest = NULL; - } - - return dest; -} - -NameTree::NameTree(void) -{ - size = 0; - length = 0; - entries = NULL; -} - -NameTree::Entry::Entry(Array *array, int index) { - GString n; - if (!array->getString(index, &n) || !array->getNF(index + 1, &value)) - error(-1, "Invalid page tree"); - name = new UGString(n); -} - -NameTree::Entry::~Entry() { - value.free(); - delete name; -} - -void NameTree::addEntry(Entry *entry) -{ - if (length == size) { - if (length == 0) { - size = 8; - } else { - size *= 2; - } - entries = (Entry **) grealloc (entries, sizeof (Entry *) * size); - } - - entries[length] = entry; - ++length; -} - -void NameTree::init(XRef *xrefA, Object *tree) { - xref = xrefA; - parse(tree); -} - -void NameTree::parse(Object *tree) { - Object names; - Object kids, kid; - int i; - - if (!tree->isDict()) - return; - - // leaf node - if (tree->dictLookup("Names", &names)->isArray()) { - for (i = 0; i < names.arrayGetLength(); i += 2) { - NameTree::Entry *entry; - - entry = new Entry(names.getArray(), i); - addEntry(entry); - } - } - - // root or intermediate node - if (tree->dictLookup("Kids", &kids)->isArray()) { - for (i = 0; i < kids.arrayGetLength(); ++i) { - if (kids.arrayGet(i, &kid)->isDict()) - parse(&kid); - kid.free(); - } - } - kids.free(); -} - -int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry) -{ - UGString *key = (UGString *) voidKey; - Entry *entry = *(NameTree::Entry **) voidEntry; - - return key->cmp(entry->name); -} - -GBool NameTree::lookup(UGString *name, Object *obj) -{ - Entry *entry; - - Entry **e = (Entry **) bsearch(name, entries, - length, sizeof(Entry *), Entry::cmp); - if (e) entry = *e; - else - { - error(-1, "failed to look up %s\n", name->getCString()); - obj->initNull(); - return gFalse; - } - if (entry != NULL) { - entry->value.fetch(xref, obj); - return gTrue; - } else { - error(-1, "failed to look up %s\n", name->getCString()); - - obj->initNull(); - - return gFalse; - } -} - -void NameTree::free() -{ - int i; - - for (i = 0; i < length; i++) - delete entries[i]; - - gfree(entries); -} diff --git a/xpdf/xpdf/Catalog.h b/xpdf/xpdf/Catalog.h deleted file mode 100644 index 700618d66..000000000 --- a/xpdf/xpdf/Catalog.h +++ /dev/null @@ -1,135 +0,0 @@ -//======================================================================== -// -// Catalog.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef CATALOG_H -#define CATALOG_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -class XRef; -class Object; -class Page; -class PageAttrs; -struct Ref; -class LinkDest; -class UGString; - -//------------------------------------------------------------------------ -// NameTree -//------------------------------------------------------------------------ - -class NameTree { -public: - NameTree(); - void init(XRef *xref, Object *tree); - void parse(Object *tree); - GBool lookup(UGString *name, Object *obj); - void free(); - -private: - struct Entry { - Entry(Array *array, int index); - ~Entry(); - UGString *name; - Object value; - void free(); - static int cmp(const void *key, const void *entry); - }; - - void addEntry(Entry *entry); - - XRef *xref; - Object *root; - Entry **entries; - int size, length; -}; - -//------------------------------------------------------------------------ -// Catalog -//------------------------------------------------------------------------ - -class Catalog { -public: - - enum PageMode { - UseNone, - UseOutlines, - UseThumbs, - FullScreen, - UseOC - }; - - // Constructor. - Catalog(XRef *xrefA); - - // Destructor. - ~Catalog(); - - // Is catalog valid? - GBool isOk() { return ok; } - - // Get number of pages. - int getNumPages() { return numPages; } - - // Get a page. - Page *getPage(int i) { return pages[i-1]; } - - // Get the reference for a page object. - Ref *getPageRef(int i) { return &pageRefs[i-1]; } - - // Return base URI, or NULL if none. - GString *getBaseURI() { return baseURI; } - - // Returns the page mode. - PageMode getPageMode() { return pageMode; } - - // Return the contents of the metadata stream, or NULL if there is - // no metadata. - GString *readMetadata(); - - // Return the structure tree root object. - Object *getStructTreeRoot() { return &structTreeRoot; } - - // Find a page, given its object ID. Returns page number, or 0 if - // not found. - int findPage(int num, int gen); - - // Find a named destination. Returns the link destination, or - // NULL if is not a destination. - LinkDest *findDest(UGString *name); - - Object *getOutline() { return &outline; } - - Object *getAcroForm() { return &acroForm; } - -private: - - XRef *xref; // the xref table for this PDF file - Page **pages; // array of pages - Ref *pageRefs; // object ID for each page - int numPages; // number of pages - int pagesSize; // size of pages array - Object dests; // named destination dictionary - NameTree destNameTree; // name tree - GString *baseURI; // base URI for URI-type links - PageMode pageMode; // page mode - Object metadata; // metadata stream - Object structTreeRoot; // structure tree root dictionary - Object outline; // outline dictionary - Object acroForm; // AcroForm dictionary - GBool ok; // true if catalog is valid - - int readPageTree(Dict *pages, PageAttrs *attrs, int start); - Object *findDestInTree(Object *tree, GString *name, Object *obj); -}; - -#endif diff --git a/xpdf/xpdf/CharCodeToUnicode.cc b/xpdf/xpdf/CharCodeToUnicode.cc deleted file mode 100644 index 650424891..000000000 --- a/xpdf/xpdf/CharCodeToUnicode.cc +++ /dev/null @@ -1,563 +0,0 @@ -//======================================================================== -// -// CharCodeToUnicode.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "gfile.h" -#include "GString.h" -#include "Error.h" -#include "GlobalParams.h" -#include "PSTokenizer.h" -#include "CharCodeToUnicode.h" - -//------------------------------------------------------------------------ - -#define maxUnicodeString 8 - -struct CharCodeToUnicodeString { - CharCode c; - Unicode u[maxUnicodeString]; - int len; -}; - -//------------------------------------------------------------------------ - -static int getCharFromString(void *data) { - char *p; - int c; - - p = *(char **)data; - if (*p) { - c = *p++; - *(char **)data = p; - } else { - c = EOF; - } - return c; -} - -static int CharCodeToUnicode_getCharFromFile(void *data) { - return fgetc((FILE *)data); -} - -//------------------------------------------------------------------------ - -CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName, - GString *collection) { - FILE *f; - Unicode *mapA; - CharCode size, mapLenA; - char buf[64]; - Unicode u; - CharCodeToUnicode *ctu; - - if (!(f = fopen(fileName->getCString(), "r"))) { - error(-1, "Couldn't open cidToUnicode file '%s'", - fileName->getCString()); - return NULL; - } - - size = 32768; - mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); - mapLenA = 0; - - while (getLine(buf, sizeof(buf), f)) { - if (mapLenA == size) { - size *= 2; - mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); - } - if (sscanf(buf, "%x", &u) == 1) { - mapA[mapLenA] = u; - } else { - error(-1, "Bad line (%d) in cidToUnicode file '%s'", - (int)(mapLenA + 1), fileName->getCString()); - mapA[mapLenA] = 0; - } - ++mapLenA; - } - fclose(f); - - ctu = new CharCodeToUnicode(collection->copy(), mapA, mapLenA, gTrue, - NULL, 0, 0); - gfree(mapA); - return ctu; -} - -CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( - GString *fileName) { - FILE *f; - Unicode *mapA; - CharCodeToUnicodeString *sMapA; - CharCode size, oldSize, len, sMapSizeA, sMapLenA; - char buf[256]; - char *tok; - Unicode u0; - Unicode uBuf[maxUnicodeString]; - CharCodeToUnicode *ctu; - int line, n, i; - - if (!(f = fopen(fileName->getCString(), "r"))) { - error(-1, "Couldn't open unicodeToUnicode file '%s'", - fileName->getCString()); - return NULL; - } - - size = 4096; - mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); - memset(mapA, 0, size * sizeof(Unicode)); - len = 0; - sMapA = NULL; - sMapSizeA = sMapLenA = 0; - - line = 0; - while (getLine(buf, sizeof(buf), f)) { - ++line; - if (!(tok = strtok(buf, " \t\r\n")) || - sscanf(tok, "%x", &u0) != 1) { - error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", - line, fileName->getCString()); - continue; - } - n = 0; - while (n < maxUnicodeString) { - if (!(tok = strtok(NULL, " \t\r\n"))) { - break; - } - if (sscanf(tok, "%x", &uBuf[n]) != 1) { - error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", - line, fileName->getCString()); - break; - } - ++n; - } - if (n < 1) { - error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", - line, fileName->getCString()); - continue; - } - if (u0 >= size) { - oldSize = size; - while (u0 >= size) { - size *= 2; - } - mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); - memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode)); - } - if (n == 1) { - mapA[u0] = uBuf[0]; - } else { - mapA[u0] = 0; - if (sMapLenA == sMapSizeA) { - sMapSizeA += 16; - sMapA = (CharCodeToUnicodeString *) - greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString)); - } - sMapA[sMapLenA].c = u0; - for (i = 0; i < n; ++i) { - sMapA[sMapLenA].u[i] = uBuf[i]; - } - sMapA[sMapLenA].len = n; - ++sMapLenA; - } - if (u0 >= len) { - len = u0 + 1; - } - } - fclose(f); - - ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue, - sMapA, sMapLenA, sMapSizeA); - gfree(mapA); - return ctu; -} - -CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) { - return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0); -} - -CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) { - CharCodeToUnicode *ctu; - char *p; - - ctu = new CharCodeToUnicode(NULL); - p = buf->getCString(); - ctu->parseCMap1(&getCharFromString, &p, nBits); - return ctu; -} - -void CharCodeToUnicode::mergeCMap(GString *buf, int nBits) { - char *p; - - p = buf->getCString(); - parseCMap1(&getCharFromString, &p, nBits); -} - -void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, - int nBits) { - PSTokenizer *pst; - char tok1[256], tok2[256], tok3[256]; - int nDigits, n1, n2, n3; - CharCode i; - CharCode code1, code2; - GString *name; - FILE *f; - - nDigits = nBits / 4; - pst = new PSTokenizer(getCharFunc, data); - pst->getToken(tok1, sizeof(tok1), &n1); - while (pst->getToken(tok2, sizeof(tok2), &n2)) { - if (!strcmp(tok2, "usecmap")) { - if (tok1[0] == '/') { - name = new GString(tok1 + 1); - if ((f = globalParams->findToUnicodeFile(name))) { - parseCMap1(&CharCodeToUnicode_getCharFromFile, f, nBits); - fclose(f); - } else { - error(-1, "Couldn't find ToUnicode CMap file for '%s'", - name->getCString()); - } - delete name; - } - pst->getToken(tok1, sizeof(tok1), &n1); - } else if (!strcmp(tok2, "beginbfchar")) { - while (pst->getToken(tok1, sizeof(tok1), &n1)) { - if (!strcmp(tok1, "endbfchar")) { - break; - } - if (!pst->getToken(tok2, sizeof(tok2), &n2) || - !strcmp(tok2, "endbfchar")) { - error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); - break; - } - if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && - tok2[0] == '<' && tok2[n2 - 1] == '>')) { - - // check there was no line jump inside the token and so the length is - // longer than it should be - int countAux = 0; - for (int k = 0; k < n1; k++) - if (tok1[k] != '\n' && tok1[k] != '\r') countAux++; - - if (!(countAux == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && - tok2[0] == '<' && tok2[n2 - 1] == '>')) { - error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); - continue; - } - } - tok1[n1 - 1] = tok2[n2 - 1] = '\0'; - if (sscanf(tok1 + 1, "%x", &code1) != 1) { - error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); - continue; - } - addMapping(code1, tok2 + 1, n2 - 2, 0); - } - pst->getToken(tok1, sizeof(tok1), &n1); - } else if (!strcmp(tok2, "beginbfrange")) { - while (pst->getToken(tok1, sizeof(tok1), &n1)) { - if (!strcmp(tok1, "endbfrange")) { - break; - } - if (!pst->getToken(tok2, sizeof(tok2), &n2) || - !strcmp(tok2, "endbfrange") || - !pst->getToken(tok3, sizeof(tok3), &n3) || - !strcmp(tok3, "endbfrange")) { - error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); - break; - } - if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && - n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) { - // check there was no line jump inside the token and so the length is - // longer than it should be - int countAux = 0; - for (int k = 0; k < n1; k++) - if (tok1[k] != '\n' && tok1[k] != '\r') countAux++; - - int countAux2 = 0; - for (int k = 0; k < n1; k++) - if (tok2[k] != '\n' && tok2[k] != '\r') countAux++; - - if (!(countAux == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && - countAux2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) { - error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); - continue; - } - } - tok1[n1 - 1] = tok2[n2 - 1] = '\0'; - if (sscanf(tok1 + 1, "%x", &code1) != 1 || - sscanf(tok2 + 1, "%x", &code2) != 1) { - error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); - continue; - } - if (!strcmp(tok3, "[")) { - i = 0; - while (pst->getToken(tok1, sizeof(tok1), &n1) && - code1 + i <= code2) { - if (!strcmp(tok1, "]")) { - break; - } - if (tok1[0] == '<' && tok1[n1 - 1] == '>') { - tok1[n1 - 1] = '\0'; - addMapping(code1 + i, tok1 + 1, n1 - 2, 0); - } else { - error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); - } - ++i; - } - } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') { - tok3[n3 - 1] = '\0'; - for (i = 0; code1 <= code2; ++code1, ++i) { - addMapping(code1, tok3 + 1, n3 - 2, i); - } - - } else { - error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); - } - } - pst->getToken(tok1, sizeof(tok1), &n1); - } else { - strcpy(tok1, tok2); - } - } - delete pst; -} - -void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n, - int offset) { - CharCode oldLen, i; - Unicode u; - char uHex[5]; - int j; - - if (code >= mapLen) { - oldLen = mapLen; - mapLen = (code + 256) & ~255; - map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode)); - for (i = oldLen; i < mapLen; ++i) { - map[i] = 0; - } - } - if (n <= 4) { - if (sscanf(uStr, "%x", &u) != 1) { - error(-1, "Illegal entry in ToUnicode CMap"); - return; - } - map[code] = u + offset; - } else { - if (sMapLen >= sMapSize) { - sMapSize = sMapSize + 16; - sMap = (CharCodeToUnicodeString *) - greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); - } - map[code] = 0; - sMap[sMapLen].c = code; - sMap[sMapLen].len = n / 4; - for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) { - strncpy(uHex, uStr + j*4, 4); - uHex[4] = '\0'; - if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) { - error(-1, "Illegal entry in ToUnicode CMap"); - } - } - sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset; - ++sMapLen; - } -} - -CharCodeToUnicode::CharCodeToUnicode(GString *tagA) { - CharCode i; - - tag = tagA; - mapLen = 256; - map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); - for (i = 0; i < mapLen; ++i) { - map[i] = 0; - } - sMap = NULL; - sMapLen = sMapSize = 0; - refCnt = 1; -#if MULTITHREADED - gInitMutex(&mutex); -#endif -} - -CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA, - CharCode mapLenA, GBool copyMap, - CharCodeToUnicodeString *sMapA, - int sMapLenA, int sMapSizeA) { - tag = tagA; - mapLen = mapLenA; - if (copyMap) { - map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); - memcpy(map, mapA, mapLen * sizeof(Unicode)); - } else { - map = mapA; - } - sMap = sMapA; - sMapLen = sMapLenA; - sMapSize = sMapSizeA; - refCnt = 1; -#if MULTITHREADED - gInitMutex(&mutex); -#endif -} - -CharCodeToUnicode::~CharCodeToUnicode() { - if (tag) { - delete tag; - } - gfree(map); - if (sMap) { - gfree(sMap); - } -#if MULTITHREADED - gDestroyMutex(&mutex); -#endif -} - -void CharCodeToUnicode::incRefCnt() { -#if MULTITHREADED - gLockMutex(&mutex); -#endif - ++refCnt; -#if MULTITHREADED - gUnlockMutex(&mutex); -#endif -} - -void CharCodeToUnicode::decRefCnt() { - GBool done; - -#if MULTITHREADED - gLockMutex(&mutex); -#endif - done = --refCnt == 0; -#if MULTITHREADED - gUnlockMutex(&mutex); -#endif - if (done) { - delete this; - } -} - -GBool CharCodeToUnicode::match(GString *tagA) { - return tag && !tag->cmp(tagA); -} - -void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) { - int i, j; - - if (len == 1) { - map[c] = u[0]; - } else { - for (i = 0; i < sMapLen; ++i) { - if (sMap[i].c == c) { - break; - } - } - if (i == sMapLen) { - if (sMapLen == sMapSize) { - sMapSize += 8; - sMap = (CharCodeToUnicodeString *) - greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); - } - ++sMapLen; - } - map[c] = 0; - sMap[i].c = c; - sMap[i].len = len; - for (j = 0; j < len && j < maxUnicodeString; ++j) { - sMap[i].u[j] = u[j]; - } - } -} - -int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) { - int i, j; - - if (c >= mapLen) { - return 0; - } - if (map[c]) { - u[0] = map[c]; - return 1; - } - for (i = 0; i < sMapLen; ++i) { - if (sMap[i].c == c) { - for (j = 0; j < sMap[i].len && j < size; ++j) { - u[j] = sMap[i].u[j]; - } - return j; - } - } - return 0; -} - -//------------------------------------------------------------------------ - -CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) { - int i; - - size = sizeA; - cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *)); - for (i = 0; i < size; ++i) { - cache[i] = NULL; - } -} - -CharCodeToUnicodeCache::~CharCodeToUnicodeCache() { - int i; - - for (i = 0; i < size; ++i) { - if (cache[i]) { - cache[i]->decRefCnt(); - } - } - gfree(cache); -} - -CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GString *tag) { - CharCodeToUnicode *ctu; - int i, j; - - if (cache[0] && cache[0]->match(tag)) { - cache[0]->incRefCnt(); - return cache[0]; - } - for (i = 1; i < size; ++i) { - if (cache[i] && cache[i]->match(tag)) { - ctu = cache[i]; - for (j = i; j >= 1; --j) { - cache[j] = cache[j - 1]; - } - cache[0] = ctu; - ctu->incRefCnt(); - return ctu; - } - } - return NULL; -} - -void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) { - int i; - - if (cache[size - 1]) { - cache[size - 1]->decRefCnt(); - } - for (i = size - 1; i >= 1; --i) { - cache[i] = cache[i - 1]; - } - cache[0] = ctu; - ctu->incRefCnt(); -} diff --git a/xpdf/xpdf/CharCodeToUnicode.h b/xpdf/xpdf/CharCodeToUnicode.h deleted file mode 100644 index 04852aea8..000000000 --- a/xpdf/xpdf/CharCodeToUnicode.h +++ /dev/null @@ -1,117 +0,0 @@ -//======================================================================== -// -// CharCodeToUnicode.h -// -// Mapping from character codes to Unicode. -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef CHARCODETOUNICODE_H -#define CHARCODETOUNICODE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "CharTypes.h" - -#if MULTITHREADED -#include "GMutex.h" -#endif - -struct CharCodeToUnicodeString; - -//------------------------------------------------------------------------ - -class CharCodeToUnicode { -public: - - // Read the CID-to-Unicode mapping for from the file - // specified by . Sets the initial reference count to 1. - // Returns NULL on failure. - static CharCodeToUnicode *parseCIDToUnicode(GString *fileName, - GString *collection); - - // Create a Unicode-to-Unicode mapping from the file specified by - // . Sets the initial reference count to 1. Returns NULL - // on failure. - static CharCodeToUnicode *parseUnicodeToUnicode(GString *fileName); - - // Create the CharCode-to-Unicode mapping for an 8-bit font. - // is an array of 256 Unicode indexes. Sets the initial - // reference count to 1. - static CharCodeToUnicode *make8BitToUnicode(Unicode *toUnicode); - - // Parse a ToUnicode CMap for an 8- or 16-bit font. - static CharCodeToUnicode *parseCMap(GString *buf, int nBits); - - // Parse a ToUnicode CMap for an 8- or 16-bit font, merging it into - // . - void mergeCMap(GString *buf, int nBits); - - ~CharCodeToUnicode(); - - void incRefCnt(); - void decRefCnt(); - - // Return true if this mapping matches the specified . - GBool match(GString *tagA); - - // Set the mapping for . - void setMapping(CharCode c, Unicode *u, int len); - - // Map a CharCode to Unicode. - int mapToUnicode(CharCode c, Unicode *u, int size); - - // Return the mapping's length, i.e., one more than the max char - // code supported by the mapping. - CharCode getLength() { return mapLen; } - -private: - - void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits); - void addMapping(CharCode code, char *uStr, int n, int offset); - CharCodeToUnicode(GString *tagA); - CharCodeToUnicode(GString *tagA, Unicode *mapA, - CharCode mapLenA, GBool copyMap, - CharCodeToUnicodeString *sMapA, - int sMapLenA, int sMapSizeA); - - GString *tag; - Unicode *map; - CharCode mapLen; - CharCodeToUnicodeString *sMap; - int sMapLen, sMapSize; - int refCnt; -#if MULTITHREADED - GMutex mutex; -#endif -}; - -//------------------------------------------------------------------------ - -class CharCodeToUnicodeCache { -public: - - CharCodeToUnicodeCache(int sizeA); - ~CharCodeToUnicodeCache(); - - // Get the CharCodeToUnicode object for . Increments its - // reference count; there will be one reference for the cache plus - // one for the caller of this function. Returns NULL on failure. - CharCodeToUnicode *getCharCodeToUnicode(GString *tag); - - // Insert into the cache, in the most-recently-used position. - void add(CharCodeToUnicode *ctu); - -private: - - CharCodeToUnicode **cache; - int size; -}; - -#endif diff --git a/xpdf/xpdf/CharTypes.h b/xpdf/xpdf/CharTypes.h deleted file mode 100644 index d0df630d0..000000000 --- a/xpdf/xpdf/CharTypes.h +++ /dev/null @@ -1,24 +0,0 @@ -//======================================================================== -// -// CharTypes.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef CHARTYPES_H -#define CHARTYPES_H - -// Unicode character. -typedef unsigned int Unicode; - -// Character ID for CID character collections. -typedef unsigned int CID; - -// This is large enough to hold any of the following: -// - 8-bit char code -// - 16-bit CID -// - Unicode -typedef unsigned int CharCode; - -#endif diff --git a/xpdf/xpdf/CompactFontTables.h b/xpdf/xpdf/CompactFontTables.h deleted file mode 100644 index 28e16e775..000000000 --- a/xpdf/xpdf/CompactFontTables.h +++ /dev/null @@ -1,464 +0,0 @@ -//======================================================================== -// -// CompactFontTables.h -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef COMPACTFONTINFO_H -#define COMPACTFONTINFO_H - -static char *type1CStdStrings[391] = { - ".notdef", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotesingle", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "endash", - "dagger", - "daggerdbl", - "periodcentered", - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - "questiondown", - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "emdash", - "AE", - "ordfeminine", - "Lslash", - "Oslash", - "OE", - "ordmasculine", - "ae", - "dotlessi", - "lslash", - "oslash", - "oe", - "germandbls", - "onesuperior", - "logicalnot", - "mu", - "trademark", - "Eth", - "onehalf", - "plusminus", - "Thorn", - "onequarter", - "divide", - "brokenbar", - "degree", - "thorn", - "threequarters", - "twosuperior", - "registered", - "minus", - "eth", - "multiply", - "threesuperior", - "copyright", - "Aacute", - "Acircumflex", - "Adieresis", - "Agrave", - "Aring", - "Atilde", - "Ccedilla", - "Eacute", - "Ecircumflex", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Ntilde", - "Oacute", - "Ocircumflex", - "Odieresis", - "Ograve", - "Otilde", - "Scaron", - "Uacute", - "Ucircumflex", - "Udieresis", - "Ugrave", - "Yacute", - "Ydieresis", - "Zcaron", - "aacute", - "acircumflex", - "adieresis", - "agrave", - "aring", - "atilde", - "ccedilla", - "eacute", - "ecircumflex", - "edieresis", - "egrave", - "iacute", - "icircumflex", - "idieresis", - "igrave", - "ntilde", - "oacute", - "ocircumflex", - "odieresis", - "ograve", - "otilde", - "scaron", - "uacute", - "ucircumflex", - "udieresis", - "ugrave", - "yacute", - "ydieresis", - "zcaron", - "exclamsmall", - "Hungarumlautsmall", - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "commasuperior", - "threequartersemdash", - "periodsuperior", - "questionsmall", - "asuperior", - "bsuperior", - "centsuperior", - "dsuperior", - "esuperior", - "isuperior", - "lsuperior", - "msuperior", - "nsuperior", - "osuperior", - "rsuperior", - "ssuperior", - "tsuperior", - "ff", - "ffi", - "ffl", - "parenleftinferior", - "parenrightinferior", - "Circumflexsmall", - "hyphensuperior", - "Gravesmall", - "Asmall", - "Bsmall", - "Csmall", - "Dsmall", - "Esmall", - "Fsmall", - "Gsmall", - "Hsmall", - "Ismall", - "Jsmall", - "Ksmall", - "Lsmall", - "Msmall", - "Nsmall", - "Osmall", - "Psmall", - "Qsmall", - "Rsmall", - "Ssmall", - "Tsmall", - "Usmall", - "Vsmall", - "Wsmall", - "Xsmall", - "Ysmall", - "Zsmall", - "colonmonetary", - "onefitted", - "rupiah", - "Tildesmall", - "exclamdownsmall", - "centoldstyle", - "Lslashsmall", - "Scaronsmall", - "Zcaronsmall", - "Dieresissmall", - "Brevesmall", - "Caronsmall", - "Dotaccentsmall", - "Macronsmall", - "figuredash", - "hypheninferior", - "Ogoneksmall", - "Ringsmall", - "Cedillasmall", - "questiondownsmall", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - "zerosuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "eightsuperior", - "ninesuperior", - "zeroinferior", - "oneinferior", - "twoinferior", - "threeinferior", - "fourinferior", - "fiveinferior", - "sixinferior", - "seveninferior", - "eightinferior", - "nineinferior", - "centinferior", - "dollarinferior", - "periodinferior", - "commainferior", - "Agravesmall", - "Aacutesmall", - "Acircumflexsmall", - "Atildesmall", - "Adieresissmall", - "Aringsmall", - "AEsmall", - "Ccedillasmall", - "Egravesmall", - "Eacutesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Igravesmall", - "Iacutesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ethsmall", - "Ntildesmall", - "Ogravesmall", - "Oacutesmall", - "Ocircumflexsmall", - "Otildesmall", - "Odieresissmall", - "OEsmall", - "Oslashsmall", - "Ugravesmall", - "Uacutesmall", - "Ucircumflexsmall", - "Udieresissmall", - "Yacutesmall", - "Thornsmall", - "Ydieresissmall", - "001.000", - "001.001", - "001.002", - "001.003", - "Black", - "Bold", - "Book", - "Light", - "Medium", - "Regular", - "Roman", - "Semibold" -}; - -static Gushort type1CISOAdobeCharset[229] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228 -}; - -static Gushort type1CExpertCharset[166] = { - 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, - 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, - 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, - 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, - 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, - 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378 -}; - -static Gushort type1CExpertSubsetCharset[87] = { - 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, - 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, - 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, - 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, - 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346 -}; - -#endif diff --git a/xpdf/xpdf/DCTStream.cc b/xpdf/xpdf/DCTStream.cc deleted file mode 100644 index f2e9dda0a..000000000 --- a/xpdf/xpdf/DCTStream.cc +++ /dev/null @@ -1,159 +0,0 @@ -//======================================================================== -// -// DCTStream.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include "DCTStream.h" - -static void str_init_source(j_decompress_ptr /*cinfo*/) -{ -} - -static boolean str_fill_input_buffer(j_decompress_ptr cinfo) -{ - int c; - struct str_src_mgr * src = (struct str_src_mgr *)cinfo->src; - if (src->index == 0) { - c = 0xFF; - src->index++; - } - else if (src->index == 1) { - c = 0xD8; - src->index++; - } - else c = src->str->getChar(); - if (c != EOF) - { - src->buffer = c; - src->pub.next_input_byte = &src->buffer; - src->pub.bytes_in_buffer = 1; - return TRUE; - } - else return FALSE; -} - -static void str_skip_input_data(j_decompress_ptr cinfo, long num_bytes) -{ - struct str_src_mgr * src = (struct str_src_mgr *)cinfo->src; - if (num_bytes > 0) { - while (num_bytes > (long) src->pub.bytes_in_buffer) { - num_bytes -= (long) src->pub.bytes_in_buffer; - str_fill_input_buffer(cinfo); - } - src->pub.next_input_byte += (size_t) num_bytes; - src->pub.bytes_in_buffer -= (size_t) num_bytes; - } -} - -static void str_term_source(j_decompress_ptr /*cinfo*/) -{ -} - -DCTStream::DCTStream(Stream *strA): - FilterStream(strA) { - - jpeg_create_decompress(&cinfo); - src.pub.init_source = str_init_source; - src.pub.fill_input_buffer = str_fill_input_buffer; - src.pub.skip_input_data = str_skip_input_data; - src.pub.resync_to_restart = jpeg_resync_to_restart; - src.pub.term_source = str_term_source; - src.pub.bytes_in_buffer = 0; - src.pub.next_input_byte = NULL; - src.str = str; - src.index = 0; - cinfo.src = (jpeg_source_mgr *)&src; - cinfo.err = jpeg_std_error(&jerr); - x = 0; -} - -DCTStream::~DCTStream() { - jpeg_destroy_decompress(&cinfo); - delete str; -} - -void DCTStream::reset() { - int row_stride; - - str->reset(); - - // JPEG data has to start with 0xFF 0xD8 - // but some pdf like the one on - // https://bugs.freedesktop.org/show_bug.cgi?id=3299 - // does have some garbage before that this seeks for - // the start marker... - bool startFound = false; - int c = 0, c2 = 0; - while (!startFound) - { - if (!c) - { - c = str->getChar(); - if (c == -1) - { - error(-1, "Could not find start of jpeg data"); - exit(1); - } - if (c != 0xFF) c = 0; - } - else - { - c2 = str->getChar(); - if (c2 != 0xD8) - { - c = 0; - c2 = 0; - } - else startFound = true; - } - } - - jpeg_read_header(&cinfo, TRUE); - jpeg_start_decompress(&cinfo); - - row_stride = cinfo.output_width * cinfo.output_components; - row_buffer = cinfo.mem->alloc_sarray((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); -} - -int DCTStream::getChar() { - int c; - - if (x == 0) { - if (cinfo.output_scanline < cinfo.output_height) - { - if (!jpeg_read_scanlines(&cinfo, row_buffer, 1)) return EOF; - } - else return EOF; - } - c = row_buffer[0][x]; - x++; - if (x == cinfo.output_width * cinfo.output_components) - x = 0; - return c; -} - -int DCTStream::lookChar() { - int c; - c = row_buffer[0][x]; - return c; -} - -GString *DCTStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("<< >> /DCTDecode filter\n"); - return s; -} - -GBool DCTStream::isBinary(GBool /*last*/) { - return str->isBinary(gTrue); -} diff --git a/xpdf/xpdf/DCTStream.h b/xpdf/xpdf/DCTStream.h deleted file mode 100644 index 885899d3b..000000000 --- a/xpdf/xpdf/DCTStream.h +++ /dev/null @@ -1,72 +0,0 @@ -//======================================================================== -// -// DCTStream.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef DCTSTREAM_H -#define DCTSTREAM_H -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#ifndef WIN32 -#include -#endif -#include -#include -#include "goo/gmem.h" -#include "goo/gfile.h" -#include "Error.h" -#include "Object.h" -#ifndef NO_DECRYPTION -#include "Decrypt.h" -#endif -#include "Stream.h" - -extern "C" { -#include -} - -struct str_src_mgr { - struct jpeg_source_mgr pub; - JOCTET buffer; - Stream *str; - int index; -}; - - -class DCTStream: public FilterStream { -public: - - DCTStream(Stream *strA); - virtual ~DCTStream(); - virtual StreamKind getKind() { return strDCT; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - Stream *getRawStream() { return str; } - -private: - unsigned int x; - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - struct str_src_mgr src; - JSAMPARRAY row_buffer; -}; - -#endif diff --git a/xpdf/xpdf/Decrypt.cc b/xpdf/xpdf/Decrypt.cc deleted file mode 100644 index cb53abd1f..000000000 --- a/xpdf/xpdf/Decrypt.cc +++ /dev/null @@ -1,411 +0,0 @@ -//======================================================================== -// -// Decrypt.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "Decrypt.h" - -static void rc4InitKey(Guchar *key, int keyLen, Guchar *state); -static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); -static void md5(Guchar *msg, int msgLen, Guchar *digest); - -static Guchar passwordPad[32] = { - 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, - 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, - 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, - 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a -}; - -//------------------------------------------------------------------------ -// Decrypt -//------------------------------------------------------------------------ - -Decrypt::Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen) { - int i; - - // construct object key - for (i = 0; i < keyLength; ++i) { - objKey[i] = fileKey[i]; - } - objKey[keyLength] = objNum & 0xff; - objKey[keyLength + 1] = (objNum >> 8) & 0xff; - objKey[keyLength + 2] = (objNum >> 16) & 0xff; - objKey[keyLength + 3] = objGen & 0xff; - objKey[keyLength + 4] = (objGen >> 8) & 0xff; - md5(objKey, keyLength + 5, objKey); - - // set up for decryption - x = y = 0; - if ((objKeyLength = keyLength + 5) > 16) { - objKeyLength = 16; - } - rc4InitKey(objKey, objKeyLength, state); -} - -void Decrypt::reset() { - x = y = 0; - rc4InitKey(objKey, objKeyLength, state); -} - -Guchar Decrypt::decryptByte(Guchar c) { - return rc4DecryptByte(state, &x, &y, c); -} - -GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, - GString *ownerKey, GString *userKey, - int permissions, GString *fileID, - GString *ownerPassword, GString *userPassword, - Guchar *fileKey, GBool encryptMetadata, - GBool *ownerPasswordOk) { - Guchar test[32], test2[32]; - GString *userPassword2; - Guchar fState[256]; - Guchar tmpKey[16]; - Guchar fx, fy; - int len, i, j; - - // try using the supplied owner password to generate the user password - *ownerPasswordOk = gFalse; - if (ownerPassword) { - len = ownerPassword->getLength(); - if (len < 32) { - memcpy(test, ownerPassword->getCString(), len); - memcpy(test + len, passwordPad, 32 - len); - } else { - memcpy(test, ownerPassword->getCString(), 32); - } - md5(test, 32, test); - if (encRevision == 3) { - for (i = 0; i < 50; ++i) { - md5(test, 16, test); - } - } - if (encRevision == 2) { - rc4InitKey(test, keyLength, fState); - fx = fy = 0; - for (i = 0; i < 32; ++i) { - test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i)); - } - } else { - memcpy(test2, ownerKey->getCString(), 32); - for (i = 19; i >= 0; --i) { - for (j = 0; j < keyLength; ++j) { - tmpKey[j] = test[j] ^ i; - } - rc4InitKey(tmpKey, keyLength, fState); - fx = fy = 0; - for (j = 0; j < 32; ++j) { - test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]); - } - } - } - userPassword2 = new GString((char *)test2, 32); - if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, - permissions, fileID, userPassword2, fileKey, - encryptMetadata)) { - *ownerPasswordOk = gTrue; - delete userPassword2; - return gTrue; - } - delete userPassword2; - } - - // try using the supplied user password - return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, - permissions, fileID, userPassword, fileKey, - encryptMetadata); -} - -GBool Decrypt::makeFileKey2(int /*encVersion*/, int encRevision, int keyLength, - GString *ownerKey, GString *userKey, - int permissions, GString *fileID, - GString *userPassword, Guchar *fileKey, - GBool encryptMetadata) { - Guchar *buf; - Guchar test[32]; - Guchar fState[256]; - Guchar tmpKey[16]; - Guchar fx, fy; - int len, i, j; - GBool ok; - - // generate file key - buf = (Guchar *)gmalloc(72 + fileID->getLength()); - if (userPassword) { - len = userPassword->getLength(); - if (len < 32) { - memcpy(buf, userPassword->getCString(), len); - memcpy(buf + len, passwordPad, 32 - len); - } else { - memcpy(buf, userPassword->getCString(), 32); - } - } else { - memcpy(buf, passwordPad, 32); - } - memcpy(buf + 32, ownerKey->getCString(), 32); - buf[64] = permissions & 0xff; - buf[65] = (permissions >> 8) & 0xff; - buf[66] = (permissions >> 16) & 0xff; - buf[67] = (permissions >> 24) & 0xff; - memcpy(buf + 68, fileID->getCString(), fileID->getLength()); - len = 68 + fileID->getLength(); - if (!encryptMetadata) { - buf[len++] = 0xff; - buf[len++] = 0xff; - buf[len++] = 0xff; - buf[len++] = 0xff; - } - md5(buf, len, fileKey); - if (encRevision == 3) { - for (i = 0; i < 50; ++i) { - md5(fileKey, keyLength, fileKey); - } - } - - // test user password - if (encRevision == 2) { - rc4InitKey(fileKey, keyLength, fState); - fx = fy = 0; - for (i = 0; i < 32; ++i) { - test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i)); - } - ok = memcmp(test, passwordPad, 32) == 0; - } else if (encRevision == 3) { - memcpy(test, userKey->getCString(), 32); - for (i = 19; i >= 0; --i) { - for (j = 0; j < keyLength; ++j) { - tmpKey[j] = fileKey[j] ^ i; - } - rc4InitKey(tmpKey, keyLength, fState); - fx = fy = 0; - for (j = 0; j < 32; ++j) { - test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]); - } - } - memcpy(buf, passwordPad, 32); - memcpy(buf + 32, fileID->getCString(), fileID->getLength()); - md5(buf, 32 + fileID->getLength(), buf); - ok = memcmp(test, buf, 16) == 0; - } else { - ok = gFalse; - } - - gfree(buf); - return ok; -} - -//------------------------------------------------------------------------ -// RC4-compatible decryption -//------------------------------------------------------------------------ - -static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) { - Guchar index1, index2; - Guchar t; - int i; - - for (i = 0; i < 256; ++i) - state[i] = i; - index1 = index2 = 0; - for (i = 0; i < 256; ++i) { - index2 = (key[index1] + state[i] + index2) % 256; - t = state[i]; - state[i] = state[index2]; - state[index2] = t; - index1 = (index1 + 1) % keyLen; - } -} - -static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) { - Guchar x1, y1, tx, ty; - - x1 = *x = (*x + 1) % 256; - y1 = *y = (state[*x] + *y) % 256; - tx = state[x1]; - ty = state[y1]; - state[x1] = ty; - state[y1] = tx; - return c ^ state[(tx + ty) % 256]; -} - -//------------------------------------------------------------------------ -// MD5 message digest -//------------------------------------------------------------------------ - -// this works around a bug in older Sun compilers -static inline Gulong rotateLeft(Gulong x, int r) { - x &= 0xffffffff; - return ((x << r) | (x >> (32 - r))) & 0xffffffff; -} - -static inline Gulong md5Round1(Gulong a, Gulong b, Gulong c, Gulong d, - Gulong Xk, Gulong s, Gulong Ti) { - return b + rotateLeft((a + ((b & c) | (~b & d)) + Xk + Ti), s); -} - -static inline Gulong md5Round2(Gulong a, Gulong b, Gulong c, Gulong d, - Gulong Xk, Gulong s, Gulong Ti) { - return b + rotateLeft((a + ((b & d) | (c & ~d)) + Xk + Ti), s); -} - -static inline Gulong md5Round3(Gulong a, Gulong b, Gulong c, Gulong d, - Gulong Xk, Gulong s, Gulong Ti) { - return b + rotateLeft((a + (b ^ c ^ d) + Xk + Ti), s); -} - -static inline Gulong md5Round4(Gulong a, Gulong b, Gulong c, Gulong d, - Gulong Xk, Gulong s, Gulong Ti) { - return b + rotateLeft((a + (c ^ (b | ~d)) + Xk + Ti), s); -} - -static void md5(Guchar *msg, int msgLen, Guchar *digest) { - Gulong x[16]; - Gulong a, b, c, d, aa, bb, cc, dd; - int n64; - int i, j, k; - - // compute number of 64-byte blocks - // (length + pad byte (0x80) + 8 bytes for length) - n64 = (msgLen + 1 + 8 + 63) / 64; - - // initialize a, b, c, d - a = 0x67452301; - b = 0xefcdab89; - c = 0x98badcfe; - d = 0x10325476; - - // loop through blocks - k = 0; - for (i = 0; i < n64; ++i) { - - // grab a 64-byte block - for (j = 0; j < 16 && k < msgLen - 3; ++j, k += 4) - x[j] = (((((msg[k+3] << 8) + msg[k+2]) << 8) + msg[k+1]) << 8) + msg[k]; - if (i == n64 - 1) { - if (k == msgLen - 3) - x[j] = 0x80000000 + (((msg[k+2] << 8) + msg[k+1]) << 8) + msg[k]; - else if (k == msgLen - 2) - x[j] = 0x800000 + (msg[k+1] << 8) + msg[k]; - else if (k == msgLen - 1) - x[j] = 0x8000 + msg[k]; - else - x[j] = 0x80; - ++j; - while (j < 16) - x[j++] = 0; - x[14] = msgLen << 3; - } - - // save a, b, c, d - aa = a; - bb = b; - cc = c; - dd = d; - - // round 1 - a = md5Round1(a, b, c, d, x[0], 7, 0xd76aa478); - d = md5Round1(d, a, b, c, x[1], 12, 0xe8c7b756); - c = md5Round1(c, d, a, b, x[2], 17, 0x242070db); - b = md5Round1(b, c, d, a, x[3], 22, 0xc1bdceee); - a = md5Round1(a, b, c, d, x[4], 7, 0xf57c0faf); - d = md5Round1(d, a, b, c, x[5], 12, 0x4787c62a); - c = md5Round1(c, d, a, b, x[6], 17, 0xa8304613); - b = md5Round1(b, c, d, a, x[7], 22, 0xfd469501); - a = md5Round1(a, b, c, d, x[8], 7, 0x698098d8); - d = md5Round1(d, a, b, c, x[9], 12, 0x8b44f7af); - c = md5Round1(c, d, a, b, x[10], 17, 0xffff5bb1); - b = md5Round1(b, c, d, a, x[11], 22, 0x895cd7be); - a = md5Round1(a, b, c, d, x[12], 7, 0x6b901122); - d = md5Round1(d, a, b, c, x[13], 12, 0xfd987193); - c = md5Round1(c, d, a, b, x[14], 17, 0xa679438e); - b = md5Round1(b, c, d, a, x[15], 22, 0x49b40821); - - // round 2 - a = md5Round2(a, b, c, d, x[1], 5, 0xf61e2562); - d = md5Round2(d, a, b, c, x[6], 9, 0xc040b340); - c = md5Round2(c, d, a, b, x[11], 14, 0x265e5a51); - b = md5Round2(b, c, d, a, x[0], 20, 0xe9b6c7aa); - a = md5Round2(a, b, c, d, x[5], 5, 0xd62f105d); - d = md5Round2(d, a, b, c, x[10], 9, 0x02441453); - c = md5Round2(c, d, a, b, x[15], 14, 0xd8a1e681); - b = md5Round2(b, c, d, a, x[4], 20, 0xe7d3fbc8); - a = md5Round2(a, b, c, d, x[9], 5, 0x21e1cde6); - d = md5Round2(d, a, b, c, x[14], 9, 0xc33707d6); - c = md5Round2(c, d, a, b, x[3], 14, 0xf4d50d87); - b = md5Round2(b, c, d, a, x[8], 20, 0x455a14ed); - a = md5Round2(a, b, c, d, x[13], 5, 0xa9e3e905); - d = md5Round2(d, a, b, c, x[2], 9, 0xfcefa3f8); - c = md5Round2(c, d, a, b, x[7], 14, 0x676f02d9); - b = md5Round2(b, c, d, a, x[12], 20, 0x8d2a4c8a); - - // round 3 - a = md5Round3(a, b, c, d, x[5], 4, 0xfffa3942); - d = md5Round3(d, a, b, c, x[8], 11, 0x8771f681); - c = md5Round3(c, d, a, b, x[11], 16, 0x6d9d6122); - b = md5Round3(b, c, d, a, x[14], 23, 0xfde5380c); - a = md5Round3(a, b, c, d, x[1], 4, 0xa4beea44); - d = md5Round3(d, a, b, c, x[4], 11, 0x4bdecfa9); - c = md5Round3(c, d, a, b, x[7], 16, 0xf6bb4b60); - b = md5Round3(b, c, d, a, x[10], 23, 0xbebfbc70); - a = md5Round3(a, b, c, d, x[13], 4, 0x289b7ec6); - d = md5Round3(d, a, b, c, x[0], 11, 0xeaa127fa); - c = md5Round3(c, d, a, b, x[3], 16, 0xd4ef3085); - b = md5Round3(b, c, d, a, x[6], 23, 0x04881d05); - a = md5Round3(a, b, c, d, x[9], 4, 0xd9d4d039); - d = md5Round3(d, a, b, c, x[12], 11, 0xe6db99e5); - c = md5Round3(c, d, a, b, x[15], 16, 0x1fa27cf8); - b = md5Round3(b, c, d, a, x[2], 23, 0xc4ac5665); - - // round 4 - a = md5Round4(a, b, c, d, x[0], 6, 0xf4292244); - d = md5Round4(d, a, b, c, x[7], 10, 0x432aff97); - c = md5Round4(c, d, a, b, x[14], 15, 0xab9423a7); - b = md5Round4(b, c, d, a, x[5], 21, 0xfc93a039); - a = md5Round4(a, b, c, d, x[12], 6, 0x655b59c3); - d = md5Round4(d, a, b, c, x[3], 10, 0x8f0ccc92); - c = md5Round4(c, d, a, b, x[10], 15, 0xffeff47d); - b = md5Round4(b, c, d, a, x[1], 21, 0x85845dd1); - a = md5Round4(a, b, c, d, x[8], 6, 0x6fa87e4f); - d = md5Round4(d, a, b, c, x[15], 10, 0xfe2ce6e0); - c = md5Round4(c, d, a, b, x[6], 15, 0xa3014314); - b = md5Round4(b, c, d, a, x[13], 21, 0x4e0811a1); - a = md5Round4(a, b, c, d, x[4], 6, 0xf7537e82); - d = md5Round4(d, a, b, c, x[11], 10, 0xbd3af235); - c = md5Round4(c, d, a, b, x[2], 15, 0x2ad7d2bb); - b = md5Round4(b, c, d, a, x[9], 21, 0xeb86d391); - - // increment a, b, c, d - a += aa; - b += bb; - c += cc; - d += dd; - } - - // break digest into bytes - digest[0] = (Guchar)(a & 0xff); - digest[1] = (Guchar)((a >>= 8) & 0xff); - digest[2] = (Guchar)((a >>= 8) & 0xff); - digest[3] = (Guchar)((a >>= 8) & 0xff); - digest[4] = (Guchar)(b & 0xff); - digest[5] = (Guchar)((b >>= 8) & 0xff); - digest[6] = (Guchar)((b >>= 8) & 0xff); - digest[7] = (Guchar)((b >>= 8) & 0xff); - digest[8] = (Guchar)(c & 0xff); - digest[9] = (Guchar)((c >>= 8) & 0xff); - digest[10] = (Guchar)((c >>= 8) & 0xff); - digest[11] = (Guchar)((c >>= 8) & 0xff); - digest[12] = (Guchar)(d & 0xff); - digest[13] = (Guchar)((d >>= 8) & 0xff); - digest[14] = (Guchar)((d >>= 8) & 0xff); - digest[15] = (Guchar)((d >>= 8) & 0xff); -} diff --git a/xpdf/xpdf/Decrypt.h b/xpdf/xpdf/Decrypt.h deleted file mode 100644 index 2beba5815..000000000 --- a/xpdf/xpdf/Decrypt.h +++ /dev/null @@ -1,63 +0,0 @@ -//======================================================================== -// -// Decrypt.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef DECRYPT_H -#define DECRYPT_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "GString.h" - -//------------------------------------------------------------------------ -// Decrypt -//------------------------------------------------------------------------ - -class Decrypt { -public: - - // Initialize the decryptor object. - Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen); - - // Reset decryption. - void reset(); - - // Decrypt one byte. - Guchar decryptByte(Guchar c); - - // Generate a file key. The buffer must have space for at - // least 16 bytes. Checks and then - // and returns true if either is correct. Sets if - // the owner password was correct. Either or both of the passwords - // may be NULL, which is treated as an empty string. - static GBool makeFileKey(int encVersion, int encRevision, int keyLength, - GString *ownerKey, GString *userKey, - int permissions, GString *fileID, - GString *ownerPassword, GString *userPassword, - Guchar *fileKey, GBool encryptMetadata, - GBool *ownerPasswordOk); - -private: - - static GBool makeFileKey2(int encVersion, int encRevision, int keyLength, - GString *ownerKey, GString *userKey, - int permissions, GString *fileID, - GString *userPassword, Guchar *fileKey, - GBool encryptMetadata); - - int objKeyLength; - Guchar objKey[21]; - Guchar state[256]; - Guchar x, y; -}; - -#endif diff --git a/xpdf/xpdf/Dict.cc b/xpdf/xpdf/Dict.cc deleted file mode 100644 index 1edb3a4b4..000000000 --- a/xpdf/xpdf/Dict.cc +++ /dev/null @@ -1,96 +0,0 @@ -//======================================================================== -// -// Dict.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "Object.h" -#include "XRef.h" -#include "Dict.h" -#include "UGString.h" - -//------------------------------------------------------------------------ -// Dict -//------------------------------------------------------------------------ - -Dict::Dict(XRef *xrefA) { - xref = xrefA; - entries = NULL; - size = length = 0; - ref = 1; -} - -Dict::~Dict() { - int i; - - for (i = 0; i < length; ++i) { - delete entries[i].key; - entries[i].val.free(); - } - gfree(entries); -} - -void Dict::add(const UGString &key, Object *val) { - if (length == size) { - if (length == 0) { - size = 8; - } else { - size *= 2; - } - entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry)); - } - entries[length].key = new UGString(key); - entries[length].val = *val; - ++length; -} - -inline DictEntry *Dict::find(const UGString &key) { - int i; - - for (i = 0; i < length; ++i) { - if (!key.cmp(entries[i].key)) - return &entries[i]; - } - return NULL; -} - -GBool Dict::is(const char *type) { - DictEntry *e; - - return (e = find("Type")) && e->val.isName(type); -} - -Object *Dict::lookup(const UGString &key, Object *obj) { - DictEntry *e; - - return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull(); -} - -Object *Dict::lookupNF(const UGString &key, Object *obj) { - DictEntry *e; - - return (e = find(key)) ? e->val.copy(obj) : obj->initNull(); -} - -UGString *Dict::getKey(int i) { - return entries[i].key; -} - -Object *Dict::getVal(int i, Object *obj) { - return entries[i].val.fetch(xref, obj); -} - -Object *Dict::getValNF(int i, Object *obj) { - return entries[i].val.copy(obj); -} diff --git a/xpdf/xpdf/Dict.h b/xpdf/xpdf/Dict.h deleted file mode 100644 index 22b49b1f9..000000000 --- a/xpdf/xpdf/Dict.h +++ /dev/null @@ -1,79 +0,0 @@ -//======================================================================== -// -// Dict.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef DICT_H -#define DICT_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" - -class UGString; - -//------------------------------------------------------------------------ -// Dict -//------------------------------------------------------------------------ - -struct DictEntry { - UGString *key; - Object val; -}; - -class Dict { -public: - - // Constructor. - Dict(XRef *xrefA); - - // Destructor. - ~Dict(); - - // Reference counting. - int incRef() { return ++ref; } - int decRef() { return --ref; } - - // Get number of entries. - int getLength() { return length; } - - // Add an entry. - void add(const UGString &key, Object *val); - - // Check if dictionary is of specified type. - GBool is(const char *type); - - // Look up an entry and return the value. Returns a null object - // if is not in the dictionary. - Object *lookup(const UGString &key, Object *obj); - Object *lookupNF(const UGString &key, Object *obj); - - // Iterative accessors. - UGString *getKey(int i); - Object *getVal(int i, Object *obj); - Object *getValNF(int i, Object *obj); - - // Set the xref pointer. This is only used in one special case: the - // trailer dictionary, which is read before the xref table is - // parsed. - void setXRef(XRef *xrefA) { xref = xrefA; } - -private: - - XRef *xref; // the xref table for this PDF file - DictEntry *entries; // array of entries - int size; // size of array - int length; // number of entries in dictionary - int ref; // reference count - - DictEntry *find(const UGString &key); -}; - -#endif diff --git a/xpdf/xpdf/Error.h b/xpdf/xpdf/Error.h deleted file mode 100644 index fd886dc93..000000000 --- a/xpdf/xpdf/Error.h +++ /dev/null @@ -1,23 +0,0 @@ -//======================================================================== -// -// Error.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef ERROR_H -#define ERROR_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include "xpdf_config.h" - -extern void CDECL error(int pos, const char *msg, ...); - -#endif diff --git a/xpdf/xpdf/ErrorCodes.h b/xpdf/xpdf/ErrorCodes.h deleted file mode 100644 index b28528df5..000000000 --- a/xpdf/xpdf/ErrorCodes.h +++ /dev/null @@ -1,36 +0,0 @@ -//======================================================================== -// -// ErrorCodes.h -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef ERRORCODES_H -#define ERRORCODES_H - -#define errNone 0 // no error - -#define errOpenFile 1 // couldn't open the PDF file - -#define errBadCatalog 2 // couldn't read the page catalog - -#define errDamaged 3 // PDF file was damaged and couldn't be - // repaired - -#define errEncrypted 4 // file was encrypted and password was - // incorrect or not supplied - -#define errHighlightFile 5 // nonexistent or invalid highlight file - -#define errBadPrinter 6 // invalid printer - -#define errPrinting 7 // error during printing - -#define errPermission 8 // PDF file doesn't allow that operation - -#define errBadPageNum 9 // invalid page number - -#define errFileIO 10 // file I/O error - -#endif diff --git a/xpdf/xpdf/FlateStream.cc b/xpdf/xpdf/FlateStream.cc deleted file mode 100644 index 0e6b06e9b..000000000 --- a/xpdf/xpdf/FlateStream.cc +++ /dev/null @@ -1,107 +0,0 @@ -//======================================================================== -// -// FlateStream.cc -// -// Copyright (C) 2005, Jeff Muizelaar -// -//======================================================================== -#include "FlateStream.h" -FlateStream::FlateStream(Stream *strA, int predictor, int columns, int colors, int bits) : - FilterStream(strA) -{ - if (predictor != 1) { - pred = new StreamPredictor(this, predictor, columns, colors, bits); - } else { - pred = NULL; - } - out_pos = 0; - memset(&d_stream, 0, sizeof(d_stream)); -} - -FlateStream::~FlateStream() { - inflateEnd(&d_stream); - delete str; -} - -void FlateStream::reset() { - //FIXME: what are the semantics of reset? - //i.e. how much intialization has to happen in the constructor? - str->reset(); - memset(&d_stream, 0, sizeof(d_stream)); - inflateInit(&d_stream); - d_stream.avail_in = 0; - status = Z_OK; - out_pos = 0; - out_buf_len = 0; -} - -int FlateStream::getRawChar() { - if (fill_buffer()) - return EOF; - - return out_buf[out_pos++]; -} - -int FlateStream::getChar() { - if (pred) - return pred->getChar(); - else - return getRawChar(); -} - -int FlateStream::lookChar() { - if (pred) - return pred->lookChar(); - - if (fill_buffer()) - return EOF; - - return out_buf[out_pos]; -} - -int FlateStream::fill_buffer() { - if (out_pos >= out_buf_len) { - if (status == Z_STREAM_END) { - return -1; - } - d_stream.avail_out = sizeof(out_buf); - d_stream.next_out = out_buf; - out_pos = 0; - /* buffer is empty so we need to fill it */ - if (d_stream.avail_in == 0) { - int c; - /* read from the source stream */ - while (d_stream.avail_in < sizeof(in_buf) && (c = str->getChar()) != EOF) { - in_buf[d_stream.avail_in++] = c; - } - d_stream.next_in = in_buf; - } - while (d_stream.avail_out && d_stream.avail_in && (status == Z_OK || status == Z_BUF_ERROR)) { - status = inflate(&d_stream, Z_SYNC_FLUSH); - } - out_buf_len = sizeof(out_buf) - d_stream.avail_out; - if (status != Z_OK && status != Z_STREAM_END) - return -1; - if (!out_buf_len) - return -1; - } - - return 0; -} - -GString *FlateStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 3 || pred) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("<< >> /FlateDecode filter\n"); - return s; -} - -GBool FlateStream::isBinary(GBool /*last*/) { - return str->isBinary(gTrue); -} diff --git a/xpdf/xpdf/FlateStream.h b/xpdf/xpdf/FlateStream.h deleted file mode 100644 index 357f5714e..000000000 --- a/xpdf/xpdf/FlateStream.h +++ /dev/null @@ -1,67 +0,0 @@ -//======================================================================== -// -// FlateStream.h -// -// Copyright (C) 2005, Jeff Muizelaar -// -//======================================================================== - -#ifndef FLATESTREAM_H -#define FLATESTREAM_H -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#ifndef WIN32 -#include -#endif -#include -#include -#include "goo/gmem.h" -#include "goo/gfile.h" -#include "Error.h" -#include "Object.h" -#ifndef NO_DECRYPTION -#include "Decrypt.h" -#endif -#include "Stream.h" - -extern "C" { -#include -} - -class FlateStream: public FilterStream { -public: - - FlateStream(Stream *strA, int predictor, int columns, int colors, int bits); - virtual ~FlateStream(); - virtual StreamKind getKind() { return strFlate; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual int getRawChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - int fill_buffer(void); - z_stream d_stream; - StreamPredictor *pred; - int status; - unsigned char in_buf[4096]; - unsigned char out_buf[4096]; - int out_pos; - int out_buf_len; -}; - -#endif diff --git a/xpdf/xpdf/FontEncodingTables.cc b/xpdf/xpdf/FontEncodingTables.cc deleted file mode 100644 index bf04b5b19..000000000 --- a/xpdf/xpdf/FontEncodingTables.cc +++ /dev/null @@ -1,1824 +0,0 @@ -//======================================================================== -// -// FontEncodingTables.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include -#include -#include "FontEncodingTables.h" - -const char *macRomanEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quotesingle", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "grave", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - NULL, - "Adieresis", - "Aring", - "Ccedilla", - "Eacute", - "Ntilde", - "Odieresis", - "Udieresis", - "aacute", - "agrave", - "acircumflex", - "adieresis", - "atilde", - "aring", - "ccedilla", - "eacute", - "egrave", - "ecircumflex", - "edieresis", - "iacute", - "igrave", - "icircumflex", - "idieresis", - "ntilde", - "oacute", - "ograve", - "ocircumflex", - "odieresis", - "otilde", - "uacute", - "ugrave", - "ucircumflex", - "udieresis", - "dagger", - "degree", - "cent", - "sterling", - "section", - "bullet", - "paragraph", - "germandbls", - "registered", - "copyright", - "trademark", - "acute", - "dieresis", - "notequal", - "AE", - "Oslash", - "infinity", - "plusminus", - "lessequal", - "greaterequal", - "yen", - "mu", - "partialdiff", - "summation", - "product", - "pi", - "integral", - "ordfeminine", - "ordmasculine", - "Omega", - "ae", - "oslash", - "questiondown", - "exclamdown", - "logicalnot", - "radical", - "florin", - "approxequal", - "Delta", - "guillemotleft", - "guillemotright", - "ellipsis", - "space", - "Agrave", - "Atilde", - "Otilde", - "OE", - "oe", - "endash", - "emdash", - "quotedblleft", - "quotedblright", - "quoteleft", - "quoteright", - "divide", - "lozenge", - "ydieresis", - "Ydieresis", - "fraction", - "currency", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "daggerdbl", - "periodcentered", - "quotesinglbase", - "quotedblbase", - "perthousand", - "Acircumflex", - "Ecircumflex", - "Aacute", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Oacute", - "Ocircumflex", - "apple", - "Ograve", - "Uacute", - "Ucircumflex", - "Ugrave", - "dotlessi", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron" -}; - -const char *macExpertEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclamsmall", - "Hungarumlautsmall", - "centoldstyle", - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "comma", - "hyphen", - "period", - "fraction", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "colon", - "semicolon", - NULL, - "threequartersemdash", - NULL, - "questionsmall", - NULL, - NULL, - NULL, - NULL, - "Ethsmall", - NULL, - NULL, - "onequarter", - "onehalf", - "threequarters", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "ff", - "fi", - "fl", - "ffi", - "ffl", - "parenleftinferior", - NULL, - "parenrightinferior", - "Circumflexsmall", - "hypheninferior", - "Gravesmall", - "Asmall", - "Bsmall", - "Csmall", - "Dsmall", - "Esmall", - "Fsmall", - "Gsmall", - "Hsmall", - "Ismall", - "Jsmall", - "Ksmall", - "Lsmall", - "Msmall", - "Nsmall", - "Osmall", - "Psmall", - "Qsmall", - "Rsmall", - "Ssmall", - "Tsmall", - "Usmall", - "Vsmall", - "Wsmall", - "Xsmall", - "Ysmall", - "Zsmall", - "colonmonetary", - "onefitted", - "rupiah", - "Tildesmall", - NULL, - NULL, - "asuperior", - "centsuperior", - NULL, - NULL, - NULL, - NULL, - "Aacutesmall", - "Agravesmall", - "Acircumflexsmall", - "Adieresissmall", - "Atildesmall", - "Aringsmall", - "Ccedillasmall", - "Eacutesmall", - "Egravesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Iacutesmall", - "Igravesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ntildesmall", - "Oacutesmall", - "Ogravesmall", - "Ocircumflexsmall", - "Odieresissmall", - "Otildesmall", - "Uacutesmall", - "Ugravesmall", - "Ucircumflexsmall", - "Udieresissmall", - NULL, - "eightsuperior", - "fourinferior", - "threeinferior", - "sixinferior", - "eightinferior", - "seveninferior", - "Scaronsmall", - NULL, - "centinferior", - "twoinferior", - NULL, - "Dieresissmall", - NULL, - "Caronsmall", - "osuperior", - "fiveinferior", - NULL, - "commainferior", - "periodinferior", - "Yacutesmall", - NULL, - "dollarinferior", - NULL, - NULL, - "Thornsmall", - NULL, - "nineinferior", - "zeroinferior", - "Zcaronsmall", - "AEsmall", - "Oslashsmall", - "questiondownsmall", - "oneinferior", - "Lslashsmall", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "Cedillasmall", - NULL, - NULL, - NULL, - NULL, - NULL, - "OEsmall", - "figuredash", - "hyphensuperior", - NULL, - NULL, - NULL, - NULL, - "exclamdownsmall", - NULL, - "Ydieresissmall", - NULL, - "onesuperior", - "twosuperior", - "threesuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "ninesuperior", - "zerosuperior", - NULL, - "esuperior", - "rsuperior", - "tsuperior", - NULL, - NULL, - "isuperior", - "ssuperior", - "dsuperior", - NULL, - NULL, - NULL, - NULL, - NULL, - "lsuperior", - "Ogoneksmall", - "Brevesmall", - "Macronsmall", - "bsuperior", - "nsuperior", - "msuperior", - "commasuperior", - "periodsuperior", - "Dotaccentsmall", - "Ringsmall", - NULL, - NULL, - NULL, - NULL -}; - -const char *winAnsiEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quotesingle", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "grave", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "bullet", - "Euro", - "bullet", - "quotesinglbase", - "florin", - "quotedblbase", - "ellipsis", - "dagger", - "daggerdbl", - "circumflex", - "perthousand", - "Scaron", - "guilsinglleft", - "OE", - "bullet", - "Zcaron", - "bullet", - "bullet", - "quoteleft", - "quoteright", - "quotedblleft", - "quotedblright", - "bullet", - "endash", - "emdash", - "tilde", - "trademark", - "scaron", - "guilsinglright", - "oe", - "bullet", - "zcaron", - "Ydieresis", - "space", - "exclamdown", - "cent", - "sterling", - "currency", - "yen", - "brokenbar", - "section", - "dieresis", - "copyright", - "ordfeminine", - "guillemotleft", - "logicalnot", - "hyphen", - "registered", - "macron", - "degree", - "plusminus", - "twosuperior", - "threesuperior", - "acute", - "mu", - "paragraph", - "periodcentered", - "cedilla", - "onesuperior", - "ordmasculine", - "guillemotright", - "onequarter", - "onehalf", - "threequarters", - "questiondown", - "Agrave", - "Aacute", - "Acircumflex", - "Atilde", - "Adieresis", - "Aring", - "AE", - "Ccedilla", - "Egrave", - "Eacute", - "Ecircumflex", - "Edieresis", - "Igrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Eth", - "Ntilde", - "Ograve", - "Oacute", - "Ocircumflex", - "Otilde", - "Odieresis", - "multiply", - "Oslash", - "Ugrave", - "Uacute", - "Ucircumflex", - "Udieresis", - "Yacute", - "Thorn", - "germandbls", - "agrave", - "aacute", - "acircumflex", - "atilde", - "adieresis", - "aring", - "ae", - "ccedilla", - "egrave", - "eacute", - "ecircumflex", - "edieresis", - "igrave", - "iacute", - "icircumflex", - "idieresis", - "eth", - "ntilde", - "ograve", - "oacute", - "ocircumflex", - "otilde", - "odieresis", - "divide", - "oslash", - "ugrave", - "uacute", - "ucircumflex", - "udieresis", - "yacute", - "thorn", - "ydieresis" -}; - -const char *standardEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotesingle", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - NULL, - "endash", - "dagger", - "daggerdbl", - "periodcentered", - NULL, - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - NULL, - "questiondown", - NULL, - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - NULL, - "ring", - "cedilla", - NULL, - "hungarumlaut", - "ogonek", - "caron", - "emdash", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "AE", - NULL, - "ordfeminine", - NULL, - NULL, - NULL, - NULL, - "Lslash", - "Oslash", - "OE", - "ordmasculine", - NULL, - NULL, - NULL, - NULL, - NULL, - "ae", - NULL, - NULL, - NULL, - "dotlessi", - NULL, - NULL, - "lslash", - "oslash", - "oe", - "germandbls", - NULL, - NULL, - NULL, - NULL -}; - -const char *expertEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclamsmall", - "Hungarumlautsmall", - NULL, - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "comma", - "hyphen", - "period", - "fraction", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "colon", - "semicolon", - "commasuperior", - "threequartersemdash", - "periodsuperior", - "questionsmall", - NULL, - "asuperior", - "bsuperior", - "centsuperior", - "dsuperior", - "esuperior", - NULL, - NULL, - NULL, - "isuperior", - NULL, - NULL, - "lsuperior", - "msuperior", - "nsuperior", - "osuperior", - NULL, - NULL, - "rsuperior", - "ssuperior", - "tsuperior", - NULL, - "ff", - "fi", - "fl", - "ffi", - "ffl", - "parenleftinferior", - NULL, - "parenrightinferior", - "Circumflexsmall", - "hyphensuperior", - "Gravesmall", - "Asmall", - "Bsmall", - "Csmall", - "Dsmall", - "Esmall", - "Fsmall", - "Gsmall", - "Hsmall", - "Ismall", - "Jsmall", - "Ksmall", - "Lsmall", - "Msmall", - "Nsmall", - "Osmall", - "Psmall", - "Qsmall", - "Rsmall", - "Ssmall", - "Tsmall", - "Usmall", - "Vsmall", - "Wsmall", - "Xsmall", - "Ysmall", - "Zsmall", - "colonmonetary", - "onefitted", - "rupiah", - "Tildesmall", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "exclamdownsmall", - "centoldstyle", - "Lslashsmall", - NULL, - NULL, - "Scaronsmall", - "Zcaronsmall", - "Dieresissmall", - "Brevesmall", - "Caronsmall", - NULL, - "Dotaccentsmall", - NULL, - NULL, - "Macronsmall", - NULL, - NULL, - "figuredash", - "hypheninferior", - NULL, - NULL, - "Ogoneksmall", - "Ringsmall", - "Cedillasmall", - NULL, - NULL, - NULL, - "onequarter", - "onehalf", - "threequarters", - "questiondownsmall", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - NULL, - NULL, - "zerosuperior", - "onesuperior", - "twosuperior", - "threesuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "eightsuperior", - "ninesuperior", - "zeroinferior", - "oneinferior", - "twoinferior", - "threeinferior", - "fourinferior", - "fiveinferior", - "sixinferior", - "seveninferior", - "eightinferior", - "nineinferior", - "centinferior", - "dollarinferior", - "periodinferior", - "commainferior", - "Agravesmall", - "Aacutesmall", - "Acircumflexsmall", - "Atildesmall", - "Adieresissmall", - "Aringsmall", - "AEsmall", - "Ccedillasmall", - "Egravesmall", - "Eacutesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Igravesmall", - "Iacutesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ethsmall", - "Ntildesmall", - "Ogravesmall", - "Oacutesmall", - "Ocircumflexsmall", - "Otildesmall", - "Odieresissmall", - "OEsmall", - "Oslashsmall", - "Ugravesmall", - "Uacutesmall", - "Ucircumflexsmall", - "Udieresissmall", - "Yacutesmall", - "Thornsmall", - "Ydieresissmall" -}; - -const char *symbolEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclam", - "universal", - "numbersign", - "existential", - "percent", - "ampersand", - "suchthat", - "parenleft", - "parenright", - "asteriskmath", - "plus", - "comma", - "minus", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "congruent", - "Alpha", - "Beta", - "Chi", - "Delta", - "Epsilon", - "Phi", - "Gamma", - "Eta", - "Iota", - "theta1", - "Kappa", - "Lambda", - "Mu", - "Nu", - "Omicron", - "Pi", - "Theta", - "Rho", - "Sigma", - "Tau", - "Upsilon", - "sigma1", - "Omega", - "Xi", - "Psi", - "Zeta", - "bracketleft", - "therefore", - "bracketright", - "perpendicular", - "underscore", - "radicalex", - "alpha", - "beta", - "chi", - "delta", - "epsilon", - "phi", - "gamma", - "eta", - "iota", - "phi1", - "kappa", - "lambda", - "mu", - "nu", - "omicron", - "pi", - "theta", - "rho", - "sigma", - "tau", - "upsilon", - "omega1", - "omega", - "xi", - "psi", - "zeta", - "braceleft", - "bar", - "braceright", - "similar", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "Upsilon1", - "minute", - "lessequal", - "fraction", - "infinity", - "florin", - "club", - "diamond", - "heart", - "spade", - "arrowboth", - "arrowleft", - "arrowup", - "arrowright", - "arrowdown", - "degree", - "plusminus", - "second", - "greaterequal", - "multiply", - "proportional", - "partialdiff", - "bullet", - "divide", - "notequal", - "equivalence", - "approxequal", - "ellipsis", - "arrowvertex", - "arrowhorizex", - "carriagereturn", - "aleph", - "Ifraktur", - "Rfraktur", - "weierstrass", - "circlemultiply", - "circleplus", - "emptyset", - "intersection", - "union", - "propersuperset", - "reflexsuperset", - "notsubset", - "propersubset", - "reflexsubset", - "element", - "notelement", - "angle", - "gradient", - "registerserif", - "copyrightserif", - "trademarkserif", - "product", - "radical", - "dotmath", - "logicalnot", - "logicaland", - "logicalor", - "arrowdblboth", - "arrowdblleft", - "arrowdblup", - "arrowdblright", - "arrowdbldown", - "lozenge", - "angleleft", - "registersans", - "copyrightsans", - "trademarksans", - "summation", - "parenlefttp", - "parenleftex", - "parenleftbt", - "bracketlefttp", - "bracketleftex", - "bracketleftbt", - "bracelefttp", - "braceleftmid", - "braceleftbt", - "braceex", - NULL, - "angleright", - "integral", - "integraltp", - "integralex", - "integralbt", - "parenrighttp", - "parenrightex", - "parenrightbt", - "bracketrighttp", - "bracketrightex", - "bracketrightbt", - "bracerighttp", - "bracerightmid", - "bracerightbt", - NULL -}; - -const char *zapfDingbatsEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "a1", - "a2", - "a202", - "a3", - "a4", - "a5", - "a119", - "a118", - "a117", - "a11", - "a12", - "a13", - "a14", - "a15", - "a16", - "a105", - "a17", - "a18", - "a19", - "a20", - "a21", - "a22", - "a23", - "a24", - "a25", - "a26", - "a27", - "a28", - "a6", - "a7", - "a8", - "a9", - "a10", - "a29", - "a30", - "a31", - "a32", - "a33", - "a34", - "a35", - "a36", - "a37", - "a38", - "a39", - "a40", - "a41", - "a42", - "a43", - "a44", - "a45", - "a46", - "a47", - "a48", - "a49", - "a50", - "a51", - "a52", - "a53", - "a54", - "a55", - "a56", - "a57", - "a58", - "a59", - "a60", - "a61", - "a62", - "a63", - "a64", - "a65", - "a66", - "a67", - "a68", - "a69", - "a70", - "a71", - "a72", - "a73", - "a74", - "a203", - "a75", - "a204", - "a76", - "a77", - "a78", - "a79", - "a81", - "a82", - "a83", - "a84", - "a97", - "a98", - "a99", - "a100", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "a101", - "a102", - "a103", - "a104", - "a106", - "a107", - "a108", - "a112", - "a111", - "a110", - "a109", - "a120", - "a121", - "a122", - "a123", - "a124", - "a125", - "a126", - "a127", - "a128", - "a129", - "a130", - "a131", - "a132", - "a133", - "a134", - "a135", - "a136", - "a137", - "a138", - "a139", - "a140", - "a141", - "a142", - "a143", - "a144", - "a145", - "a146", - "a147", - "a148", - "a149", - "a150", - "a151", - "a152", - "a153", - "a154", - "a155", - "a156", - "a157", - "a158", - "a159", - "a160", - "a161", - "a163", - "a164", - "a196", - "a165", - "a192", - "a166", - "a167", - "a168", - "a169", - "a170", - "a171", - "a172", - "a173", - "a162", - "a174", - "a175", - "a176", - "a177", - "a178", - "a179", - "a193", - "a180", - "a199", - "a181", - "a200", - "a182", - NULL, - "a201", - "a183", - "a184", - "a197", - "a185", - "a194", - "a198", - "a186", - "a195", - "a187", - "a188", - "a189", - "a190", - "a191", - NULL -}; diff --git a/xpdf/xpdf/FontEncodingTables.h b/xpdf/xpdf/FontEncodingTables.h deleted file mode 100644 index a417b324e..000000000 --- a/xpdf/xpdf/FontEncodingTables.h +++ /dev/null @@ -1,20 +0,0 @@ -//======================================================================== -// -// FontEncodingTables.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef FONTENCODINGTABLES_H -#define FONTENCODINGTABLES_H - -extern const char *macRomanEncoding[]; -extern const char *macExpertEncoding[]; -extern const char *winAnsiEncoding[]; -extern const char *standardEncoding[]; -extern const char *expertEncoding[]; -extern const char *symbolEncoding[]; -extern const char *zapfDingbatsEncoding[]; - -#endif diff --git a/xpdf/xpdf/Function.cc b/xpdf/xpdf/Function.cc deleted file mode 100644 index 4b66ee918..000000000 --- a/xpdf/xpdf/Function.cc +++ /dev/null @@ -1,1536 +0,0 @@ -//======================================================================== -// -// Function.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include "gmem.h" -#include "Object.h" -#include "Dict.h" -#include "Stream.h" -#include "Error.h" -#include "Function.h" -#include "UGString.h" - -//------------------------------------------------------------------------ -// Function -//------------------------------------------------------------------------ - -Function::Function() { -} - -Function::~Function() { -} - -Function *Function::parse(Object *funcObj) { - Function *func; - Dict *dict; - int funcType; - Object obj1; - - if (funcObj->isStream()) { - dict = funcObj->streamGetDict(); - } else if (funcObj->isDict()) { - dict = funcObj->getDict(); - } else if (funcObj->isName("Identity")) { - return new IdentityFunction(); - } else { - error(-1, "Expected function dictionary or stream"); - return NULL; - } - - if (!dict->lookup("FunctionType", &obj1)->isInt()) { - error(-1, "Function type is missing or wrong type"); - obj1.free(); - return NULL; - } - funcType = obj1.getInt(); - obj1.free(); - - if (funcType == 0) { - func = new SampledFunction(funcObj, dict); - } else if (funcType == 2) { - func = new ExponentialFunction(funcObj, dict); - } else if (funcType == 3) { - func = new StitchingFunction(funcObj, dict); - } else if (funcType == 4) { - func = new PostScriptFunction(funcObj, dict); - } else { - error(-1, "Unimplemented function type (%d)", funcType); - return NULL; - } - if (!func->isOk()) { - delete func; - return NULL; - } - - return func; -} - -GBool Function::init(Dict *dict) { - Object obj1, obj2; - int i; - - //----- Domain - if (!dict->lookup("Domain", &obj1)->isArray()) { - error(-1, "Function is missing domain"); - goto err2; - } - m = obj1.arrayGetLength() / 2; - if (m > funcMaxInputs) { - error(-1, "Functions with more than %d inputs are unsupported", - funcMaxInputs); - goto err2; - } - for (i = 0; i < m; ++i) { - obj1.arrayGet(2*i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function domain array"); - goto err1; - } - domain[i][0] = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2*i+1, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function domain array"); - goto err1; - } - domain[i][1] = obj2.getNum(); - obj2.free(); - } - obj1.free(); - - //----- Range - hasRange = gFalse; - n = 0; - if (dict->lookup("Range", &obj1)->isArray()) { - hasRange = gTrue; - n = obj1.arrayGetLength() / 2; - if (n > funcMaxOutputs) { - error(-1, "Functions with more than %d outputs are unsupported", - funcMaxOutputs); - goto err2; - } - for (i = 0; i < n; ++i) { - obj1.arrayGet(2*i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function range array"); - goto err1; - } - range[i][0] = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2*i+1, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function range array"); - goto err1; - } - range[i][1] = obj2.getNum(); - obj2.free(); - } - } - obj1.free(); - - return gTrue; - - err1: - obj2.free(); - err2: - obj1.free(); - return gFalse; -} - -//------------------------------------------------------------------------ -// IdentityFunction -//------------------------------------------------------------------------ - -IdentityFunction::IdentityFunction() { - int i; - - // fill these in with arbitrary values just in case they get used - // somewhere - m = funcMaxInputs; - n = funcMaxOutputs; - for (i = 0; i < funcMaxInputs; ++i) { - domain[i][0] = 0; - domain[i][1] = 1; - } - hasRange = gFalse; -} - -IdentityFunction::~IdentityFunction() { -} - -void IdentityFunction::transform(double *in, double *out) { - int i; - - for (i = 0; i < funcMaxOutputs; ++i) { - out[i] = in[i]; - } -} - -//------------------------------------------------------------------------ -// SampledFunction -//------------------------------------------------------------------------ - -SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { - Stream *str; - int sampleBits; - double sampleMul; - Object obj1, obj2; - Guint buf, bitMask; - int bits; - int s; - int i; - - samples = NULL; - ok = gFalse; - - //----- initialize the generic stuff - if (!init(dict)) { - goto err1; - } - if (!hasRange) { - error(-1, "Type 0 function is missing range"); - goto err1; - } - - //----- get the stream - if (!funcObj->isStream()) { - error(-1, "Type 0 function isn't a stream"); - goto err1; - } - str = funcObj->getStream(); - - //----- Size - if (!dict->lookup("Size", &obj1)->isArray() || - obj1.arrayGetLength() != m) { - error(-1, "Function has missing or invalid size array"); - goto err2; - } - for (i = 0; i < m; ++i) { - obj1.arrayGet(i, &obj2); - if (!obj2.isInt()) { - error(-1, "Illegal value in function size array"); - goto err3; - } - sampleSize[i] = obj2.getInt(); - obj2.free(); - } - obj1.free(); - idxMul[0] = n; - for (i = 1; i < m; ++i) { - idxMul[i] = idxMul[i-1] * sampleSize[i-1]; - } - - //----- BitsPerSample - if (!dict->lookup("BitsPerSample", &obj1)->isInt()) { - error(-1, "Function has missing or invalid BitsPerSample"); - goto err2; - } - sampleBits = obj1.getInt(); - sampleMul = 1.0 / (double)((1 << sampleBits) - 1); - obj1.free(); - - //----- Encode - if (dict->lookup("Encode", &obj1)->isArray() && - obj1.arrayGetLength() == 2*m) { - for (i = 0; i < m; ++i) { - obj1.arrayGet(2*i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function encode array"); - goto err3; - } - encode[i][0] = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2*i+1, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function encode array"); - goto err3; - } - encode[i][1] = obj2.getNum(); - obj2.free(); - } - } else { - for (i = 0; i < m; ++i) { - encode[i][0] = 0; - encode[i][1] = sampleSize[i] - 1; - } - } - obj1.free(); - for (i = 0; i < m; ++i) { - inputMul[i] = (encode[i][1] - encode[i][0]) / - (domain[i][1] - domain[i][0]); - } - - //----- Decode - if (dict->lookup("Decode", &obj1)->isArray() && - obj1.arrayGetLength() == 2*n) { - for (i = 0; i < n; ++i) { - obj1.arrayGet(2*i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function decode array"); - goto err3; - } - decode[i][0] = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2*i+1, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function decode array"); - goto err3; - } - decode[i][1] = obj2.getNum(); - obj2.free(); - } - } else { - for (i = 0; i < n; ++i) { - decode[i][0] = range[i][0]; - decode[i][1] = range[i][1]; - } - } - obj1.free(); - - //----- samples - nSamples = n; - for (i = 0; i < m; ++i) - nSamples *= sampleSize[i]; - samples = (double *)gmallocn(nSamples, sizeof(double)); - buf = 0; - bits = 0; - bitMask = (1 << sampleBits) - 1; - str->reset(); - for (i = 0; i < nSamples; ++i) { - if (sampleBits == 8) { - s = str->getChar(); - } else if (sampleBits == 16) { - s = str->getChar(); - s = (s << 8) + str->getChar(); - } else if (sampleBits == 32) { - s = str->getChar(); - s = (s << 8) + str->getChar(); - s = (s << 8) + str->getChar(); - s = (s << 8) + str->getChar(); - } else { - while (bits < sampleBits) { - buf = (buf << 8) | (str->getChar() & 0xff); - bits += 8; - } - s = (buf >> (bits - sampleBits)) & bitMask; - bits -= sampleBits; - } - samples[i] = (double)s * sampleMul; - } - str->close(); - - ok = gTrue; - return; - - err3: - obj2.free(); - err2: - obj1.free(); - err1: - return; -} - -SampledFunction::~SampledFunction() { - if (samples) { - gfree(samples); - } -} - -SampledFunction::SampledFunction(SampledFunction *func) { - memcpy(this, func, sizeof(SampledFunction)); - samples = (double *)gmallocn(nSamples, sizeof(double)); - memcpy(samples, func->samples, nSamples * sizeof(double)); -} - -void SampledFunction::transform(double *in, double *out) { - double x; - int e[funcMaxInputs][2]; - double efrac0[funcMaxInputs]; - double efrac1[funcMaxInputs]; - double s[1 << funcMaxInputs]; - int i, j, k, idx, t; - - // map input values into sample array - for (i = 0; i < m; ++i) { - x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0]; - if (x < 0) { - x = 0; - } else if (x > sampleSize[i] - 1) { - x = sampleSize[i] - 1; - } - e[i][0] = (int)x; - if ((e[i][1] = e[i][0] + 1) >= sampleSize[i]) { - // this happens if in[i] = domain[i][1] - e[i][1] = e[i][0]; - } - efrac1[i] = x - e[i][0]; - efrac0[i] = 1 - efrac1[i]; - } - - // for each output, do m-linear interpolation - for (i = 0; i < n; ++i) { - - // pull 2^m values out of the sample array - for (j = 0; j < (1<>= 1) { - idx += idxMul[k] * (e[k][t & 1]); - } - s[j] = samples[idx]; - } - - // do m sets of interpolations - for (j = 0, t = (1<>= 1) { - for (k = 0; k < t; k += 2) { - s[k >> 1] = efrac0[j] * s[k] + efrac1[j] * s[k+1]; - } - } - - // map output value to range - out[i] = s[0] * (decode[i][1] - decode[i][0]) + decode[i][0]; - if (out[i] < range[i][0]) { - out[i] = range[i][0]; - } else if (out[i] > range[i][1]) { - out[i] = range[i][1]; - } - } -} - -//------------------------------------------------------------------------ -// ExponentialFunction -//------------------------------------------------------------------------ - -ExponentialFunction::ExponentialFunction(Object * /*funcObj*/, Dict *dict) { - Object obj1, obj2; - int i; - - ok = gFalse; - - //----- initialize the generic stuff - if (!init(dict)) { - goto err1; - } - if (m != 1) { - error(-1, "Exponential function with more than one input"); - goto err1; - } - - //----- C0 - if (dict->lookup("C0", &obj1)->isArray()) { - if (hasRange && obj1.arrayGetLength() != n) { - error(-1, "Function's C0 array is wrong length"); - goto err2; - } - n = obj1.arrayGetLength(); - for (i = 0; i < n; ++i) { - obj1.arrayGet(i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function C0 array"); - goto err3; - } - c0[i] = obj2.getNum(); - obj2.free(); - } - } else { - if (hasRange && n != 1) { - error(-1, "Function's C0 array is wrong length"); - goto err2; - } - n = 1; - c0[0] = 0; - } - obj1.free(); - - //----- C1 - if (dict->lookup("C1", &obj1)->isArray()) { - if (obj1.arrayGetLength() != n) { - error(-1, "Function's C1 array is wrong length"); - goto err2; - } - for (i = 0; i < n; ++i) { - obj1.arrayGet(i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function C1 array"); - goto err3; - } - c1[i] = obj2.getNum(); - obj2.free(); - } - } else { - if (n != 1) { - error(-1, "Function's C1 array is wrong length"); - goto err2; - } - c1[0] = 1; - } - obj1.free(); - - //----- N (exponent) - if (!dict->lookup("N", &obj1)->isNum()) { - error(-1, "Function has missing or invalid N"); - goto err2; - } - e = obj1.getNum(); - obj1.free(); - - ok = gTrue; - return; - - err3: - obj2.free(); - err2: - obj1.free(); - err1: - return; -} - -ExponentialFunction::~ExponentialFunction() { -} - -ExponentialFunction::ExponentialFunction(ExponentialFunction *func) { - memcpy(this, func, sizeof(ExponentialFunction)); -} - -void ExponentialFunction::transform(double *in, double *out) { - double x; - int i; - - if (in[0] < domain[0][0]) { - x = domain[0][0]; - } else if (in[0] > domain[0][1]) { - x = domain[0][1]; - } else { - x = in[0]; - } - for (i = 0; i < n; ++i) { - out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]); - if (hasRange) { - if (out[i] < range[i][0]) { - out[i] = range[i][0]; - } else if (out[i] > range[i][1]) { - out[i] = range[i][1]; - } - } - } - return; -} - -//------------------------------------------------------------------------ -// StitchingFunction -//------------------------------------------------------------------------ - -StitchingFunction::StitchingFunction(Object * /*funcObj*/, Dict *dict) { - Object obj1, obj2; - int i; - - ok = gFalse; - funcs = NULL; - bounds = NULL; - encode = NULL; - - //----- initialize the generic stuff - if (!init(dict)) { - goto err1; - } - if (m != 1) { - error(-1, "Stitching function with more than one input"); - goto err1; - } - - //----- Functions - if (!dict->lookup("Functions", &obj1)->isArray()) { - error(-1, "Missing 'Functions' entry in stitching function"); - goto err1; - } - k = obj1.arrayGetLength(); - funcs = (Function **)gmallocn(k, sizeof(Function *)); - bounds = (double *)gmallocn(k + 1, sizeof(double)); - encode = (double *)gmallocn(2 * k, sizeof(double)); - for (i = 0; i < k; ++i) { - funcs[i] = NULL; - } - for (i = 0; i < k; ++i) { - if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) { - goto err2; - } - if (i > 0 && (funcs[i]->getInputSize() != 1 || - funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) { - error(-1, "Incompatible subfunctions in stitching function"); - goto err2; - } - obj2.free(); - } - obj1.free(); - - //----- Bounds - if (!dict->lookup("Bounds", &obj1)->isArray() || - obj1.arrayGetLength() != k - 1) { - error(-1, "Missing or invalid 'Bounds' entry in stitching function"); - goto err1; - } - bounds[0] = domain[0][0]; - for (i = 1; i < k; ++i) { - if (!obj1.arrayGet(i - 1, &obj2)->isNum()) { - error(-1, "Invalid type in 'Bounds' array in stitching function"); - goto err2; - } - bounds[i] = obj2.getNum(); - obj2.free(); - } - bounds[k] = domain[0][1]; - obj1.free(); - - //----- Encode - if (!dict->lookup("Encode", &obj1)->isArray() || - obj1.arrayGetLength() != 2 * k) { - error(-1, "Missing or invalid 'Encode' entry in stitching function"); - goto err1; - } - for (i = 0; i < 2 * k; ++i) { - if (!obj1.arrayGet(i, &obj2)->isNum()) { - error(-1, "Invalid type in 'Encode' array in stitching function"); - goto err2; - } - encode[i] = obj2.getNum(); - obj2.free(); - } - obj1.free(); - - ok = gTrue; - return; - - err2: - obj2.free(); - err1: - obj1.free(); -} - -StitchingFunction::StitchingFunction(StitchingFunction *func) { - int i; - - k = func->k; - funcs = (Function **)gmallocn(k, sizeof(Function *)); - for (i = 0; i < k; ++i) { - funcs[i] = func->funcs[i]->copy(); - } - bounds = (double *)gmallocn(k + 1, sizeof(double)); - memcpy(bounds, func->bounds, (k + 1) * sizeof(double)); - encode = (double *)gmallocn(2 * k, sizeof(double)); - memcpy(encode, func->encode, 2 * k * sizeof(double)); - ok = gTrue; -} - -StitchingFunction::~StitchingFunction() { - int i; - - if (funcs) { - for (i = 0; i < k; ++i) { - if (funcs[i]) { - delete funcs[i]; - } - } - } - gfree(funcs); - gfree(bounds); - gfree(encode); -} - -void StitchingFunction::transform(double *in, double *out) { - double x; - int i; - - if (in[0] < domain[0][0]) { - x = domain[0][0]; - } else if (in[0] > domain[0][1]) { - x = domain[0][1]; - } else { - x = in[0]; - } - for (i = 0; i < k - 1; ++i) { - if (x < bounds[i+1]) { - break; - } - } - x = encode[2*i] + ((x - bounds[i]) / (bounds[i+1] - bounds[i])) * - (encode[2*i+1] - encode[2*i]); - funcs[i]->transform(&x, out); -} - -//------------------------------------------------------------------------ -// PostScriptFunction -//------------------------------------------------------------------------ - -enum PSOp { - psOpAbs, - psOpAdd, - psOpAnd, - psOpAtan, - psOpBitshift, - psOpCeiling, - psOpCopy, - psOpCos, - psOpCvi, - psOpCvr, - psOpDiv, - psOpDup, - psOpEq, - psOpExch, - psOpExp, - psOpFalse, - psOpFloor, - psOpGe, - psOpGt, - psOpIdiv, - psOpIndex, - psOpLe, - psOpLn, - psOpLog, - psOpLt, - psOpMod, - psOpMul, - psOpNe, - psOpNeg, - psOpNot, - psOpOr, - psOpPop, - psOpRoll, - psOpRound, - psOpSin, - psOpSqrt, - psOpSub, - psOpTrue, - psOpTruncate, - psOpXor, - psOpIf, - psOpIfelse, - psOpReturn -}; - -// Note: 'if' and 'ifelse' are parsed separately. -// The rest are listed here in alphabetical order. -// The index in this table is equivalent to the entry in PSOp. -const char *psOpNames[] = { - "abs", - "add", - "and", - "atan", - "bitshift", - "ceiling", - "copy", - "cos", - "cvi", - "cvr", - "div", - "dup", - "eq", - "exch", - "exp", - "false", - "floor", - "ge", - "gt", - "idiv", - "index", - "le", - "ln", - "log", - "lt", - "mod", - "mul", - "ne", - "neg", - "not", - "or", - "pop", - "roll", - "round", - "sin", - "sqrt", - "sub", - "true", - "truncate", - "xor" -}; - -#define nPSOps (sizeof(psOpNames) / sizeof(char *)) - -enum PSObjectType { - psBool, - psInt, - psReal, - psOperator, - psBlock -}; - -// In the code array, 'if'/'ifelse' operators take up three slots -// plus space for the code in the subclause(s). -// -// +---------------------------------+ -// | psOperator: psOpIf / psOpIfelse | -// +---------------------------------+ -// | psBlock: ptr= | -// +---------------------------------+ -// | psBlock: ptr= | -// +---------------------------------+ -// | if clause | -// | ... | -// | psOperator: psOpReturn | -// +---------------------------------+ -// | else clause | -// | ... | -// | psOperator: psOpReturn | -// +---------------------------------+ -// | ... | -// -// For 'if', pointer is present in the code stream but unused. - -struct PSObject { - PSObjectType type; - union { - GBool booln; // boolean (stack only) - int intg; // integer (stack and code) - double real; // real (stack and code) - PSOp op; // operator (code only) - int blk; // if/ifelse block pointer (code only) - }; -}; - -#define psStackSize 100 - -class PSStack { -public: - - PSStack() { sp = psStackSize; } - void pushBool(GBool booln); - void pushInt(int intg); - void pushReal(double real); - GBool popBool(); - int popInt(); - double popNum(); - GBool empty() { return sp == psStackSize; } - GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; } - GBool topTwoAreInts() - { return sp < psStackSize - 1 && - stack[sp].type == psInt && - stack[sp+1].type == psInt; } - GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; } - GBool topTwoAreNums() - { return sp < psStackSize - 1 && - (stack[sp].type == psInt || stack[sp].type == psReal) && - (stack[sp+1].type == psInt || stack[sp+1].type == psReal); } - void copy(int n); - void roll(int n, int j); - void index(int i); - void pop(); - -private: - - GBool checkOverflow(int n = 1); - GBool checkUnderflow(); - GBool checkType(PSObjectType t1, PSObjectType t2); - - PSObject stack[psStackSize]; - int sp; -}; - -GBool PSStack::checkOverflow(int n) { - if (sp - n < 0) { - error(-1, "Stack overflow in PostScript function"); - return gFalse; - } - return gTrue; -} - -GBool PSStack::checkUnderflow() { - if (sp == psStackSize) { - error(-1, "Stack underflow in PostScript function"); - return gFalse; - } - return gTrue; -} - -GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) { - if (stack[sp].type != t1 && stack[sp].type != t2) { - error(-1, "Type mismatch in PostScript function"); - return gFalse; - } - return gTrue; -} - -void PSStack::pushBool(GBool booln) { - if (checkOverflow()) { - stack[--sp].type = psBool; - stack[sp].booln = booln; - } -} - -void PSStack::pushInt(int intg) { - if (checkOverflow()) { - stack[--sp].type = psInt; - stack[sp].intg = intg; - } -} - -void PSStack::pushReal(double real) { - if (checkOverflow()) { - stack[--sp].type = psReal; - stack[sp].real = real; - } -} - -GBool PSStack::popBool() { - if (checkUnderflow() && checkType(psBool, psBool)) { - return stack[sp++].booln; - } - return gFalse; -} - -int PSStack::popInt() { - if (checkUnderflow() && checkType(psInt, psInt)) { - return stack[sp++].intg; - } - return 0; -} - -double PSStack::popNum() { - double ret; - - if (checkUnderflow() && checkType(psInt, psReal)) { - ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real; - ++sp; - return ret; - } - return 0; -} - -void PSStack::copy(int n) { - int i; - - if (sp + n > psStackSize) { - error(-1, "Stack underflow in PostScript function"); - return; - } - if (!checkOverflow(n)) { - return; - } - for (i = sp + n - 1; i >= sp; --i) { - stack[i - n] = stack[i]; - } - sp -= n; -} - -void PSStack::roll(int n, int j) { - PSObject obj; - int i, k; - - if (j >= 0) { - j %= n; - } else { - j = -j % n; - if (j != 0) { - j = n - j; - } - } - if (n <= 0 || j == 0) { - return; - } - for (i = 0; i < j; ++i) { - obj = stack[sp]; - for (k = sp; k < sp + n - 1; ++k) { - stack[k] = stack[k+1]; - } - stack[sp + n - 1] = obj; - } -} - -void PSStack::index(int i) { - if (!checkOverflow()) { - return; - } - --sp; - stack[sp] = stack[sp + 1 + i]; -} - -void PSStack::pop() { - if (!checkUnderflow()) { - return; - } - ++sp; -} - -PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) { - Stream *str; - int codePtr; - GString *tok; - - code = NULL; - codeSize = 0; - ok = gFalse; - - //----- initialize the generic stuff - if (!init(dict)) { - goto err1; - } - if (!hasRange) { - error(-1, "Type 4 function is missing range"); - goto err1; - } - - //----- get the stream - if (!funcObj->isStream()) { - error(-1, "Type 4 function isn't a stream"); - goto err1; - } - str = funcObj->getStream(); - - //----- parse the function - codeString = new GString(); - str->reset(); - if (!(tok = getToken(str)) || tok->cmp("{")) { - error(-1, "Expected '{' at start of PostScript function"); - if (tok) { - delete tok; - } - goto err1; - } - delete tok; - codePtr = 0; - if (!parseCode(str, &codePtr)) { - goto err2; - } - str->close(); - - ok = gTrue; - - err2: - str->close(); - err1: - return; -} - -PostScriptFunction::PostScriptFunction(PostScriptFunction *func) { - memcpy(this, func, sizeof(PostScriptFunction)); - code = (PSObject *)gmallocn(codeSize, sizeof(PSObject)); - memcpy(code, func->code, codeSize * sizeof(PSObject)); - codeString = func->codeString->copy(); -} - -PostScriptFunction::~PostScriptFunction() { - gfree(code); - delete codeString; -} - -void PostScriptFunction::transform(double *in, double *out) { - PSStack *stack; - int i; - - stack = new PSStack(); - for (i = 0; i < m; ++i) { - //~ may need to check for integers here - stack->pushReal(in[i]); - } - exec(stack, 0); - for (i = n - 1; i >= 0; --i) { - out[i] = stack->popNum(); - if (out[i] < range[i][0]) { - out[i] = range[i][0]; - } else if (out[i] > range[i][1]) { - out[i] = range[i][1]; - } - } - // if (!stack->empty()) { - // error(-1, "Extra values on stack at end of PostScript function"); - // } - delete stack; -} - -GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) { - GString *tok; - char *p; - GBool isReal; - int opPtr, elsePtr; - int a, b, mid, cmp; - - while (1) { - if (!(tok = getToken(str))) { - error(-1, "Unexpected end of PostScript function stream"); - return gFalse; - } - p = tok->getCString(); - if (isdigit(*p) || *p == '.' || *p == '-') { - isReal = gFalse; - for (++p; *p; ++p) { - if (*p == '.') { - isReal = gTrue; - break; - } - } - resizeCode(*codePtr); - if (isReal) { - code[*codePtr].type = psReal; - code[*codePtr].real = atof(tok->getCString()); - } else { - code[*codePtr].type = psInt; - code[*codePtr].intg = atoi(tok->getCString()); - } - ++*codePtr; - delete tok; - } else if (!tok->cmp("{")) { - delete tok; - opPtr = *codePtr; - *codePtr += 3; - resizeCode(opPtr + 2); - if (!parseCode(str, codePtr)) { - return gFalse; - } - if (!(tok = getToken(str))) { - error(-1, "Unexpected end of PostScript function stream"); - return gFalse; - } - if (!tok->cmp("{")) { - elsePtr = *codePtr; - if (!parseCode(str, codePtr)) { - return gFalse; - } - delete tok; - if (!(tok = getToken(str))) { - error(-1, "Unexpected end of PostScript function stream"); - return gFalse; - } - } else { - elsePtr = -1; - } - if (!tok->cmp("if")) { - if (elsePtr >= 0) { - error(-1, "Got 'if' operator with two blocks in PostScript function"); - return gFalse; - } - code[opPtr].type = psOperator; - code[opPtr].op = psOpIf; - code[opPtr+2].type = psBlock; - code[opPtr+2].blk = *codePtr; - } else if (!tok->cmp("ifelse")) { - if (elsePtr < 0) { - error(-1, "Got 'ifelse' operator with one blocks in PostScript function"); - return gFalse; - } - code[opPtr].type = psOperator; - code[opPtr].op = psOpIfelse; - code[opPtr+1].type = psBlock; - code[opPtr+1].blk = elsePtr; - code[opPtr+2].type = psBlock; - code[opPtr+2].blk = *codePtr; - } else { - error(-1, "Expected if/ifelse operator in PostScript function"); - delete tok; - return gFalse; - } - delete tok; - } else if (!tok->cmp("}")) { - delete tok; - resizeCode(*codePtr); - code[*codePtr].type = psOperator; - code[*codePtr].op = psOpReturn; - ++*codePtr; - break; - } else { - a = -1; - b = nPSOps; - // invariant: psOpNames[a] < tok < psOpNames[b] - while (b - a > 1) { - mid = (a + b) / 2; - cmp = tok->cmp(psOpNames[mid]); - if (cmp > 0) { - a = mid; - } else if (cmp < 0) { - b = mid; - } else { - a = b = mid; - } - } - if (cmp != 0) { - error(-1, "Unknown operator '%s' in PostScript function", - tok->getCString()); - delete tok; - return gFalse; - } - delete tok; - resizeCode(*codePtr); - code[*codePtr].type = psOperator; - code[*codePtr].op = (PSOp)a; - ++*codePtr; - } - } - return gTrue; -} - -GString *PostScriptFunction::getToken(Stream *str) { - GString *s; - int c; - - s = new GString(); - do { - c = str->getChar(); - if (c != EOF) { - codeString->append(c); - } - } while (c != EOF && isspace(c)); - if (c == '{' || c == '}') { - s->append((char)c); - } else if (isdigit(c) || c == '.' || c == '-') { - while (1) { - s->append((char)c); - c = str->lookChar(); - if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) { - break; - } - str->getChar(); - codeString->append(c); - } - } else { - while (1) { - s->append((char)c); - c = str->lookChar(); - if (c == EOF || !isalnum(c)) { - break; - } - str->getChar(); - codeString->append(c); - } - } - return s; -} - -void PostScriptFunction::resizeCode(int newSize) { - if (newSize >= codeSize) { - codeSize += 64; - code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject)); - } -} - -void PostScriptFunction::exec(PSStack *stack, int codePtr) { - int i1, i2; - double r1, r2; - GBool b1, b2; - - while (1) { - switch (code[codePtr].type) { - case psInt: - stack->pushInt(code[codePtr++].intg); - break; - case psReal: - stack->pushReal(code[codePtr++].real); - break; - case psOperator: - switch (code[codePtr++].op) { - case psOpAbs: - if (stack->topIsInt()) { - stack->pushInt(abs(stack->popInt())); - } else { - stack->pushReal(fabs(stack->popNum())); - } - break; - case psOpAdd: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 + i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(r1 + r2); - } - break; - case psOpAnd: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 & i2); - } else { - b2 = stack->popBool(); - b1 = stack->popBool(); - stack->pushBool(b1 && b2); - } - break; - case psOpAtan: - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(atan2(r1, r2)); - break; - case psOpBitshift: - i2 = stack->popInt(); - i1 = stack->popInt(); - if (i2 > 0) { - stack->pushInt(i1 << i2); - } else if (i2 < 0) { - stack->pushInt((int)((Guint)i1 >> i2)); - } else { - stack->pushInt(i1); - } - break; - case psOpCeiling: - if (!stack->topIsInt()) { - stack->pushReal(ceil(stack->popNum())); - } - break; - case psOpCopy: - stack->copy(stack->popInt()); - break; - case psOpCos: - stack->pushReal(cos(stack->popNum())); - break; - case psOpCvi: - if (!stack->topIsInt()) { - stack->pushInt((int)stack->popNum()); - } - break; - case psOpCvr: - if (!stack->topIsReal()) { - stack->pushReal(stack->popNum()); - } - break; - case psOpDiv: - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(r1 / r2); - break; - case psOpDup: - stack->copy(1); - break; - case psOpEq: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 == i2); - } else if (stack->topTwoAreNums()) { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 == r2); - } else { - b2 = stack->popBool(); - b1 = stack->popBool(); - stack->pushBool(b1 == b2); - } - break; - case psOpExch: - stack->roll(2, 1); - break; - case psOpExp: - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(pow(r1, r2)); - break; - case psOpFalse: - stack->pushBool(gFalse); - break; - case psOpFloor: - if (!stack->topIsInt()) { - stack->pushReal(floor(stack->popNum())); - } - break; - case psOpGe: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 >= i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 >= r2); - } - break; - case psOpGt: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 > i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 > r2); - } - break; - case psOpIdiv: - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 / i2); - break; - case psOpIndex: - stack->index(stack->popInt()); - break; - case psOpLe: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 <= i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 <= r2); - } - break; - case psOpLn: - stack->pushReal(log(stack->popNum())); - break; - case psOpLog: - stack->pushReal(log10(stack->popNum())); - break; - case psOpLt: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 < i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 < r2); - } - break; - case psOpMod: - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 % i2); - break; - case psOpMul: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - //~ should check for out-of-range, and push a real instead - stack->pushInt(i1 * i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(r1 * r2); - } - break; - case psOpNe: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 != i2); - } else if (stack->topTwoAreNums()) { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 != r2); - } else { - b2 = stack->popBool(); - b1 = stack->popBool(); - stack->pushBool(b1 != b2); - } - break; - case psOpNeg: - if (stack->topIsInt()) { - stack->pushInt(-stack->popInt()); - } else { - stack->pushReal(-stack->popNum()); - } - break; - case psOpNot: - if (stack->topIsInt()) { - stack->pushInt(~stack->popInt()); - } else { - stack->pushBool(!stack->popBool()); - } - break; - case psOpOr: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 | i2); - } else { - b2 = stack->popBool(); - b1 = stack->popBool(); - stack->pushBool(b1 || b2); - } - break; - case psOpPop: - stack->pop(); - break; - case psOpRoll: - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->roll(i1, i2); - break; - case psOpRound: - if (!stack->topIsInt()) { - r1 = stack->popNum(); - stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5)); - } - break; - case psOpSin: - stack->pushReal(sin(stack->popNum())); - break; - case psOpSqrt: - stack->pushReal(sqrt(stack->popNum())); - break; - case psOpSub: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 - i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(r1 - r2); - } - break; - case psOpTrue: - stack->pushBool(gTrue); - break; - case psOpTruncate: - if (!stack->topIsInt()) { - r1 = stack->popNum(); - stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1)); - } - break; - case psOpXor: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 ^ i2); - } else { - b2 = stack->popBool(); - b1 = stack->popBool(); - stack->pushBool(b1 ^ b2); - } - break; - case psOpIf: - b1 = stack->popBool(); - if (b1) { - exec(stack, codePtr + 2); - } - codePtr = code[codePtr + 1].blk; - break; - case psOpIfelse: - b1 = stack->popBool(); - if (b1) { - exec(stack, codePtr + 2); - } else { - exec(stack, code[codePtr].blk); - } - codePtr = code[codePtr + 1].blk; - break; - case psOpReturn: - return; - } - break; - default: - error(-1, "Internal: bad object in PostScript function code"); - break; - } - } -} diff --git a/xpdf/xpdf/Function.h b/xpdf/xpdf/Function.h deleted file mode 100644 index bfaf83e30..000000000 --- a/xpdf/xpdf/Function.h +++ /dev/null @@ -1,225 +0,0 @@ -//======================================================================== -// -// Function.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef FUNCTION_H -#define FUNCTION_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "Object.h" - -class Dict; -class Stream; -struct PSObject; -class PSStack; - -//------------------------------------------------------------------------ -// Function -//------------------------------------------------------------------------ - -#define funcMaxInputs 8 -#define funcMaxOutputs 32 - -class Function { -public: - - Function(); - - virtual ~Function(); - - // Construct a function. Returns NULL if unsuccessful. - static Function *parse(Object *funcObj); - - // Initialize the entries common to all function types. - GBool init(Dict *dict); - - virtual Function *copy() = 0; - - // Return the function type: - // -1 : identity - // 0 : sampled - // 2 : exponential - // 3 : stitching - // 4 : PostScript - virtual int getType() = 0; - - // Return size of input and output tuples. - int getInputSize() { return m; } - int getOutputSize() { return n; } - - double getDomainMin(int i) { return domain[i][0]; } - double getDomainMax(int i) { return domain[i][1]; } - double getRangeMin(int i) { return range[i][0]; } - double getRangeMax(int i) { return range[i][1]; } - GBool getHasRange() { return hasRange; } - - // Transform an input tuple into an output tuple. - virtual void transform(double *in, double *out) = 0; - - virtual GBool isOk() = 0; - -protected: - - int m, n; // size of input and output tuples - double // min and max values for function domain - domain[funcMaxInputs][2]; - double // min and max values for function range - range[funcMaxOutputs][2]; - GBool hasRange; // set if range is defined -}; - -//------------------------------------------------------------------------ -// IdentityFunction -//------------------------------------------------------------------------ - -class IdentityFunction: public Function { -public: - - IdentityFunction(); - virtual ~IdentityFunction(); - virtual Function *copy() { return new IdentityFunction(); } - virtual int getType() { return -1; } - virtual void transform(double *in, double *out); - virtual GBool isOk() { return gTrue; } - -private: -}; - -//------------------------------------------------------------------------ -// SampledFunction -//------------------------------------------------------------------------ - -class SampledFunction: public Function { -public: - - SampledFunction(Object *funcObj, Dict *dict); - virtual ~SampledFunction(); - virtual Function *copy() { return new SampledFunction(this); } - virtual int getType() { return 0; } - virtual void transform(double *in, double *out); - virtual GBool isOk() { return ok; } - - int getSampleSize(int i) { return sampleSize[i]; } - double getEncodeMin(int i) { return encode[i][0]; } - double getEncodeMax(int i) { return encode[i][1]; } - double getDecodeMin(int i) { return decode[i][0]; } - double getDecodeMax(int i) { return decode[i][1]; } - double *getSamples() { return samples; } - -private: - - SampledFunction(SampledFunction *func); - - int // number of samples for each domain element - sampleSize[funcMaxInputs]; - double // min and max values for domain encoder - encode[funcMaxInputs][2]; - double // min and max values for range decoder - decode[funcMaxOutputs][2]; - double // input multipliers - inputMul[funcMaxInputs]; - int idxMul[funcMaxInputs]; // sample array index multipliers - double *samples; // the samples - int nSamples; // size of the samples array - GBool ok; -}; - -//------------------------------------------------------------------------ -// ExponentialFunction -//------------------------------------------------------------------------ - -class ExponentialFunction: public Function { -public: - - ExponentialFunction(Object *funcObj, Dict *dict); - virtual ~ExponentialFunction(); - virtual Function *copy() { return new ExponentialFunction(this); } - virtual int getType() { return 2; } - virtual void transform(double *in, double *out); - virtual GBool isOk() { return ok; } - - double *getC0() { return c0; } - double *getC1() { return c1; } - double getE() { return e; } - -private: - - ExponentialFunction(ExponentialFunction *func); - - double c0[funcMaxOutputs]; - double c1[funcMaxOutputs]; - double e; - GBool ok; -}; - -//------------------------------------------------------------------------ -// StitchingFunction -//------------------------------------------------------------------------ - -class StitchingFunction: public Function { -public: - - StitchingFunction(Object *funcObj, Dict *dict); - virtual ~StitchingFunction(); - virtual Function *copy() { return new StitchingFunction(this); } - virtual int getType() { return 3; } - virtual void transform(double *in, double *out); - virtual GBool isOk() { return ok; } - - int getNumFuncs() { return k; } - Function *getFunc(int i) { return funcs[i]; } - double *getBounds() { return bounds; } - double *getEncode() { return encode; } - -private: - - StitchingFunction(StitchingFunction *func); - - int k; - Function **funcs; - double *bounds; - double *encode; - GBool ok; -}; - -//------------------------------------------------------------------------ -// PostScriptFunction -//------------------------------------------------------------------------ - -class PostScriptFunction: public Function { -public: - - PostScriptFunction(Object *funcObj, Dict *dict); - virtual ~PostScriptFunction(); - virtual Function *copy() { return new PostScriptFunction(this); } - virtual int getType() { return 4; } - virtual void transform(double *in, double *out); - virtual GBool isOk() { return ok; } - - GString *getCodeString() { return codeString; } - -private: - - PostScriptFunction(PostScriptFunction *func); - GBool parseCode(Stream *str, int *codePtr); - GString *getToken(Stream *str); - void resizeCode(int newSize); - void exec(PSStack *stack, int codePtr); - - GString *codeString; - PSObject *code; - int codeSize; - GBool ok; -}; - -#endif diff --git a/xpdf/xpdf/Gfx.cc b/xpdf/xpdf/Gfx.cc deleted file mode 100644 index cb93a405f..000000000 --- a/xpdf/xpdf/Gfx.cc +++ /dev/null @@ -1,3598 +0,0 @@ -//======================================================================== -// -// Gfx.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include -#include "gmem.h" -#include "GlobalParams.h" -#include "CharTypes.h" -#include "Object.h" -#include "Array.h" -#include "Dict.h" -#include "Stream.h" -#include "Lexer.h" -#include "Parser.h" -#include "GfxFont.h" -#include "GfxState.h" -#include "OutputDev.h" -#include "Page.h" -#include "Error.h" -#include "Gfx.h" -#include "UGString.h" - -// the MSVC math.h doesn't define this -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -//------------------------------------------------------------------------ -// constants -//------------------------------------------------------------------------ - -// Max recursive depth for a function shading fill. -#define functionMaxDepth 6 - -// Max delta allowed in any color component for a function shading fill. -#define functionColorDelta (dblToCol(1 / 256.0)) - -// Max number of splits along the t axis for an axial shading fill. -#define axialMaxSplits 256 - -// Max delta allowed in any color component for an axial shading fill. -#define axialColorDelta (dblToCol(1 / 256.0)) - -// Max number of splits along the t axis for a radial shading fill. -#define radialMaxSplits 256 - -// Max delta allowed in any color component for a radial shading fill. -#define radialColorDelta (dblToCol(1 / 256.0)) - -// Max recursive depth for a Gouraud triangle shading fill. -#define gouraudMaxDepth 4 - -// Max delta allowed in any color component for a Gouraud triangle -// shading fill. -#define gouraudColorDelta (dblToCol(1 / 256.0)) - -// Max recursive depth for a patch mesh shading fill. -#define patchMaxDepth 6 - -// Max delta allowed in any color component for a patch mesh shading -// fill. -#define patchColorDelta (dblToCol(1 / 256.0)) - -//------------------------------------------------------------------------ -// Operator table -//------------------------------------------------------------------------ - -#ifdef WIN32 // this works around a bug in the VC7 compiler -# pragma optimize("",off) -#endif - -Operator Gfx::opTab[] = { - {"\"", 3, {tchkNum, tchkNum, tchkString}, - &Gfx::opMoveSetShowText}, - {"'", 1, {tchkString}, - &Gfx::opMoveShowText}, - {"B", 0, {tchkNone}, - &Gfx::opFillStroke}, - {"B*", 0, {tchkNone}, - &Gfx::opEOFillStroke}, - {"BDC", 2, {tchkName, tchkProps}, - &Gfx::opBeginMarkedContent}, - {"BI", 0, {tchkNone}, - &Gfx::opBeginImage}, - {"BMC", 1, {tchkName}, - &Gfx::opBeginMarkedContent}, - {"BT", 0, {tchkNone}, - &Gfx::opBeginText}, - {"BX", 0, {tchkNone}, - &Gfx::opBeginIgnoreUndef}, - {"CS", 1, {tchkName}, - &Gfx::opSetStrokeColorSpace}, - {"DP", 2, {tchkName, tchkProps}, - &Gfx::opMarkPoint}, - {"Do", 1, {tchkName}, - &Gfx::opXObject}, - {"EI", 0, {tchkNone}, - &Gfx::opEndImage}, - {"EMC", 0, {tchkNone}, - &Gfx::opEndMarkedContent}, - {"ET", 0, {tchkNone}, - &Gfx::opEndText}, - {"EX", 0, {tchkNone}, - &Gfx::opEndIgnoreUndef}, - {"F", 0, {tchkNone}, - &Gfx::opFill}, - {"G", 1, {tchkNum}, - &Gfx::opSetStrokeGray}, - {"ID", 0, {tchkNone}, - &Gfx::opImageData}, - {"J", 1, {tchkInt}, - &Gfx::opSetLineCap}, - {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, - &Gfx::opSetStrokeCMYKColor}, - {"M", 1, {tchkNum}, - &Gfx::opSetMiterLimit}, - {"MP", 1, {tchkName}, - &Gfx::opMarkPoint}, - {"Q", 0, {tchkNone}, - &Gfx::opRestore}, - {"RG", 3, {tchkNum, tchkNum, tchkNum}, - &Gfx::opSetStrokeRGBColor}, - {"S", 0, {tchkNone}, - &Gfx::opStroke}, - {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum}, - &Gfx::opSetStrokeColor}, - {"SCN", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN, - tchkSCN}, - &Gfx::opSetStrokeColorN}, - {"T*", 0, {tchkNone}, - &Gfx::opTextNextLine}, - {"TD", 2, {tchkNum, tchkNum}, - &Gfx::opTextMoveSet}, - {"TJ", 1, {tchkArray}, - &Gfx::opShowSpaceText}, - {"TL", 1, {tchkNum}, - &Gfx::opSetTextLeading}, - {"Tc", 1, {tchkNum}, - &Gfx::opSetCharSpacing}, - {"Td", 2, {tchkNum, tchkNum}, - &Gfx::opTextMove}, - {"Tf", 2, {tchkName, tchkNum}, - &Gfx::opSetFont}, - {"Tj", 1, {tchkString}, - &Gfx::opShowText}, - {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum, - tchkNum, tchkNum}, - &Gfx::opSetTextMatrix}, - {"Tr", 1, {tchkInt}, - &Gfx::opSetTextRender}, - {"Ts", 1, {tchkNum}, - &Gfx::opSetTextRise}, - {"Tw", 1, {tchkNum}, - &Gfx::opSetWordSpacing}, - {"Tz", 1, {tchkNum}, - &Gfx::opSetHorizScaling}, - {"W", 0, {tchkNone}, - &Gfx::opClip}, - {"W*", 0, {tchkNone}, - &Gfx::opEOClip}, - {"b", 0, {tchkNone}, - &Gfx::opCloseFillStroke}, - {"b*", 0, {tchkNone}, - &Gfx::opCloseEOFillStroke}, - {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum, - tchkNum, tchkNum}, - &Gfx::opCurveTo}, - {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum, - tchkNum, tchkNum}, - &Gfx::opConcat}, - {"cs", 1, {tchkName}, - &Gfx::opSetFillColorSpace}, - {"d", 2, {tchkArray, tchkNum}, - &Gfx::opSetDash}, - {"d0", 2, {tchkNum, tchkNum}, - &Gfx::opSetCharWidth}, - {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum, - tchkNum, tchkNum}, - &Gfx::opSetCacheDevice}, - {"f", 0, {tchkNone}, - &Gfx::opFill}, - {"f*", 0, {tchkNone}, - &Gfx::opEOFill}, - {"g", 1, {tchkNum}, - &Gfx::opSetFillGray}, - {"gs", 1, {tchkName}, - &Gfx::opSetExtGState}, - {"h", 0, {tchkNone}, - &Gfx::opClosePath}, - {"i", 1, {tchkNum}, - &Gfx::opSetFlat}, - {"j", 1, {tchkInt}, - &Gfx::opSetLineJoin}, - {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, - &Gfx::opSetFillCMYKColor}, - {"l", 2, {tchkNum, tchkNum}, - &Gfx::opLineTo}, - {"m", 2, {tchkNum, tchkNum}, - &Gfx::opMoveTo}, - {"n", 0, {tchkNone}, - &Gfx::opEndPath}, - {"q", 0, {tchkNone}, - &Gfx::opSave}, - {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, - &Gfx::opRectangle}, - {"rg", 3, {tchkNum, tchkNum, tchkNum}, - &Gfx::opSetFillRGBColor}, - {"ri", 1, {tchkName}, - &Gfx::opSetRenderingIntent}, - {"s", 0, {tchkNone}, - &Gfx::opCloseStroke}, - {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum}, - &Gfx::opSetFillColor}, - {"scn", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN, - tchkSCN}, - &Gfx::opSetFillColorN}, - {"sh", 1, {tchkName}, - &Gfx::opShFill}, - {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, - &Gfx::opCurveTo1}, - {"w", 1, {tchkNum}, - &Gfx::opSetLineWidth}, - {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, - &Gfx::opCurveTo2}, -}; - -#ifdef WIN32 // this works around a bug in the VC7 compiler -# pragma optimize("",on) -#endif - -#define numOps (sizeof(opTab) / sizeof(Operator)) - -//------------------------------------------------------------------------ -// GfxResources -//------------------------------------------------------------------------ - -GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) { - Object obj1, obj2; - Ref r; - - if (resDict) { - - // build font dictionary - fonts = NULL; - resDict->lookupNF("Font", &obj1); - if (obj1.isRef()) { - obj1.fetch(xref, &obj2); - if (obj2.isDict()) { - r = obj1.getRef(); - fonts = new GfxFontDict(xref, &r, obj2.getDict()); - } - obj2.free(); - } else if (obj1.isDict()) { - fonts = new GfxFontDict(xref, NULL, obj1.getDict()); - } - obj1.free(); - - // get XObject dictionary - resDict->lookup("XObject", &xObjDict); - - // get color space dictionary - resDict->lookup("ColorSpace", &colorSpaceDict); - - // get pattern dictionary - resDict->lookup("Pattern", &patternDict); - - // get shading dictionary - resDict->lookup("Shading", &shadingDict); - - // get graphics state parameter dictionary - resDict->lookup("ExtGState", &gStateDict); - - } else { - fonts = NULL; - xObjDict.initNull(); - colorSpaceDict.initNull(); - patternDict.initNull(); - shadingDict.initNull(); - gStateDict.initNull(); - } - - next = nextA; -} - -GfxResources::~GfxResources() { - if (fonts) { - delete fonts; - } - xObjDict.free(); - colorSpaceDict.free(); - patternDict.free(); - shadingDict.free(); - gStateDict.free(); -} - -GfxFont *GfxResources::lookupFont(const char *name) { - GfxFont *font; - GfxResources *resPtr; - - for (resPtr = this; resPtr; resPtr = resPtr->next) { - if (resPtr->fonts) { - if ((font = resPtr->fonts->lookup(name))) - return font; - } - } - error(-1, "Unknown font tag '%s'", name); - return NULL; -} - -GBool GfxResources::lookupXObject(const char *name, Object *obj) { - GfxResources *resPtr; - - for (resPtr = this; resPtr; resPtr = resPtr->next) { - if (resPtr->xObjDict.isDict()) { - if (!resPtr->xObjDict.dictLookup(name, obj)->isNull()) - return gTrue; - obj->free(); - } - } - error(-1, "XObject '%s' is unknown", name); - return gFalse; -} - -GBool GfxResources::lookupXObjectNF(const char *name, Object *obj) { - GfxResources *resPtr; - - for (resPtr = this; resPtr; resPtr = resPtr->next) { - if (resPtr->xObjDict.isDict()) { - if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull()) - return gTrue; - obj->free(); - } - } - error(-1, "XObject '%s' is unknown", name); - return gFalse; -} - -void GfxResources::lookupColorSpace(const char *name, Object *obj) { - GfxResources *resPtr; - - for (resPtr = this; resPtr; resPtr = resPtr->next) { - if (resPtr->colorSpaceDict.isDict()) { - if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) { - return; - } - obj->free(); - } - } - obj->initNull(); -} - -GfxPattern *GfxResources::lookupPattern(const char *name) { - GfxResources *resPtr; - GfxPattern *pattern; - Object obj; - - for (resPtr = this; resPtr; resPtr = resPtr->next) { - if (resPtr->patternDict.isDict()) { - if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) { - pattern = GfxPattern::parse(&obj); - obj.free(); - return pattern; - } - obj.free(); - } - } - error(-1, "Unknown pattern '%s'", name); - return NULL; -} - -GfxShading *GfxResources::lookupShading(const char *name) { - GfxResources *resPtr; - GfxShading *shading; - Object obj; - - for (resPtr = this; resPtr; resPtr = resPtr->next) { - if (resPtr->shadingDict.isDict()) { - if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) { - shading = GfxShading::parse(&obj); - obj.free(); - return shading; - } - obj.free(); - } - } - error(-1, "Unknown shading '%s'", name); - return NULL; -} - -GBool GfxResources::lookupGState(const char *name, Object *obj) { - GfxResources *resPtr; - - for (resPtr = this; resPtr; resPtr = resPtr->next) { - if (resPtr->gStateDict.isDict()) { - if (!resPtr->gStateDict.dictLookup(name, obj)->isNull()) { - return gTrue; - } - obj->free(); - } - } - error(-1, "ExtGState '%s' is unknown", name); - return gFalse; -} - -//------------------------------------------------------------------------ -// Gfx -//------------------------------------------------------------------------ - -Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, - double hDPI, double vDPI, PDFRectangle *box, - PDFRectangle *cropBox, int rotate, - GBool (*abortCheckCbkA)(void *data), - void *abortCheckCbkDataA) { - int i; - - xref = xrefA; - subPage = gFalse; - printCommands = globalParams->getPrintCommands(); - - // start the resource stack - res = new GfxResources(xref, resDict, NULL); - - // initialize - out = outA; - state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown()); - fontChanged = gFalse; - clip = clipNone; - ignoreUndef = 0; - out->startPage(pageNum, state); - out->setDefaultCTM(state->getCTM()); - out->updateAll(state); - for (i = 0; i < 6; ++i) { - baseMatrix[i] = state->getCTM()[i]; - } - formDepth = 0; - abortCheckCbk = abortCheckCbkA; - abortCheckCbkData = abortCheckCbkDataA; - - // set crop box - if (cropBox) { - state->moveTo(cropBox->x1, cropBox->y1); - state->lineTo(cropBox->x2, cropBox->y1); - state->lineTo(cropBox->x2, cropBox->y2); - state->lineTo(cropBox->x1, cropBox->y2); - state->closePath(); - state->clip(); - out->clip(state); - state->clearPath(); - } -} - -Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, - PDFRectangle *box, PDFRectangle *cropBox, - GBool (*abortCheckCbkA)(void *data), - void *abortCheckCbkDataA) { - int i; - - xref = xrefA; - subPage = gTrue; - printCommands = globalParams->getPrintCommands(); - - // start the resource stack - res = new GfxResources(xref, resDict, NULL); - - // initialize - out = outA; - state = new GfxState(72, 72, box, 0, gFalse); - fontChanged = gFalse; - clip = clipNone; - ignoreUndef = 0; - for (i = 0; i < 6; ++i) { - baseMatrix[i] = state->getCTM()[i]; - } - formDepth = 0; - abortCheckCbk = abortCheckCbkA; - abortCheckCbkData = abortCheckCbkDataA; - - // set crop box - if (cropBox) { - state->moveTo(cropBox->x1, cropBox->y1); - state->lineTo(cropBox->x2, cropBox->y1); - state->lineTo(cropBox->x2, cropBox->y2); - state->lineTo(cropBox->x1, cropBox->y2); - state->closePath(); - state->clip(); - out->clip(state); - state->clearPath(); - } -} - -Gfx::~Gfx() { - while (state->hasSaves()) { - restoreState(); - } - if (!subPage) { - out->endPage(); - } - while (res) { - popResources(); - } - if (state) { - delete state; - } -} - -void Gfx::display(Object *obj, GBool topLevel) { - Object obj2; - int i; - - if (obj->isArray()) { - for (i = 0; i < obj->arrayGetLength(); ++i) { - obj->arrayGet(i, &obj2); - if (!obj2.isStream()) { - error(-1, "Weird page contents"); - obj2.free(); - return; - } - obj2.free(); - } - } else if (!obj->isStream()) { - error(-1, "Weird page contents"); - return; - } - parser = new Parser(xref, new Lexer(xref, obj)); - go(topLevel); - delete parser; - parser = NULL; -} - -void Gfx::go(GBool topLevel) { - Object obj; - Object args[maxArgs]; - int numArgs, i; - int lastAbortCheck; - - // scan a sequence of objects - updateLevel = lastAbortCheck = 0; - numArgs = 0; - parser->getObj(&obj); - while (!obj.isEOF()) { - - // got a command - execute it - if (obj.isCmd()) { - if (printCommands) { - obj.print(stdout); - for (i = 0; i < numArgs; ++i) { - printf(" "); - args[i].print(stdout); - } - printf("\n"); - fflush(stdout); - } - execOp(&obj, args, numArgs); - obj.free(); - for (i = 0; i < numArgs; ++i) - args[i].free(); - numArgs = 0; - - // periodically update display - if (++updateLevel >= 20000) { - out->dump(); - updateLevel = 0; - } - - // check for an abort - if (abortCheckCbk) { - if (updateLevel - lastAbortCheck > 10) { - if ((*abortCheckCbk)(abortCheckCbkData)) { - break; - } - lastAbortCheck = updateLevel; - } - } - - // got an argument - save it - } else if (numArgs < maxArgs) { - args[numArgs++] = obj; - - // too many arguments - something is wrong - } else { - error(getPos(), "Too many args in content stream"); - if (printCommands) { - printf("throwing away arg: "); - obj.print(stdout); - printf("\n"); - fflush(stdout); - } - obj.free(); - } - - // grab the next object - parser->getObj(&obj); - } - obj.free(); - - // args at end with no command - if (numArgs > 0) { - error(getPos(), "Leftover args in content stream"); - if (printCommands) { - printf("%d leftovers:", numArgs); - for (i = 0; i < numArgs; ++i) { - printf(" "); - args[i].print(stdout); - } - printf("\n"); - fflush(stdout); - } - for (i = 0; i < numArgs; ++i) - args[i].free(); - } - - // update display - if (topLevel && updateLevel > 0) { - out->dump(); - } -} - -void Gfx::execOp(Object *cmd, Object args[], int numArgs) { - Operator *op; - const char *name; - Object *argPtr; - int i; - - // find operator - name = cmd->getCmd(); - if (!(op = findOp(name))) { - if (ignoreUndef == 0) - error(getPos(), "Unknown operator '%s'", name); - return; - } - - // type check args - argPtr = args; - if (op->numArgs >= 0) { - if (numArgs < op->numArgs) { - error(getPos(), "Too few (%d) args to '%s' operator", numArgs, name); - return; - } - if (numArgs > op->numArgs) { -#if 0 - error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name); -#endif - argPtr += numArgs - op->numArgs; - numArgs = op->numArgs; - } - } else { - if (numArgs > -op->numArgs) { - error(getPos(), "Too many (%d) args to '%s' operator", - numArgs, name); - return; - } - } - for (i = 0; i < numArgs; ++i) { - if (!checkArg(&argPtr[i], op->tchk[i])) { - error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)", - i, name, argPtr[i].getTypeName()); - return; - } - } - - // do it - (this->*op->func)(argPtr, numArgs); -} - -Operator *Gfx::findOp(const char *name) { - int a, b, m, cmp; - - a = -1; - b = numOps; - // invariant: opTab[a] < name < opTab[b] - while (b - a > 1) { - m = (a + b) / 2; - cmp = strcmp(opTab[m].name, name); - if (cmp < 0) - a = m; - else if (cmp > 0) - b = m; - else - a = b = m; - } - if (cmp != 0) - return NULL; - return &opTab[a]; -} - -GBool Gfx::checkArg(Object *arg, TchkType type) { - switch (type) { - case tchkBool: return arg->isBool(); - case tchkInt: return arg->isInt(); - case tchkNum: return arg->isNum(); - case tchkString: return arg->isString(); - case tchkName: return arg->isName(); - case tchkArray: return arg->isArray(); - case tchkProps: return arg->isDict() || arg->isName(); - case tchkSCN: return arg->isNum() || arg->isName(); - case tchkNone: return gFalse; - } - return gFalse; -} - -int Gfx::getPos() { - return parser ? parser->getPos() : -1; -} - -//------------------------------------------------------------------------ -// graphics state operators -//------------------------------------------------------------------------ - -void Gfx::opSave(Object * /*args*/, int /*numArgs*/) { - saveState(); -} - -void Gfx::opRestore(Object * /*args*/, int /*numArgs*/) { - restoreState(); -} - -void Gfx::opConcat(Object args[], int /*numArgs*/) { - state->concatCTM(args[0].getNum(), args[1].getNum(), - args[2].getNum(), args[3].getNum(), - args[4].getNum(), args[5].getNum()); - out->updateCTM(state, args[0].getNum(), args[1].getNum(), - args[2].getNum(), args[3].getNum(), - args[4].getNum(), args[5].getNum()); - fontChanged = gTrue; -} - -void Gfx::opSetDash(Object args[], int /*numArgs*/) { - Array *a; - int length; - Object obj; - double *dash; - int i; - - a = args[0].getArray(); - length = a->getLength(); - if (length == 0) { - dash = NULL; - } else { - dash = (double *)gmallocn(length, sizeof(double)); - for (i = 0; i < length; ++i) { - dash[i] = a->get(i, &obj)->getNum(); - obj.free(); - } - } - state->setLineDash(dash, length, args[1].getNum()); - out->updateLineDash(state); -} - -void Gfx::opSetFlat(Object args[], int /*numArgs*/) { - state->setFlatness((int)args[0].getNum()); - out->updateFlatness(state); -} - -void Gfx::opSetLineJoin(Object args[], int /*numArgs*/) { - state->setLineJoin(args[0].getInt()); - out->updateLineJoin(state); -} - -void Gfx::opSetLineCap(Object args[], int /*numArgs*/) { - state->setLineCap(args[0].getInt()); - out->updateLineCap(state); -} - -void Gfx::opSetMiterLimit(Object args[], int /*numArgs*/) { - state->setMiterLimit(args[0].getNum()); - out->updateMiterLimit(state); -} - -void Gfx::opSetLineWidth(Object args[], int /*numArgs*/) { - state->setLineWidth(args[0].getNum()); - out->updateLineWidth(state); -} - -void Gfx::opSetExtGState(Object args[], int /*numArgs*/) { - Object obj1, obj2; - GfxBlendMode mode; - GBool haveFillOP; - - if (!res->lookupGState(args[0].getName(), &obj1)) { - return; - } - if (!obj1.isDict()) { - error(getPos(), "ExtGState '%s' is wrong type", args[0].getName()); - obj1.free(); - return; - } - - // transparency support: blend mode, fill/stroke opacity - if (!obj1.dictLookup("BM", &obj2)->isNull()) { - if (state->parseBlendMode(&obj2, &mode)) { - state->setBlendMode(mode); - out->updateBlendMode(state); - } else { - error(getPos(), "Invalid blend mode in ExtGState"); - } - } - obj2.free(); - if (obj1.dictLookup("ca", &obj2)->isNum()) { - state->setFillOpacity(obj2.getNum()); - out->updateFillOpacity(state); - } - obj2.free(); - if (obj1.dictLookup("CA", &obj2)->isNum()) { - state->setStrokeOpacity(obj2.getNum()); - out->updateStrokeOpacity(state); - } - obj2.free(); - - // fill/stroke overprint - if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) { - state->setFillOverprint(obj2.getBool()); - out->updateFillOverprint(state); - } - obj2.free(); - if (obj1.dictLookup("OP", &obj2)->isBool()) { - state->setStrokeOverprint(obj2.getBool()); - out->updateStrokeOverprint(state); - if (!haveFillOP) { - state->setFillOverprint(obj2.getBool()); - out->updateFillOverprint(state); - } - } - obj2.free(); - - obj1.free(); -} - -void Gfx::opSetRenderingIntent(Object */*args*/, int /*numArgs*/) { -} - -//------------------------------------------------------------------------ -// color operators -//------------------------------------------------------------------------ - -void Gfx::opSetFillGray(Object args[], int /*numArgs*/) { - GfxColor color; - - state->setFillPattern(NULL); - state->setFillColorSpace(new GfxDeviceGrayColorSpace()); - out->updateFillColorSpace(state); - color.c[0] = dblToCol(args[0].getNum()); - state->setFillColor(&color); - out->updateFillColor(state); -} - -void Gfx::opSetStrokeGray(Object args[], int /*numArgs*/) { - GfxColor color; - - state->setStrokePattern(NULL); - state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); - out->updateStrokeColorSpace(state); - color.c[0] = dblToCol(args[0].getNum()); - state->setStrokeColor(&color); - out->updateStrokeColor(state); -} - -void Gfx::opSetFillCMYKColor(Object args[], int /*numArgs*/) { - GfxColor color; - int i; - - state->setFillPattern(NULL); - state->setFillColorSpace(new GfxDeviceCMYKColorSpace()); - out->updateFillColorSpace(state); - for (i = 0; i < 4; ++i) { - color.c[i] = dblToCol(args[i].getNum()); - } - state->setFillColor(&color); - out->updateFillColor(state); -} - -void Gfx::opSetStrokeCMYKColor(Object args[], int /*numArgs*/) { - GfxColor color; - int i; - - state->setStrokePattern(NULL); - state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace()); - out->updateStrokeColorSpace(state); - for (i = 0; i < 4; ++i) { - color.c[i] = dblToCol(args[i].getNum()); - } - state->setStrokeColor(&color); - out->updateStrokeColor(state); -} - -void Gfx::opSetFillRGBColor(Object args[], int /*numArgs*/) { - GfxColor color; - int i; - - state->setFillPattern(NULL); - state->setFillColorSpace(new GfxDeviceRGBColorSpace()); - out->updateFillColorSpace(state); - for (i = 0; i < 3; ++i) { - color.c[i] = dblToCol(args[i].getNum()); - } - state->setFillColor(&color); - out->updateFillColor(state); -} - -void Gfx::opSetStrokeRGBColor(Object args[], int /*numArgs*/) { - GfxColor color; - int i; - - state->setStrokePattern(NULL); - state->setStrokeColorSpace(new GfxDeviceRGBColorSpace()); - out->updateStrokeColorSpace(state); - for (i = 0; i < 3; ++i) { - color.c[i] = dblToCol(args[i].getNum()); - } - state->setStrokeColor(&color); - out->updateStrokeColor(state); -} - -void Gfx::opSetFillColorSpace(Object args[], int /*numArgs*/) { - Object obj; - GfxColorSpace *colorSpace; - GfxColor color; - int i; - - state->setFillPattern(NULL); - res->lookupColorSpace(args[0].getName(), &obj); - if (obj.isNull()) { - colorSpace = GfxColorSpace::parse(&args[0]); - } else { - colorSpace = GfxColorSpace::parse(&obj); - } - obj.free(); - if (colorSpace) { - state->setFillColorSpace(colorSpace); - out->updateFillColorSpace(state); - } else { - error(getPos(), "Bad color space (fill)"); - } - for (i = 0; i < gfxColorMaxComps; ++i) { - color.c[i] = 0; - } - state->setFillColor(&color); - out->updateFillColor(state); -} - -void Gfx::opSetStrokeColorSpace(Object args[], int /*numArgs*/) { - Object obj; - GfxColorSpace *colorSpace; - GfxColor color; - int i; - - state->setStrokePattern(NULL); - res->lookupColorSpace(args[0].getName(), &obj); - if (obj.isNull()) { - colorSpace = GfxColorSpace::parse(&args[0]); - } else { - colorSpace = GfxColorSpace::parse(&obj); - } - obj.free(); - if (colorSpace) { - state->setStrokeColorSpace(colorSpace); - out->updateStrokeColorSpace(state); - } else { - error(getPos(), "Bad color space (stroke)"); - } - for (i = 0; i < gfxColorMaxComps; ++i) { - color.c[i] = 0; - } - state->setStrokeColor(&color); - out->updateStrokeColor(state); -} - -void Gfx::opSetFillColor(Object args[], int numArgs) { - GfxColor color; - int i; - - state->setFillPattern(NULL); - for (i = 0; i < numArgs; ++i) { - color.c[i] = dblToCol(args[i].getNum()); - } - state->setFillColor(&color); - out->updateFillColor(state); -} - -void Gfx::opSetStrokeColor(Object args[], int numArgs) { - GfxColor color; - int i; - - state->setStrokePattern(NULL); - for (i = 0; i < numArgs; ++i) { - color.c[i] = dblToCol(args[i].getNum()); - } - state->setStrokeColor(&color); - out->updateStrokeColor(state); -} - -void Gfx::opSetFillColorN(Object args[], int numArgs) { - GfxColor color; - GfxPattern *pattern; - int i; - - if (state->getFillColorSpace()->getMode() == csPattern) { - if (numArgs > 1) { - for (i = 0; i < numArgs && i < 4; ++i) { - if (args[i].isNum()) { - color.c[i] = dblToCol(args[i].getNum()); - } - } - state->setFillColor(&color); - out->updateFillColor(state); - } - if (args[numArgs-1].isName() && - (pattern = res->lookupPattern(args[numArgs-1].getName()))) { - state->setFillPattern(pattern); - } - - } else { - state->setFillPattern(NULL); - for (i = 0; i < numArgs && i < 4; ++i) { - if (args[i].isNum()) { - color.c[i] = dblToCol(args[i].getNum()); - } - } - state->setFillColor(&color); - out->updateFillColor(state); - } -} - -void Gfx::opSetStrokeColorN(Object args[], int numArgs) { - GfxColor color; - GfxPattern *pattern; - int i; - - if (state->getStrokeColorSpace()->getMode() == csPattern) { - if (numArgs > 1) { - for (i = 0; i < numArgs && i < 4; ++i) { - if (args[i].isNum()) { - color.c[i] = dblToCol(args[i].getNum()); - } - } - state->setStrokeColor(&color); - out->updateStrokeColor(state); - } - if (args[numArgs-1].isName() && - (pattern = res->lookupPattern(args[numArgs-1].getName()))) { - state->setStrokePattern(pattern); - } - - } else { - state->setStrokePattern(NULL); - for (i = 0; i < numArgs && i < 4; ++i) { - if (args[i].isNum()) { - color.c[i] = dblToCol(args[i].getNum()); - } - } - state->setStrokeColor(&color); - out->updateStrokeColor(state); - } -} - -//------------------------------------------------------------------------ -// path segment operators -//------------------------------------------------------------------------ - -void Gfx::opMoveTo(Object args[], int /*numArgs*/) { - state->moveTo(args[0].getNum(), args[1].getNum()); -} - -void Gfx::opLineTo(Object args[], int /*numArgs*/) { - if (!state->isCurPt()) { - error(getPos(), "No current point in lineto"); - return; - } - state->lineTo(args[0].getNum(), args[1].getNum()); -} - -void Gfx::opCurveTo(Object args[], int /*numArgs*/) { - double x1, y1, x2, y2, x3, y3; - - if (!state->isCurPt()) { - error(getPos(), "No current point in curveto"); - return; - } - x1 = args[0].getNum(); - y1 = args[1].getNum(); - x2 = args[2].getNum(); - y2 = args[3].getNum(); - x3 = args[4].getNum(); - y3 = args[5].getNum(); - state->curveTo(x1, y1, x2, y2, x3, y3); -} - -void Gfx::opCurveTo1(Object args[], int /*numArgs*/) { - double x1, y1, x2, y2, x3, y3; - - if (!state->isCurPt()) { - error(getPos(), "No current point in curveto1"); - return; - } - x1 = state->getCurX(); - y1 = state->getCurY(); - x2 = args[0].getNum(); - y2 = args[1].getNum(); - x3 = args[2].getNum(); - y3 = args[3].getNum(); - state->curveTo(x1, y1, x2, y2, x3, y3); -} - -void Gfx::opCurveTo2(Object args[], int /*numArgs*/) { - double x1, y1, x2, y2, x3, y3; - - if (!state->isCurPt()) { - error(getPos(), "No current point in curveto2"); - return; - } - x1 = args[0].getNum(); - y1 = args[1].getNum(); - x2 = args[2].getNum(); - y2 = args[3].getNum(); - x3 = x2; - y3 = y2; - state->curveTo(x1, y1, x2, y2, x3, y3); -} - -void Gfx::opRectangle(Object args[], int /*numArgs*/) { - double x, y, w, h; - - x = args[0].getNum(); - y = args[1].getNum(); - w = args[2].getNum(); - h = args[3].getNum(); - state->moveTo(x, y); - state->lineTo(x + w, y); - state->lineTo(x + w, y + h); - state->lineTo(x, y + h); - state->closePath(); -} - -void Gfx::opClosePath(Object */*args*/, int /*numArgs*/) { - if (!state->isCurPt()) { - error(getPos(), "No current point in closepath"); - return; - } - state->closePath(); -} - -//------------------------------------------------------------------------ -// path painting operators -//------------------------------------------------------------------------ - -void Gfx::opEndPath(Object */*args*/, int /*numArgs*/) { - doEndPath(); -} - -void Gfx::opStroke(Object */*args*/, int /*numArgs*/) { - if (!state->isCurPt()) { - //error(getPos(), "No path in stroke"); - return; - } - if (state->isPath()) - out->stroke(state); - doEndPath(); -} - -void Gfx::opCloseStroke(Object */*args*/, int /*numArgs*/) { - if (!state->isCurPt()) { - //error(getPos(), "No path in closepath/stroke"); - return; - } - if (state->isPath()) { - state->closePath(); - out->stroke(state); - } - doEndPath(); -} - -void Gfx::opFill(Object */*args*/, int /*numArgs*/) { - if (!state->isCurPt()) { - //error(getPos(), "No path in fill"); - return; - } - if (state->isPath()) { - if (state->getFillColorSpace()->getMode() == csPattern) { - doPatternFill(gFalse); - } else { - out->fill(state); - } - } - doEndPath(); -} - -void Gfx::opEOFill(Object */*args*/, int /*numArgs*/) { - if (!state->isCurPt()) { - //error(getPos(), "No path in eofill"); - return; - } - if (state->isPath()) { - if (state->getFillColorSpace()->getMode() == csPattern) { - doPatternFill(gTrue); - } else { - out->eoFill(state); - } - } - doEndPath(); -} - -void Gfx::opFillStroke(Object */*args*/, int /*numArgs*/) { - if (!state->isCurPt()) { - //error(getPos(), "No path in fill/stroke"); - return; - } - if (state->isPath()) { - if (state->getFillColorSpace()->getMode() == csPattern) { - doPatternFill(gFalse); - } else { - out->fill(state); - } - out->stroke(state); - } - doEndPath(); -} - -void Gfx::opCloseFillStroke(Object */*args*/, int /*numArgs*/) { - if (!state->isCurPt()) { - //error(getPos(), "No path in closepath/fill/stroke"); - return; - } - if (state->isPath()) { - state->closePath(); - if (state->getFillColorSpace()->getMode() == csPattern) { - doPatternFill(gFalse); - } else { - out->fill(state); - } - out->stroke(state); - } - doEndPath(); -} - -void Gfx::opEOFillStroke(Object */*args*/, int /*numArgs*/) { - if (!state->isCurPt()) { - //error(getPos(), "No path in eofill/stroke"); - return; - } - if (state->isPath()) { - if (state->getFillColorSpace()->getMode() == csPattern) { - doPatternFill(gTrue); - } else { - out->eoFill(state); - } - out->stroke(state); - } - doEndPath(); -} - -void Gfx::opCloseEOFillStroke(Object */*args*/, int /*numArgs*/) { - if (!state->isCurPt()) { - //error(getPos(), "No path in closepath/eofill/stroke"); - return; - } - if (state->isPath()) { - state->closePath(); - if (state->getFillColorSpace()->getMode() == csPattern) { - doPatternFill(gTrue); - } else { - out->eoFill(state); - } - out->stroke(state); - } - doEndPath(); -} - -void Gfx::doPatternFill(GBool eoFill) { - GfxPattern *pattern; - - // this is a bit of a kludge -- patterns can be really slow, so we - // skip them if we're only doing text extraction, since they almost - // certainly don't contain any text - if (!out->needNonText()) { - return; - } - - if (!(pattern = state->getFillPattern())) { - return; - } - switch (pattern->getType()) { - case 1: - doTilingPatternFill((GfxTilingPattern *)pattern, eoFill); - break; - case 2: - doShadingPatternFill((GfxShadingPattern *)pattern, eoFill); - break; - default: - error(getPos(), "Unimplemented pattern type (%d) in fill", - pattern->getType()); - break; - } -} - -void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { - GfxPatternColorSpace *patCS; - GfxColorSpace *cs; - GfxPath *savedPath; - double xMin, yMin, xMax, yMax, x, y, x1, y1; - double cxMin, cyMin, cxMax, cyMax; - int xi0, yi0, xi1, yi1, xi, yi; - double *ctm, *btm, *ptm; - double m[6], ictm[6], m1[6], imb[6]; - double det; - double xstep, ystep; - int i; - - // get color space - patCS = (GfxPatternColorSpace *)state->getFillColorSpace(); - - // construct a (pattern space) -> (current space) transform matrix - ctm = state->getCTM(); - btm = baseMatrix; - ptm = tPat->getMatrix(); - // iCTM = invert CTM - det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); - ictm[0] = ctm[3] * det; - ictm[1] = -ctm[1] * det; - ictm[2] = -ctm[2] * det; - ictm[3] = ctm[0] * det; - ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; - ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; - // m1 = PTM * BTM = PTM * base transform matrix - m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2]; - m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3]; - m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2]; - m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3]; - m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4]; - m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5]; - // m = m1 * iCTM = (PTM * BTM) * (iCTM) - m[0] = m1[0] * ictm[0] + m1[1] * ictm[2]; - m[1] = m1[0] * ictm[1] + m1[1] * ictm[3]; - m[2] = m1[2] * ictm[0] + m1[3] * ictm[2]; - m[3] = m1[2] * ictm[1] + m1[3] * ictm[3]; - m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; - m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; - - // construct a (device space) -> (pattern space) transform matrix - det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]); - imb[0] = m1[3] * det; - imb[1] = -m1[1] * det; - imb[2] = -m1[2] * det; - imb[3] = m1[0] * det; - imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det; - imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det; - - // save current graphics state - savedPath = state->getPath()->copy(); - saveState(); - - // set underlying color space (for uncolored tiling patterns); set - // various other parameters (stroke color, line width) to match - // Adobe's behavior - if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) { - state->setFillColorSpace(cs->copy()); - out->updateFillColorSpace(state); - state->setStrokeColorSpace(cs->copy()); - out->updateStrokeColorSpace(state); - state->setStrokeColor(state->getFillColor()); - } else { - state->setFillColorSpace(new GfxDeviceGrayColorSpace()); - out->updateFillColorSpace(state); - state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); - out->updateStrokeColorSpace(state); - } - state->setFillPattern(NULL); - out->updateFillColor(state); - state->setStrokePattern(NULL); - out->updateStrokeColor(state); - state->setLineWidth(0); - out->updateLineWidth(state); - - // clip to current path - state->clip(); - if (eoFill) { - out->eoClip(state); - } else { - out->clip(state); - } - state->clearPath(); - - // get the clip region, check for empty - state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax); - if (cxMin > cxMax || cyMin > cyMax) { - goto err; - } - - // transform clip region bbox to pattern space - xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4]; - yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5]; - x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4]; - y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5]; - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4]; - y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5]; - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4]; - y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5]; - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - - // draw the pattern - //~ this should treat negative steps differently -- start at right/top - //~ edge instead of left/bottom (?) - xstep = fabs(tPat->getXStep()); - ystep = fabs(tPat->getYStep()); - xi0 = (int)floor((xMin - tPat->getBBox()[0]) / xstep); - xi1 = (int)ceil((xMax - tPat->getBBox()[0]) / xstep); - yi0 = (int)floor((yMin - tPat->getBBox()[1]) / ystep); - yi1 = (int)ceil((yMax - tPat->getBBox()[1]) / ystep); - for (i = 0; i < 4; ++i) { - m1[i] = m[i]; - } - if (out->useTilingPatternFill()) { - m1[4] = m[4]; - m1[5] = m[5]; - out->tilingPatternFill(state, tPat->getContentStream(), - tPat->getPaintType(), tPat->getResDict(), - m1, tPat->getBBox(), - xi0, yi0, xi1, yi1, xstep, ystep); - } else { - for (yi = yi0; yi < yi1; ++yi) { - for (xi = xi0; xi < xi1; ++xi) { - x = xi * xstep; - y = yi * ystep; - m1[4] = x * m[0] + y * m[2] + m[4]; - m1[5] = x * m[1] + y * m[3] + m[5]; - doForm1(tPat->getContentStream(), tPat->getResDict(), - m1, tPat->getBBox()); - } - } - } - - // restore graphics state - err: - restoreState(); - state->setPath(savedPath); -} - -void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) { - GfxShading *shading; - GfxPath *savedPath; - double *ctm, *btm, *ptm; - double m[6], ictm[6], m1[6]; - double xMin, yMin, xMax, yMax; - double det; - - shading = sPat->getShading(); - - // save current graphics state - savedPath = state->getPath()->copy(); - saveState(); - - // clip to bbox - if (shading->getHasBBox()) { - shading->getBBox(&xMin, &yMin, &xMax, &yMax); - state->moveTo(xMin, yMin); - state->lineTo(xMax, yMin); - state->lineTo(xMax, yMax); - state->lineTo(xMin, yMax); - state->closePath(); - state->clip(); - out->clip(state); - state->setPath(savedPath->copy()); - } - - // clip to current path - state->clip(); - if (eoFill) { - out->eoClip(state); - } else { - out->clip(state); - } - - // set the color space - state->setFillColorSpace(shading->getColorSpace()->copy()); - out->updateFillColorSpace(state); - - // background color fill - if (shading->getHasBackground()) { - state->setFillColor(shading->getBackground()); - out->updateFillColor(state); - out->fill(state); - } - state->clearPath(); - - // construct a (pattern space) -> (current space) transform matrix - ctm = state->getCTM(); - btm = baseMatrix; - ptm = sPat->getMatrix(); - // iCTM = invert CTM - det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); - ictm[0] = ctm[3] * det; - ictm[1] = -ctm[1] * det; - ictm[2] = -ctm[2] * det; - ictm[3] = ctm[0] * det; - ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; - ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; - // m1 = PTM * BTM = PTM * base transform matrix - m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2]; - m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3]; - m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2]; - m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3]; - m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4]; - m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5]; - // m = m1 * iCTM = (PTM * BTM) * (iCTM) - m[0] = m1[0] * ictm[0] + m1[1] * ictm[2]; - m[1] = m1[0] * ictm[1] + m1[1] * ictm[3]; - m[2] = m1[2] * ictm[0] + m1[3] * ictm[2]; - m[3] = m1[2] * ictm[1] + m1[3] * ictm[3]; - m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; - m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; - - // set the new matrix - state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]); - out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]); - - // do shading type-specific operations - switch (shading->getType()) { - case 1: - doFunctionShFill((GfxFunctionShading *)shading); - break; - case 2: - doAxialShFill((GfxAxialShading *)shading); - break; - case 3: - doRadialShFill((GfxRadialShading *)shading); - break; - case 4: - case 5: - doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading); - break; - case 6: - case 7: - doPatchMeshShFill((GfxPatchMeshShading *)shading); - break; - } - - // restore graphics state - restoreState(); - state->setPath(savedPath); -} - -void Gfx::opShFill(Object args[], int /*numArgs*/) { - GfxShading *shading; - GfxPath *savedPath; - double xMin, yMin, xMax, yMax; - - if (!(shading = res->lookupShading(args[0].getName()))) { - return; - } - - // save current graphics state - savedPath = state->getPath()->copy(); - saveState(); - - // clip to bbox - if (shading->getHasBBox()) { - shading->getBBox(&xMin, &yMin, &xMax, &yMax); - state->moveTo(xMin, yMin); - state->lineTo(xMax, yMin); - state->lineTo(xMax, yMax); - state->lineTo(xMin, yMax); - state->closePath(); - state->clip(); - out->clip(state); - state->clearPath(); - } - - // set the color space - state->setFillColorSpace(shading->getColorSpace()->copy()); - out->updateFillColorSpace(state); - - // do shading type-specific operations - switch (shading->getType()) { - case 1: - doFunctionShFill((GfxFunctionShading *)shading); - break; - case 2: - doAxialShFill((GfxAxialShading *)shading); - break; - case 3: - doRadialShFill((GfxRadialShading *)shading); - break; - case 4: - case 5: - doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading); - break; - case 6: - case 7: - doPatchMeshShFill((GfxPatchMeshShading *)shading); - break; - } - - // restore graphics state - restoreState(); - state->setPath(savedPath); - - delete shading; -} - -void Gfx::doFunctionShFill(GfxFunctionShading *shading) { - double x0, y0, x1, y1; - GfxColor colors[4]; - - if (out->useShadedFills()) { - out->functionShadedFill(state, shading); - } else { - shading->getDomain(&x0, &y0, &x1, &y1); - shading->getColor(x0, y0, &colors[0]); - shading->getColor(x0, y1, &colors[1]); - shading->getColor(x1, y0, &colors[2]); - shading->getColor(x1, y1, &colors[3]); - doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0); - } -} - -void Gfx::doFunctionShFill1(GfxFunctionShading *shading, - double x0, double y0, - double x1, double y1, - GfxColor *colors, int depth) { - GfxColor fillColor; - GfxColor color0M, color1M, colorM0, colorM1, colorMM; - GfxColor colors2[4]; - double *matrix; - double xM, yM; - int nComps, i, j; - - nComps = shading->getColorSpace()->getNComps(); - matrix = shading->getMatrix(); - - // compare the four corner colors - for (i = 0; i < 4; ++i) { - for (j = 0; j < nComps; ++j) { - if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) { - break; - } - } - if (j < nComps) { - break; - } - } - - // center of the rectangle - xM = 0.5 * (x0 + x1); - yM = 0.5 * (y0 + y1); - - // the four corner colors are close (or we hit the recursive limit) - // -- fill the rectangle; but require at least one subdivision - // (depth==0) to avoid problems when the four outer corners of the - // shaded region are the same color - if ((i == 4 && depth > 0) || depth == functionMaxDepth) { - - // use the center color - shading->getColor(xM, yM, &fillColor); - state->setFillColor(&fillColor); - out->updateFillColor(state); - - // fill the rectangle - state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4], - x0 * matrix[1] + y0 * matrix[3] + matrix[5]); - state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4], - x1 * matrix[1] + y0 * matrix[3] + matrix[5]); - state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4], - x1 * matrix[1] + y1 * matrix[3] + matrix[5]); - state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4], - x0 * matrix[1] + y1 * matrix[3] + matrix[5]); - state->closePath(); - out->fill(state); - state->clearPath(); - - // the four corner colors are not close enough -- subdivide the - // 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 Gfx::doAxialShFill(GfxAxialShading *shading) { - double xMin, yMin, xMax, yMax; - double x0, y0, x1, y1; - double dx, dy, mul; - GBool dxZero, dyZero; - double tMin, tMax, t, tx, ty; - double s[4], sMin, sMax, tmp; - double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1; - double t0, t1, tt; - double ta[axialMaxSplits + 1]; - int next[axialMaxSplits + 1]; - GfxColor color0, color1; - int nComps; - int i, j, k, kk; - - if (out->useShadedFills()) { - - out->axialShadedFill(state, shading); - - } else { - - // get the clip region bbox - state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - - // compute min and max t values, based on the four corners of the - // clip region bbox - shading->getCoords(&x0, &y0, &x1, &y1); - dx = x1 - x0; - dy = y1 - y0; - dxZero = fabs(dx) < 0.001; - dyZero = fabs(dy) < 0.001; - mul = 1 / (dx * dx + dy * dy); - tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; - t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; - if (t < tMin) { - tMin = t; - } else if (t > tMax) { - tMax = t; - } - t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul; - if (t < tMin) { - tMin = t; - } else if (t > tMax) { - tMax = t; - } - t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul; - if (t < tMin) { - tMin = t; - } else if (t > tMax) { - tMax = t; - } - if (tMin < 0 && !shading->getExtend0()) { - tMin = 0; - } - if (tMax > 1 && !shading->getExtend1()) { - tMax = 1; - } - - // get the function domain - t0 = shading->getDomain0(); - t1 = shading->getDomain1(); - - // Traverse the t axis and do the shading. - // - // For each point (tx, ty) on the t axis, consider a line through - // that point perpendicular to the t axis: - // - // x(s) = tx + s * -dy --> s = (x - tx) / -dy - // y(s) = ty + s * dx --> s = (y - ty) / dx - // - // Then look at the intersection of this line with the bounding box - // (xMin, yMin, xMax, yMax). In the general case, there are four - // intersection points: - // - // s0 = (xMin - tx) / -dy - // s1 = (xMax - tx) / -dy - // s2 = (yMin - ty) / dx - // s3 = (yMax - ty) / dx - // - // and we want the middle two s values. - // - // In the case where dx = 0, take s0 and s1; in the case where dy = - // 0, take s2 and s3. - // - // Each filled polygon is bounded by two of these line segments - // perpdendicular to the t axis. - // - // The t axis is bisected into smaller regions until the color - // difference across a region is small enough, and then the region - // is painted with a single color. - - // set up: require at least one split to avoid problems when the two - // ends of the t axis have the same color - nComps = shading->getColorSpace()->getNComps(); - ta[0] = tMin; - next[0] = axialMaxSplits / 2; - ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax); - next[axialMaxSplits / 2] = axialMaxSplits; - ta[axialMaxSplits] = tMax; - - // compute the color at t = tMin - if (tMin < 0) { - tt = t0; - } else if (tMin > 1) { - tt = t1; - } else { - tt = t0 + (t1 - t0) * tMin; - } - shading->getColor(tt, &color0); - - // compute the coordinates of the point on the t axis at t = tMin; - // then compute the intersection of the perpendicular line with the - // bounding box - tx = x0 + tMin * dx; - ty = y0 + tMin * dy; - if (dxZero && dyZero) { - sMin = sMax = 0; - } if (dxZero) { - sMin = (xMin - tx) / -dy; - sMax = (xMax - tx) / -dy; - if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } - } else if (dyZero) { - sMin = (yMin - ty) / dx; - sMax = (yMax - ty) / dx; - if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } - } else { - s[0] = (yMin - ty) / dx; - s[1] = (yMax - ty) / dx; - s[2] = (xMin - tx) / -dy; - s[3] = (xMax - tx) / -dy; - for (j = 0; j < 3; ++j) { - kk = j; - for (k = j + 1; k < 4; ++k) { - if (s[k] < s[kk]) { - kk = k; - } - } - tmp = s[j]; s[j] = s[kk]; s[kk] = tmp; - } - sMin = s[1]; - sMax = s[2]; - } - ux0 = tx - sMin * dy; - uy0 = ty + sMin * dx; - vx0 = tx - sMax * dy; - vy0 = ty + sMax * dx; - - i = 0; - while (i < axialMaxSplits) { - - // bisect until color difference is small enough or we hit the - // bisection limit - j = next[i]; - while (j > i + 1) { - if (ta[j] < 0) { - tt = t0; - } else if (ta[j] > 1) { - tt = t1; - } else { - tt = t0 + (t1 - t0) * ta[j]; - } - shading->getColor(tt, &color1); - for (k = 0; k < nComps; ++k) { - if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) { - break; - } - } - if (k == nComps) { - break; - } - k = (i + j) / 2; - ta[k] = 0.5 * (ta[i] + ta[j]); - next[i] = k; - next[k] = j; - j = k; - } - - // use the average of the colors of the two sides of the region - for (k = 0; k < nComps; ++k) { - color0.c[k] = (color0.c[k] + color1.c[k]) / 2; - } - - // compute the coordinates of the point on the t axis; then - // compute the intersection of the perpendicular line with the - // bounding box - tx = x0 + ta[j] * dx; - ty = y0 + ta[j] * dy; - if (dxZero && dyZero) { - sMin = sMax = 0; - } if (dxZero) { - sMin = (xMin - tx) / -dy; - sMax = (xMax - tx) / -dy; - if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } - } else if (dyZero) { - sMin = (yMin - ty) / dx; - sMax = (yMax - ty) / dx; - if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } - } else { - s[0] = (yMin - ty) / dx; - s[1] = (yMax - ty) / dx; - s[2] = (xMin - tx) / -dy; - s[3] = (xMax - tx) / -dy; - for (j = 0; j < 3; ++j) { - kk = j; - for (k = j + 1; k < 4; ++k) { - if (s[k] < s[kk]) { - kk = k; - } - } - tmp = s[j]; s[j] = s[kk]; s[kk] = tmp; - } - sMin = s[1]; - sMax = s[2]; - } - ux1 = tx - sMin * dy; - uy1 = ty + sMin * dx; - vx1 = tx - sMax * dy; - vy1 = ty + sMax * dx; - - // set the color - state->setFillColor(&color0); - out->updateFillColor(state); - - // fill the region - state->moveTo(ux0, uy0); - state->lineTo(vx0, vy0); - state->lineTo(vx1, vy1); - state->lineTo(ux1, uy1); - state->closePath(); - out->fill(state); - state->clearPath(); - - // set up for next region - ux0 = ux1; - uy0 = uy1; - vx0 = vx1; - vy0 = vy1; - color0 = color1; - i = next[i]; - } - } -} - -void Gfx::doRadialShFill(GfxRadialShading *shading) { - double sMin, sMax, xMin, yMin, xMax, yMax; - double x0, y0, r0, x1, y1, r1, t0, t1; - int nComps; - GfxColor colorA, colorB; - double xa, ya, xb, yb, ra, rb; - double ta, tb, sa, sb; - int ia, ib, k, n; - double *ctm; - double angle, t, d0, d1; - - if (out->useShadedFills()) { - - out->radialShadedFill(state, shading); - - } else { - - // get the shading info - shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); - t0 = shading->getDomain0(); - t1 = shading->getDomain1(); - nComps = shading->getColorSpace()->getNComps(); - - // compute the (possibly extended) s range - sMin = 0; - sMax = 1; - if (shading->getExtend0()) { - if (r0 < r1) { - // extend the smaller end - sMin = -r0 / (r1 - r0); - } else { - // extend the larger end - state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - d0 = (x0 - xMin) * (x0 - xMin); - d1 = (x0 - xMax) * (x0 - xMax); - sMin = d0 > d1 ? d0 : d1; - d0 = (y0 - yMin) * (y0 - yMin); - d1 = (y0 - yMax) * (y0 - yMax); - sMin += d0 > d1 ? d0 : d1; - sMin = (sqrt(sMin) - r0) / (r1 - r0); - if (sMin > 0) { - sMin = 0; - } else if (sMin < -20) { - // sanity check - sMin = -20; - } - } - } - if (shading->getExtend1()) { - if (r1 < r0) { - // extend the smaller end - sMax = -r0 / (r1 - r0); - } else if (r1 > r0) { - // extend the larger end - state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - d0 = (x1 - xMin) * (x1 - xMin); - d1 = (x1 - xMax) * (x1 - xMax); - sMax = d0 > d1 ? d0 : d1; - d0 = (y1 - yMin) * (y1 - yMin); - d1 = (y1 - yMax) * (y1 - yMax); - sMax += d0 > d1 ? d0 : d1; - sMax = (sqrt(sMax) - r0) / (r1 - r0); - if (sMax < 1) { - sMax = 1; - } else if (sMax > 20) { - // sanity check - sMax = 20; - } - } - } - - // compute the number of steps into which circles must be divided to - // achieve a curve flatness of 0.1 pixel in device space for the - // largest circle (note that "device space" is 72 dpi when generating - // PostScript, hence the relatively small 0.1 pixel accuracy) - ctm = state->getCTM(); - t = fabs(ctm[0]); - if (fabs(ctm[1]) > t) { - t = fabs(ctm[1]); - } - if (fabs(ctm[2]) > t) { - t = fabs(ctm[2]); - } - if (fabs(ctm[3]) > t) { - t = fabs(ctm[3]); - } - if (r0 > r1) { - t *= r0; - } else { - t *= r1; - } - if (t < 1) { - n = 3; - } else { - n = (int)(M_PI / acos(1 - 0.1 / t)); - if (n < 3) { - n = 3; - } else if (n > 200) { - n = 200; - } - } - - // Traverse the t axis and do the shading. - // - // This generates and fills a series of rings. Each ring is defined - // by two circles: - // sa, ta, xa, ya, ra, colorA - // sb, tb, xb, yb, rb, colorB - // - // The s/t axis is divided into radialMaxSplits parts; these parts - // are combined as much as possible while respecting the - // radialColorDelta parameter. - - // setup for the start circle - ia = 0; - sa = sMin; - ta = t0 + sa * (t1 - t0); - xa = x0 + sa * (x1 - x0); - ya = y0 + sa * (y1 - y0); - ra = r0 + sa * (r1 - r0); - if (ta < t0) { - shading->getColor(t0, &colorA); - } else if (ta > t1) { - shading->getColor(t1, &colorA); - } else { - shading->getColor(ta, &colorA); - } - - while (ia < radialMaxSplits) { - - // go as far along the t axis (toward t1) as we can, such that the - // color difference is within the tolerance (radialColorDelta) -- - // this uses bisection (between the current value, t, and t1), - // limited to radialMaxSplits points along the t axis; require at - // least one split to avoid problems when the innermost and - // outermost colors are the same - ib = radialMaxSplits; - sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin); - tb = t0 + sb * (t1 - t0); - if (tb < t0) { - shading->getColor(t0, &colorB); - } else if (tb > t1) { - shading->getColor(t1, &colorB); - } else { - shading->getColor(tb, &colorB); - } - while (ib - ia > 1) { - for (k = 0; k < nComps; ++k) { - if (abs(colorB.c[k] - colorA.c[k]) > radialColorDelta) { - break; - } - } - if (k == nComps && ib < radialMaxSplits) { - break; - } - ib = (ia + ib) / 2; - sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin); - tb = t0 + sb * (t1 - t0); - if (tb < t0) { - shading->getColor(t0, &colorB); - } else if (tb > t1) { - shading->getColor(t1, &colorB); - } else { - shading->getColor(tb, &colorB); - } - } - - // compute center and radius of the circle - xb = x0 + sb * (x1 - x0); - yb = y0 + sb * (y1 - y0); - rb = r0 + sb * (r1 - r0); - - // use the average of the colors at the two circles - for (k = 0; k < nComps; ++k) { - colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2; - } - state->setFillColor(&colorA); - out->updateFillColor(state); - - // construct path for first circle - state->moveTo(xa + ra, ya); - for (k = 1; k < n; ++k) { - angle = ((double)k / (double)n) * 2 * M_PI; - state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); - } - state->closePath(); - - // construct and append path for second circle - state->moveTo(xb + rb, yb); - for (k = 1; k < n; ++k) { - angle = ((double)k / (double)n) * 2 * M_PI; - state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); - } - state->closePath(); - - // fill the ring - out->eoFill(state); - state->clearPath(); - - // step to the next value of t - ia = ib; - sa = sb; - ta = tb; - xa = xb; - ya = yb; - ra = rb; - colorA = colorB; - } - } -} - -void Gfx::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 Gfx::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; - 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 == gouraudMaxDepth) { - state->setFillColor(color0); - out->updateFillColor(state); - state->moveTo(x0, y0); - state->lineTo(x1, y1); - state->lineTo(x2, y2); - state->closePath(); - out->fill(state); - 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 Gfx::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 Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) { - GfxPatch patch00, patch01, patch10, patch11; - double xx[4][8], yy[4][8]; - double xxm, yym; - 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; - } - } - if (i == nComps || depth == patchMaxDepth) { - state->setFillColor(&patch->color[0][0]); - out->updateFillColor(state); - 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(); - out->fill(state); - 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 Gfx::doEndPath() { - if (state->isCurPt() && clip != clipNone) { - state->clip(); - if (clip == clipNormal) { - out->clip(state); - } else { - out->eoClip(state); - } - } - clip = clipNone; - state->clearPath(); -} - -//------------------------------------------------------------------------ -// path clipping operators -//------------------------------------------------------------------------ - -void Gfx::opClip(Object */*args*/, int /*numArgs*/) { - clip = clipNormal; -} - -void Gfx::opEOClip(Object */*args*/, int /*numArgs*/) { - clip = clipEO; -} - -//------------------------------------------------------------------------ -// text object operators -//------------------------------------------------------------------------ - -void Gfx::opBeginText(Object */*args*/, int /*numArgs*/) { - state->setTextMat(1, 0, 0, 1, 0, 0); - state->textMoveTo(0, 0); - out->updateTextMat(state); - out->updateTextPos(state); - fontChanged = gTrue; -} - -void Gfx::opEndText(Object */*args*/, int /*numArgs*/) { - out->endTextObject(state); -} - -//------------------------------------------------------------------------ -// text state operators -//------------------------------------------------------------------------ - -void Gfx::opSetCharSpacing(Object args[], int /*numArgs*/) { - state->setCharSpace(args[0].getNum()); - out->updateCharSpace(state); -} - -void Gfx::opSetFont(Object args[], int /*numArgs*/) { - GfxFont *font; - - if (!(font = res->lookupFont(args[0].getName()))) { - return; - } - if (printCommands) { - printf(" font: tag=%s name='%s' %g\n", - font->getTag()->getCString(), - font->getName() ? font->getName()->getCString() : "???", - args[1].getNum()); - fflush(stdout); - } - state->setFont(font, args[1].getNum()); - fontChanged = gTrue; -} - -void Gfx::opSetTextLeading(Object args[], int /*numArgs*/) { - state->setLeading(args[0].getNum()); -} - -void Gfx::opSetTextRender(Object args[], int /*numArgs*/) { - state->setRender(args[0].getInt()); - out->updateRender(state); -} - -void Gfx::opSetTextRise(Object args[], int /*numArgs*/) { - state->setRise(args[0].getNum()); - out->updateRise(state); -} - -void Gfx::opSetWordSpacing(Object args[], int /*numArgs*/) { - state->setWordSpace(args[0].getNum()); - out->updateWordSpace(state); -} - -void Gfx::opSetHorizScaling(Object args[], int /*numArgs*/) { - state->setHorizScaling(args[0].getNum()); - out->updateHorizScaling(state); - fontChanged = gTrue; -} - -//------------------------------------------------------------------------ -// text positioning operators -//------------------------------------------------------------------------ - -void Gfx::opTextMove(Object args[], int /*numArgs*/) { - double tx, ty; - - tx = state->getLineX() + args[0].getNum(); - ty = state->getLineY() + args[1].getNum(); - state->textMoveTo(tx, ty); - out->updateTextPos(state); -} - -void Gfx::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); - out->updateTextPos(state); -} - -void Gfx::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); - out->updateTextMat(state); - out->updateTextPos(state); - fontChanged = gTrue; -} - -void Gfx::opTextNextLine(Object */*args*/, int /*numArgs*/) { - double tx, ty; - - tx = state->getLineX(); - ty = state->getLineY() - state->getLeading(); - state->textMoveTo(tx, ty); - out->updateTextPos(state); -} - -//------------------------------------------------------------------------ -// text string operators -//------------------------------------------------------------------------ - -void Gfx::opShowText(Object args[], int /*numArgs*/) { - if (!state->getFont()) { - error(getPos(), "No font in show"); - return; - } - if (fontChanged) { - out->updateFont(state); - fontChanged = gFalse; - } - out->beginStringOp(state); - doShowText(args[0].getString()); - out->endStringOp(state); -} - -void Gfx::opMoveShowText(Object args[], int /*numArgs*/) { - double tx, ty; - - if (!state->getFont()) { - error(getPos(), "No font in move/show"); - return; - } - if (fontChanged) { - out->updateFont(state); - fontChanged = gFalse; - } - tx = state->getLineX(); - ty = state->getLineY() - state->getLeading(); - state->textMoveTo(tx, ty); - out->updateTextPos(state); - out->beginStringOp(state); - doShowText(args[0].getString()); - out->endStringOp(state); -} - -void Gfx::opMoveSetShowText(Object args[], int /*numArgs*/) { - double tx, ty; - - if (!state->getFont()) { - error(getPos(), "No font in move/set/show"); - return; - } - if (fontChanged) { - out->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); - out->updateWordSpace(state); - out->updateCharSpace(state); - out->updateTextPos(state); - out->beginStringOp(state); - doShowText(args[2].getString()); - out->endStringOp(state); -} - -void Gfx::opShowSpaceText(Object args[], int /*numArgs*/) { - Array *a; - Object obj; - int wMode; - int i; - - if (!state->getFont()) { - error(getPos(), "No font in show/space"); - return; - } - if (fontChanged) { - out->updateFont(state); - fontChanged = gFalse; - } - out->beginStringOp(state); - wMode = state->getFont()->getWMode(); - a = args[0].getArray(); - for (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); - } - out->updateTextShift(state, obj.getNum()); - } else if (obj.isString()) { - doShowText(obj.getString()); - } else { - error(getPos(), "Element of show/space array must be number or string"); - } - obj.free(); - } - out->endStringOp(state); -} - -void Gfx::doShowText(GString *s) { - GfxFont *font; - int wMode; - double riseX, riseY; - CharCode code; - Unicode u[8]; - double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, lineX, lineY; - double originX, originY, tOriginX, tOriginY; - double oldCTM[6], newCTM[6]; - double *mat; - Object charProc; - Dict *resDict; - Parser *oldParser; - char *p; - int len, n, uLen, nChars, nSpaces, i; - - font = state->getFont(); - wMode = font->getWMode(); - - if (out->useDrawChar()) { - out->beginString(state, s); - } - - // handle a Type 3 char - if (font->getType() == fontType3 && out->interpretType3Chars()) { - mat = state->getCTM(); - for (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); - curX = state->getCurX(); - curY = state->getCurY(); - lineX = state->getLineX(); - lineY = state->getLineY(); - oldParser = parser; - p = s->getCString(); - len = s->getLength(); - while (len > 0) { - n = font->getNextChar(p, len, &code, - u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, - &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); - //~ out->updateCTM(???) - if (!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()) { - display(&charProc, gFalse); - } else { - error(getPos(), "Missing or bad Type3 CharProc entry"); - } - 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 if (out->useDrawChar()) { - state->textTransformDelta(0, state->getRise(), &riseX, &riseY); - p = s->getCString(); - len = s->getLength(); - while (len > 0) { - n = font->getNextChar(p, len, &code, - u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, - &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); - out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY, - tdx, tdy, tOriginX, tOriginY, code, n, u, uLen); - state->shift(tdx, tdy); - p += n; - len -= n; - } - - } else { - dx = dy = 0; - p = s->getCString(); - len = s->getLength(); - nChars = nSpaces = 0; - while (len > 0) { - n = font->getNextChar(p, len, &code, - u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, - &dx2, &dy2, &originX, &originY); - dx += dx2; - dy += dy2; - if (n == 1 && *p == ' ') { - ++nSpaces; - } - ++nChars; - p += n; - len -= n; - } - if (wMode) { - dx *= state->getFontSize(); - dy = dy * state->getFontSize() - + nChars * state->getCharSpace() - + nSpaces * state->getWordSpace(); - } else { - dx = dx * state->getFontSize() - + nChars * state->getCharSpace() - + nSpaces * state->getWordSpace(); - dx *= state->getHorizScaling(); - dy *= state->getFontSize(); - } - state->textTransformDelta(dx, dy, &tdx, &tdy); - out->drawString(state, s); - state->shift(tdx, tdy); - } - - if (out->useDrawChar()) { - out->endString(state); - } - - updateLevel += 10 * s->getLength(); -} - -//------------------------------------------------------------------------ -// XObject operators -//------------------------------------------------------------------------ - -void Gfx::opXObject(Object args[], int /*numArgs*/) { - Object obj1, obj2, obj3, refObj; -#if OPI_SUPPORT - Object opiDict; -#endif - - if (!res->lookupXObject(args[0].getName(), &obj1)) { - return; - } - if (!obj1.isStream()) { - error(getPos(), "XObject '%s' is wrong type", args[0].getName()); - obj1.free(); - return; - } -#if OPI_SUPPORT - obj1.streamGetDict()->lookup("OPI", &opiDict); - if (opiDict.isDict()) { - out->opiBegin(state, opiDict.getDict()); - } -#endif - obj1.streamGetDict()->lookup("Subtype", &obj2); - if (obj2.isName("Image")) { - if (out->needNonText()) { - res->lookupXObjectNF(args[0].getName(), &refObj); - doImage(&refObj, obj1.getStream(), gFalse); - refObj.free(); - } - } else if (obj2.isName("Form")) { - doForm(&obj1); - } else if (obj2.isName("PS")) { - obj1.streamGetDict()->lookup("Level1", &obj3); - out->psXObject(obj1.getStream(), - obj3.isStream() ? obj3.getStream() : (Stream *)NULL); - } else if (obj2.isName()) { - error(getPos(), "Unknown XObject subtype '%s'", obj2.getName()); - } else { - error(getPos(), "XObject subtype is missing or wrong type"); - } - obj2.free(); -#if OPI_SUPPORT - if (opiDict.isDict()) { - out->opiEnd(state, opiDict.getDict()); - } - opiDict.free(); -#endif - obj1.free(); -} - -void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { - Dict *dict, *maskDict; - int width, height; - int bits, maskBits; - StreamColorSpaceMode csMode; - GBool mask; - GBool invert; - GfxColorSpace *colorSpace, *maskColorSpace; - GfxImageColorMap *colorMap, *maskColorMap; - Object maskObj, smaskObj; - GBool haveColorKeyMask, haveExplicitMask, haveSoftMask; - int maskColors[2*gfxColorMaxComps]; - int maskWidth, maskHeight; - GBool maskInvert; - Stream *maskStr; - Object obj1, obj2; - int i; - - // get info from the stream - bits = 0; - csMode = streamCSNone; - str->getImageParams(&bits, &csMode); - - // get stream dict - dict = str->getDict(); - - // get size - dict->lookup("Width", &obj1); - if (obj1.isNull()) { - obj1.free(); - dict->lookup("W", &obj1); - } - if (!obj1.isInt()) - goto err2; - width = obj1.getInt(); - obj1.free(); - dict->lookup("Height", &obj1); - if (obj1.isNull()) { - obj1.free(); - dict->lookup("H", &obj1); - } - if (!obj1.isInt()) - goto err2; - height = obj1.getInt(); - obj1.free(); - - // image or mask? - dict->lookup("ImageMask", &obj1); - if (obj1.isNull()) { - obj1.free(); - dict->lookup("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("BitsPerComponent", &obj1); - if (obj1.isNull()) { - obj1.free(); - dict->lookup("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("Decode", &obj1); - if (obj1.isNull()) { - obj1.free(); - dict->lookup("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 - out->drawImageMask(state, ref, str, width, height, invert, inlineImg); - - } else { - - // get color space and color map - dict->lookup("ColorSpace", &obj1); - if (obj1.isNull()) { - obj1.free(); - dict->lookup("CS", &obj1); - } - if (obj1.isName()) { - res->lookupColorSpace(obj1.getName(), &obj2); - if (!obj2.isNull()) { - obj1.free(); - obj1 = obj2; - } else { - obj2.free(); - } - } - if (!obj1.isNull()) { - colorSpace = GfxColorSpace::parse(&obj1); - } 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("Decode", &obj1); - if (obj1.isNull()) { - obj1.free(); - dict->lookup("D", &obj1); - } - colorMap = new GfxImageColorMap(bits, &obj1, colorSpace); - obj1.free(); - if (!colorMap->isOk()) { - delete colorMap; - goto err1; - } - - // get the mask - haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse; - maskStr = NULL; // make gcc happy - maskWidth = maskHeight = 0; // make gcc happy - maskInvert = gFalse; // make gcc happy - maskColorMap = NULL; // make gcc happy - dict->lookup("Mask", &maskObj); - dict->lookup("SMask", &smaskObj); - if (smaskObj.isStream()) { - // soft mask - if (inlineImg) { - goto err1; - } - maskStr = smaskObj.getStream(); - maskDict = smaskObj.streamGetDict(); - maskDict->lookup("Width", &obj1); - if (obj1.isNull()) { - obj1.free(); - maskDict->lookup("W", &obj1); - } - if (!obj1.isInt()) { - goto err2; - } - maskWidth = obj1.getInt(); - obj1.free(); - maskDict->lookup("Height", &obj1); - if (obj1.isNull()) { - obj1.free(); - maskDict->lookup("H", &obj1); - } - if (!obj1.isInt()) { - goto err2; - } - maskHeight = obj1.getInt(); - obj1.free(); - maskDict->lookup("BitsPerComponent", &obj1); - if (obj1.isNull()) { - obj1.free(); - maskDict->lookup("BPC", &obj1); - } - if (!obj1.isInt()) { - goto err2; - } - maskBits = obj1.getInt(); - obj1.free(); - maskDict->lookup("ColorSpace", &obj1); - if (obj1.isNull()) { - obj1.free(); - maskDict->lookup("CS", &obj1); - } - if (obj1.isName()) { - res->lookupColorSpace(obj1.getName(), &obj2); - if (!obj2.isNull()) { - obj1.free(); - obj1 = obj2; - } else { - obj2.free(); - } - } - maskColorSpace = GfxColorSpace::parse(&obj1); - obj1.free(); - if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) { - goto err1; - } - maskDict->lookup("Decode", &obj1); - if (obj1.isNull()) { - obj1.free(); - maskDict->lookup("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 - 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("Width", &obj1); - if (obj1.isNull()) { - obj1.free(); - maskDict->lookup("W", &obj1); - } - if (!obj1.isInt()) { - goto err2; - } - maskWidth = obj1.getInt(); - obj1.free(); - maskDict->lookup("Height", &obj1); - if (obj1.isNull()) { - obj1.free(); - maskDict->lookup("H", &obj1); - } - if (!obj1.isInt()) { - goto err2; - } - maskHeight = obj1.getInt(); - obj1.free(); - maskDict->lookup("ImageMask", &obj1); - if (obj1.isNull()) { - obj1.free(); - maskDict->lookup("IM", &obj1); - } - if (!obj1.isBool() || !obj1.getBool()) { - goto err2; - } - obj1.free(); - maskInvert = gFalse; - maskDict->lookup("Decode", &obj1); - if (obj1.isNull()) { - obj1.free(); - maskDict->lookup("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) { - out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, - maskStr, maskWidth, maskHeight, maskColorMap); - delete maskColorMap; - } else if (haveExplicitMask) { - out->drawMaskedImage(state, ref, str, width, height, colorMap, - maskStr, maskWidth, maskHeight, maskInvert); - } else { - out->drawImage(state, ref, str, width, height, colorMap, - haveColorKeyMask ? maskColors : (int *)NULL, inlineImg); - } - delete colorMap; - - maskObj.free(); - smaskObj.free(); - } - - if ((i = width * height) > 1000) { - i = 1000; - } - updateLevel += i; - - return; - - err2: - obj1.free(); - err1: - error(getPos(), "Bad image parameters"); -} - -void Gfx::doForm(Object *str) { - Dict *dict; - Object matrixObj, bboxObj; - double m[6], bbox[6]; - Object resObj; - Dict *resDict; - Object obj1; - int i; - - // check for excessive recursion - if (formDepth > 20) { - return; - } - - // get stream dict - dict = str->streamGetDict(); - - // check form type - dict->lookup("FormType", &obj1); - if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) { - error(getPos(), "Unknown form type"); - } - obj1.free(); - - // get bounding box - dict->lookup("BBox", &bboxObj); - if (!bboxObj.isArray()) { - matrixObj.free(); - bboxObj.free(); - error(getPos(), "Bad form bounding box"); - return; - } - for (i = 0; i < 4; ++i) { - bboxObj.arrayGet(i, &obj1); - bbox[i] = obj1.getNum(); - obj1.free(); - } - bboxObj.free(); - - // get matrix - dict->lookup("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("Resources", &resObj); - resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; - - // draw it - ++formDepth; - doForm1(str, resDict, m, bbox); - --formDepth; - - resObj.free(); -} - -void Gfx::doAnnot(Object *str, double xMin, double yMin, - double xMax, double yMax) { - Dict *dict, *resDict; - Object matrixObj, bboxObj, resObj; - Object obj1; - double m[6], bbox[6], ictm[6]; - double *ctm; - double formX0, formY0, formX1, formY1; - double annotX0, annotY0, annotX1, annotY1; - double det, x, y, sx, sy; - int i; - - // get stream dict - dict = str->streamGetDict(); - - // get the form bounding box - dict->lookup("BBox", &bboxObj); - if (!bboxObj.isArray()) { - bboxObj.free(); - error(getPos(), "Bad form bounding box"); - return; - } - for (i = 0; i < 4; ++i) { - bboxObj.arrayGet(i, &obj1); - bbox[i] = obj1.getNum(); - obj1.free(); - } - bboxObj.free(); - - // get the form matrix - dict->lookup("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(); - - // transform the form bbox from form space to user space - formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4]; - formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5]; - formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4]; - formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5]; - - // transform the annotation bbox from default user space to user - // space: (bbox * baseMatrix) * iCTM - ctm = state->getCTM(); - det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); - ictm[0] = ctm[3] * det; - ictm[1] = -ctm[1] * det; - ictm[2] = -ctm[2] * det; - ictm[3] = ctm[0] * det; - ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; - ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; - x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4]; - y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5]; - annotX0 = ictm[0] * x + ictm[2] * y + ictm[4]; - annotY0 = ictm[1] * x + ictm[3] * y + ictm[5]; - x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4]; - y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5]; - annotX1 = ictm[0] * x + ictm[2] * y + ictm[4]; - annotY1 = ictm[1] * x + ictm[3] * y + ictm[5]; - - // swap min/max coords - if (formX0 > formX1) { - x = formX0; formX0 = formX1; formX1 = x; - } - if (formY0 > formY1) { - y = formY0; formY0 = formY1; formY1 = y; - } - if (annotX0 > annotX1) { - x = annotX0; annotX0 = annotX1; annotX1 = x; - } - if (annotY0 > annotY1) { - y = annotY0; annotY0 = annotY1; annotY1 = y; - } - - // scale the form to fit the annotation bbox - if (formX1 == formX0) { - // this shouldn't happen - sx = 1; - } else { - sx = (annotX1 - annotX0) / (formX1 - formX0); - } - if (formY1 == formY0) { - // this shouldn't happen - sy = 1; - } else { - sy = (annotY1 - annotY0) / (formY1 - formY0); - } - m[0] *= sx; - m[2] *= sx; - m[4] = (m[4] - formX0) * sx + annotX0; - m[1] *= sy; - m[3] *= sy; - m[5] = (m[5] - formY0) * sy + annotY0; - - // get resources - dict->lookup("Resources", &resObj); - resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; - - // draw it - doForm1(str, resDict, m, bbox); - - resObj.free(); - bboxObj.free(); -} - -void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) { - 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(); - - // save current parser - oldParser = parser; - - // set form transformation matrix - state->concatCTM(matrix[0], matrix[1], matrix[2], - matrix[3], matrix[4], matrix[5]); - out->updateCTM(state, matrix[0], matrix[1], matrix[2], - matrix[3], matrix[4], matrix[5]); - - // set new base matrix - for (i = 0; i < 6; ++i) { - oldBaseMatrix[i] = baseMatrix[i]; - baseMatrix[i] = state->getCTM()[i]; - } - - // 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(); - out->clip(state); - state->clearPath(); - - // draw the form - display(str, gFalse); - - // restore base matrix - for (i = 0; i < 6; ++i) { - baseMatrix[i] = oldBaseMatrix[i]; - } - - // restore parser - parser = oldParser; - - // restore graphics state - restoreState(); - - // pop resource stack - popResources(); - - return; -} - -//------------------------------------------------------------------------ -// in-line image operators -//------------------------------------------------------------------------ - -void Gfx::opBeginImage(Object */*args*/, int /*numArgs*/) { - Stream *str; - int c1, c2; - - // build dict/stream - str = buildImageStream(); - - // display the image - if (str) { - doImage(NULL, str, gTrue); - - // skip 'EI' tag - c1 = str->getBaseStream()->getChar(); - c2 = str->getBaseStream()->getChar(); - while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) { - c1 = c2; - c2 = str->getBaseStream()->getChar(); - } - delete str; - } -} - -Stream *Gfx::buildImageStream() { - Object dict; - Object obj; - const char *key; - Stream *str; - - // build dictionary - dict.initDict(xref); - parser->getObj(&obj); - while (!obj.isCmd("ID") && !obj.isEOF()) { - if (!obj.isName()) { - error(getPos(), "Inline image dictionary key must be a name object"); - obj.free(); - } else { - key = copyString(obj.getName()); - obj.free(); - parser->getObj(&obj); - if (obj.isEOF() || obj.isError()) { - gfree((void*)key); - break; - } - dict.dictAdd(key, &obj); - gfree((void*)key); - } - parser->getObj(&obj); - } - if (obj.isEOF()) { - error(getPos(), "End of file in inline image"); - 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 Gfx::opImageData(Object */*args*/, int /*numArgs*/) { - error(getPos(), "Internal: got 'ID' operator"); -} - -void Gfx::opEndImage(Object */*args*/, int /*numArgs*/) { - error(getPos(), "Internal: got 'EI' operator"); -} - -//------------------------------------------------------------------------ -// type 3 font operators -//------------------------------------------------------------------------ - -void Gfx::opSetCharWidth(Object args[], int /*numArgs*/) { - out->type3D0(state, args[0].getNum(), args[1].getNum()); -} - -void Gfx::opSetCacheDevice(Object args[], int /*numArgs*/) { - out->type3D1(state, args[0].getNum(), args[1].getNum(), - args[2].getNum(), args[3].getNum(), - args[4].getNum(), args[5].getNum()); -} - -//------------------------------------------------------------------------ -// compatibility operators -//------------------------------------------------------------------------ - -void Gfx::opBeginIgnoreUndef(Object */*args*/, int /*numArgs*/) { - ++ignoreUndef; -} - -void Gfx::opEndIgnoreUndef(Object */*args*/, int /*numArgs*/) { - if (ignoreUndef > 0) - --ignoreUndef; -} - -//------------------------------------------------------------------------ -// marked content operators -//------------------------------------------------------------------------ - -void Gfx::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); - } -} - -void Gfx::opEndMarkedContent(Object */*args*/, int /*numArgs*/) { -} - -void Gfx::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); - } -} - -//------------------------------------------------------------------------ -// misc -//------------------------------------------------------------------------ - -void Gfx::saveState() { - out->saveState(state); - state = state->save(); -} - -void Gfx::restoreState() { - state = state->restore(); - out->restoreState(state); -} - -void Gfx::pushResources(Dict *resDict) { - res = new GfxResources(xref, resDict, res); -} - -void Gfx::popResources() { - GfxResources *resPtr; - - resPtr = res->getNext(); - delete res; - res = resPtr; -} diff --git a/xpdf/xpdf/Gfx.h b/xpdf/xpdf/Gfx.h deleted file mode 100644 index 4ab1dee80..000000000 --- a/xpdf/xpdf/Gfx.h +++ /dev/null @@ -1,293 +0,0 @@ -//======================================================================== -// -// Gfx.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef GFX_H -#define GFX_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -class GString; -class XRef; -class Array; -class Stream; -class Parser; -class Dict; -class OutputDev; -class GfxFontDict; -class GfxFont; -class GfxPattern; -class GfxTilingPattern; -class GfxShadingPattern; -class GfxShading; -class GfxFunctionShading; -class GfxAxialShading; -class GfxRadialShading; -class GfxGouraudTriangleShading; -class GfxPatchMeshShading; -struct GfxPatch; -class GfxState; -struct GfxColor; -class Gfx; -class PDFRectangle; - -//------------------------------------------------------------------------ -// Gfx -//------------------------------------------------------------------------ - -enum GfxClipType { - clipNone, - clipNormal, - clipEO -}; - -enum TchkType { - tchkBool, // boolean - tchkInt, // integer - tchkNum, // number (integer or real) - tchkString, // string - tchkName, // name - tchkArray, // array - tchkProps, // properties (dictionary or name) - tchkSCN, // scn/SCN args (number of name) - tchkNone // used to avoid empty initializer lists -}; - -#define maxArgs 8 - -struct Operator { - char name[4]; - int numArgs; - TchkType tchk[maxArgs]; - void (Gfx::*func)(Object args[], int numArgs); -}; - -class GfxResources { -public: - - GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA); - ~GfxResources(); - - GfxFont *lookupFont(const char *name); - GBool lookupXObject(const char *name, Object *obj); - GBool lookupXObjectNF(const char *name, Object *obj); - void lookupColorSpace(const char *name, Object *obj); - GfxPattern *lookupPattern(const char *name); - GfxShading *lookupShading(const char *name); - GBool lookupGState(const char *name, Object *obj); - - GfxResources *getNext() { return next; } - -private: - - GfxFontDict *fonts; - Object xObjDict; - Object colorSpaceDict; - Object patternDict; - Object shadingDict; - Object gStateDict; - GfxResources *next; -}; - -class Gfx { -public: - - // Constructor for regular output. - Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, - double hDPI, double vDPI, PDFRectangle *box, - PDFRectangle *cropBox, int rotate, - GBool (*abortCheckCbkA)(void *data) = NULL, - void *abortCheckCbkDataA = NULL); - - // Constructor for a sub-page object. - Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, - PDFRectangle *box, PDFRectangle *cropBox, - GBool (*abortCheckCbkA)(void *data) = NULL, - void *abortCheckCbkDataA = NULL); - - ~Gfx(); - - // Interpret a stream or array of streams. - void display(Object *obj, GBool topLevel = gTrue); - - // Display an annotation, given its appearance (a Form XObject) and - // bounding box (in default user space). - void doAnnot(Object *str, double xMin, double yMin, - double xMax, double yMax); - - // Save graphics state. - void saveState(); - - // Restore graphics state. - void restoreState(); - - // Get the current graphics state object. - GfxState *getState() { return state; } - -private: - - XRef *xref; // the xref table for this PDF file - OutputDev *out; // output device - GBool subPage; // is this a sub-page object? - GBool printCommands; // print the drawing commands (for debugging) - GfxResources *res; // resource stack - int updateLevel; - - GfxState *state; // current graphics state - GBool fontChanged; // set if font or text matrix has changed - GfxClipType clip; // do a clip? - int ignoreUndef; // current BX/EX nesting level - double baseMatrix[6]; // default matrix for most recent - // page/form/pattern - int formDepth; - - Parser *parser; // parser for page content stream(s) - - GBool // callback to check for an abort - (*abortCheckCbk)(void *data); - void *abortCheckCbkData; - - static Operator opTab[]; // table of operators - - void go(GBool topLevel); - void execOp(Object *cmd, Object args[], int numArgs); - Operator *findOp(const char *name); - GBool checkArg(Object *arg, TchkType type); - int getPos(); - - // graphics state operators - void opSave(Object args[], int numArgs); - void opRestore(Object args[], int numArgs); - void opConcat(Object args[], int numArgs); - void opSetDash(Object args[], int numArgs); - void opSetFlat(Object args[], int numArgs); - void opSetLineJoin(Object args[], int numArgs); - void opSetLineCap(Object args[], int numArgs); - void opSetMiterLimit(Object args[], int numArgs); - void opSetLineWidth(Object args[], int numArgs); - void opSetExtGState(Object args[], int numArgs); - void opSetRenderingIntent(Object args[], int numArgs); - - // color operators - void opSetFillGray(Object args[], int numArgs); - void opSetStrokeGray(Object args[], int numArgs); - void opSetFillCMYKColor(Object args[], int numArgs); - void opSetStrokeCMYKColor(Object args[], int numArgs); - void opSetFillRGBColor(Object args[], int numArgs); - void opSetStrokeRGBColor(Object args[], int numArgs); - void opSetFillColorSpace(Object args[], int numArgs); - void opSetStrokeColorSpace(Object args[], int numArgs); - void opSetFillColor(Object args[], int numArgs); - void opSetStrokeColor(Object args[], int numArgs); - void opSetFillColorN(Object args[], int numArgs); - void opSetStrokeColorN(Object args[], int numArgs); - - // path segment operators - void opMoveTo(Object args[], int numArgs); - void opLineTo(Object args[], int numArgs); - void opCurveTo(Object args[], int numArgs); - void opCurveTo1(Object args[], int numArgs); - void opCurveTo2(Object args[], int numArgs); - void opRectangle(Object args[], int numArgs); - void opClosePath(Object args[], int numArgs); - - // path painting operators - void opEndPath(Object args[], int numArgs); - void opStroke(Object args[], int numArgs); - void opCloseStroke(Object args[], int numArgs); - void opFill(Object args[], int numArgs); - void opEOFill(Object args[], int numArgs); - void opFillStroke(Object args[], int numArgs); - void opCloseFillStroke(Object args[], int numArgs); - void opEOFillStroke(Object args[], int numArgs); - void opCloseEOFillStroke(Object args[], int numArgs); - void doPatternFill(GBool eoFill); - void doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill); - void doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill); - void opShFill(Object args[], int numArgs); - void doFunctionShFill(GfxFunctionShading *shading); - void doFunctionShFill1(GfxFunctionShading *shading, - double x0, double y0, - double x1, double y1, - GfxColor *colors, int depth); - void doAxialShFill(GfxAxialShading *shading); - void doRadialShFill(GfxRadialShading *shading); - void doGouraudTriangleShFill(GfxGouraudTriangleShading *shading); - void gouraudFillTriangle(double x0, double y0, GfxColor *color0, - double x1, double y1, GfxColor *color1, - double x2, double y2, GfxColor *color2, - int nComps, int depth); - void doPatchMeshShFill(GfxPatchMeshShading *shading); - void fillPatch(GfxPatch *patch, int nComps, int depth); - void doEndPath(); - - // path clipping operators - void opClip(Object args[], int numArgs); - void opEOClip(Object args[], int numArgs); - - // text object operators - void opBeginText(Object args[], int numArgs); - void opEndText(Object args[], int numArgs); - - // text state operators - void opSetCharSpacing(Object args[], int numArgs); - void opSetFont(Object args[], int numArgs); - void opSetTextLeading(Object args[], int numArgs); - void opSetTextRender(Object args[], int numArgs); - void opSetTextRise(Object args[], int numArgs); - void opSetWordSpacing(Object args[], int numArgs); - void opSetHorizScaling(Object args[], int numArgs); - - // text positioning operators - void opTextMove(Object args[], int numArgs); - void opTextMoveSet(Object args[], int numArgs); - void opSetTextMatrix(Object args[], int numArgs); - void opTextNextLine(Object args[], int numArgs); - - // text string operators - void opShowText(Object args[], int numArgs); - void opMoveShowText(Object args[], int numArgs); - void opMoveSetShowText(Object args[], int numArgs); - void opShowSpaceText(Object args[], int numArgs); - void doShowText(GString *s); - - // XObject operators - void opXObject(Object args[], int numArgs); - void doImage(Object *ref, Stream *str, GBool inlineImg); - void doForm(Object *str); - void doForm1(Object *str, Dict *resDict, double *matrix, double *bbox); - - // in-line image operators - void opBeginImage(Object args[], int numArgs); - Stream *buildImageStream(); - void opImageData(Object args[], int numArgs); - void opEndImage(Object args[], int numArgs); - - // type 3 font operators - void opSetCharWidth(Object args[], int numArgs); - void opSetCacheDevice(Object args[], int numArgs); - - // compatibility operators - void opBeginIgnoreUndef(Object args[], int numArgs); - void opEndIgnoreUndef(Object args[], int numArgs); - - // marked content operators - void opBeginMarkedContent(Object args[], int numArgs); - void opEndMarkedContent(Object args[], int numArgs); - void opMarkPoint(Object args[], int numArgs); - - void pushResources(Dict *resDict); - void popResources(); -}; - -#endif diff --git a/xpdf/xpdf/GfxFont.cc b/xpdf/xpdf/GfxFont.cc deleted file mode 100644 index 49462ff98..000000000 --- a/xpdf/xpdf/GfxFont.cc +++ /dev/null @@ -1,1597 +0,0 @@ -//======================================================================== -// -// GfxFont.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include "gmem.h" -#include "Error.h" -#include "Object.h" -#include "Dict.h" -#include "GlobalParams.h" -#include "CMap.h" -#include "CharCodeToUnicode.h" -#include "FontEncodingTables.h" -#include "BuiltinFontTables.h" -#include "FoFiType1.h" -#include "FoFiType1C.h" -#include "FoFiTrueType.h" -#include "UGString.h" -#include "GfxFont.h" - -//------------------------------------------------------------------------ - -struct StdFontMapEntry { - const char *altName; - const char *properName; -}; - -// Acrobat 4.0 and earlier substituted Base14-compatible fonts without -// providing Widths and a FontDescriptor, so we munge the names into -// the proper Base14 names. This table is from implementation note 44 -// in the PDF 1.4 spec, with some additions based on empirical -// evidence. -static StdFontMapEntry stdFontMap[] = { - { "Arial", "Helvetica" }, - { "Arial,Bold", "Helvetica-Bold" }, - { "Arial,BoldItalic", "Helvetica-BoldOblique" }, - { "Arial,Italic", "Helvetica-Oblique" }, - { "Arial-Bold", "Helvetica-Bold" }, - { "Arial-BoldItalic", "Helvetica-BoldOblique" }, - { "Arial-BoldItalicMT", "Helvetica-BoldOblique" }, - { "Arial-BoldMT", "Helvetica-Bold" }, - { "Arial-Italic", "Helvetica-Oblique" }, - { "Arial-ItalicMT", "Helvetica-Oblique" }, - { "ArialMT", "Helvetica" }, - { "Courier,Bold", "Courier-Bold" }, - { "Courier,BoldItalic", "Courier-BoldOblique" }, - { "Courier,Italic", "Courier-Oblique" }, - { "CourierNew", "Courier" }, - { "CourierNew,Bold", "Courier-Bold" }, - { "CourierNew,BoldItalic", "Courier-BoldOblique" }, - { "CourierNew,Italic", "Courier-Oblique" }, - { "CourierNew-Bold", "Courier-Bold" }, - { "CourierNew-BoldItalic", "Courier-BoldOblique" }, - { "CourierNew-Italic", "Courier-Oblique" }, - { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" }, - { "CourierNewPS-BoldMT", "Courier-Bold" }, - { "CourierNewPS-ItalicMT", "Courier-Oblique" }, - { "CourierNewPSMT", "Courier" }, - { "Helvetica,Bold", "Helvetica-Bold" }, - { "Helvetica,BoldItalic", "Helvetica-BoldOblique" }, - { "Helvetica,Italic", "Helvetica-Oblique" }, - { "Helvetica-BoldItalic", "Helvetica-BoldOblique" }, - { "Helvetica-Italic", "Helvetica-Oblique" }, - { "Symbol,Bold", "Symbol" }, - { "Symbol,BoldItalic", "Symbol" }, - { "Symbol,Italic", "Symbol" }, - { "TimesNewRoman", "Times-Roman" }, - { "TimesNewRoman,Bold", "Times-Bold" }, - { "TimesNewRoman,BoldItalic", "Times-BoldItalic" }, - { "TimesNewRoman,Italic", "Times-Italic" }, - { "TimesNewRoman-Bold", "Times-Bold" }, - { "TimesNewRoman-BoldItalic", "Times-BoldItalic" }, - { "TimesNewRoman-Italic", "Times-Italic" }, - { "TimesNewRomanPS", "Times-Roman" }, - { "TimesNewRomanPS-Bold", "Times-Bold" }, - { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" }, - { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" }, - { "TimesNewRomanPS-BoldMT", "Times-Bold" }, - { "TimesNewRomanPS-Italic", "Times-Italic" }, - { "TimesNewRomanPS-ItalicMT", "Times-Italic" }, - { "TimesNewRomanPSMT", "Times-Roman" }, - { "TimesNewRomanPSMT,Bold", "Times-Bold" }, - { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" }, - { "TimesNewRomanPSMT,Italic", "Times-Italic" } -}; - -//------------------------------------------------------------------------ -// GfxFont -//------------------------------------------------------------------------ - -GfxFont *GfxFont::makeFont(XRef *xref, const char *tagA, Ref idA, Dict *fontDict) { - GString *nameA; - GfxFont *font; - Object obj1; - - // get base font name - nameA = NULL; - fontDict->lookup("BaseFont", &obj1); - if (obj1.isName()) { - nameA = new GString(obj1.getName()); - } - obj1.free(); - - // get font type - font = NULL; - fontDict->lookup("Subtype", &obj1); - if (obj1.isName("Type1") || obj1.isName("MMType1")) { - font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict); - } else if (obj1.isName("Type1C")) { - font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict); - } else if (obj1.isName("Type3")) { - font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict); - } else if (obj1.isName("TrueType")) { - font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict); - } else if (obj1.isName("Type0")) { - font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict); - } else { - error(-1, "Unknown font type: '%s'", - obj1.isName() ? obj1.getName() : "???"); - font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict); - } - obj1.free(); - - return font; -} - -GfxFont::GfxFont(const char *tagA, Ref idA, GString *nameA) { - ok = gFalse; - tag = new GString(tagA); - id = idA; - name = nameA; - origName = nameA; - embFontName = NULL; - extFontFile = NULL; -} - -GfxFont::~GfxFont() { - delete tag; - if (origName && origName != name) { - delete origName; - } - if (name) { - delete name; - } - if (embFontName) { - delete embFontName; - } - if (extFontFile) { - delete extFontFile; - } -} - -void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { - Object obj1, obj2, obj3, obj4; - double t; - int i; - - // assume Times-Roman by default (for substitution purposes) - flags = fontSerif; - - embFontID.num = -1; - embFontID.gen = -1; - missingWidth = 0; - - if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) { - - // get flags - if (obj1.dictLookup("Flags", &obj2)->isInt()) { - flags = obj2.getInt(); - } - obj2.free(); - - // get name - obj1.dictLookup("FontName", &obj2); - if (obj2.isName()) { - embFontName = new GString(obj2.getName()); - } - obj2.free(); - - // look for embedded font file - if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) { - embFontID = obj2.getRef(); - if (type != fontType1) { - error(-1, "Mismatch between font type and embedded font file"); - type = fontType1; - } - } - obj2.free(); - if (embFontID.num == -1 && - obj1.dictLookupNF("FontFile2", &obj2)->isRef()) { - embFontID = obj2.getRef(); - if (type != fontTrueType && type != fontCIDType2) { - error(-1, "Mismatch between font type and embedded font file"); - type = type == fontCIDType0 ? fontCIDType2 : fontTrueType; - } - } - obj2.free(); - if (embFontID.num == -1 && - obj1.dictLookupNF("FontFile3", &obj2)->isRef()) { - if (obj2.fetch(xref, &obj3)->isStream()) { - obj3.streamGetDict()->lookup("Subtype", &obj4); - if (obj4.isName("Type1")) { - embFontID = obj2.getRef(); - if (type != fontType1) { - error(-1, "Mismatch between font type and embedded font file"); - type = fontType1; - } - } else if (obj4.isName("Type1C")) { - embFontID = obj2.getRef(); - if (type != fontType1 && type != fontType1C) { - error(-1, "Mismatch between font type and embedded font file"); - } - type = fontType1C; - } else if (obj4.isName("TrueType")) { - embFontID = obj2.getRef(); - if (type != fontTrueType) { - error(-1, "Mismatch between font type and embedded font file"); - type = fontTrueType; - } - } else if (obj4.isName("CIDFontType0C")) { - embFontID = obj2.getRef(); - if (type != fontCIDType0) { - error(-1, "Mismatch between font type and embedded font file"); - } - type = fontCIDType0C; - } else { - error(-1, "Unknown embedded font type '%s'", - obj4.isName() ? obj4.getName() : "???"); - } - obj4.free(); - } - obj3.free(); - } - obj2.free(); - - // look for MissingWidth - obj1.dictLookup("MissingWidth", &obj2); - if (obj2.isNum()) { - missingWidth = obj2.getNum(); - } - obj2.free(); - - // get Ascent and Descent - obj1.dictLookup("Ascent", &obj2); - if (obj2.isNum()) { - t = 0.001 * obj2.getNum(); - // some broken font descriptors set ascent and descent to 0 - if (t != 0) { - ascent = t; - } - } - obj2.free(); - obj1.dictLookup("Descent", &obj2); - if (obj2.isNum()) { - t = 0.001 * obj2.getNum(); - // some broken font descriptors set ascent and descent to 0 - if (t != 0) { - descent = t; - } - // some broken font descriptors specify a positive descent - if (descent > 0) { - descent = -descent; - } - } - obj2.free(); - - // font FontBBox - if (obj1.dictLookup("FontBBox", &obj2)->isArray()) { - for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) { - if (obj2.arrayGet(i, &obj3)->isNum()) { - fontBBox[i] = 0.001 * obj3.getNum(); - } - obj3.free(); - } - } - obj2.free(); - - } - obj1.free(); -} - -CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits, - CharCodeToUnicode *ctu) { - GString *buf; - Object obj1; - int c; - - if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) { - obj1.free(); - return NULL; - } - buf = new GString(); - obj1.streamReset(); - while ((c = obj1.streamGetChar()) != EOF) { - buf->append(c); - } - obj1.streamClose(); - obj1.free(); - if (ctu) { - ctu->mergeCMap(buf, nBits); - } else { - ctu = CharCodeToUnicode::parseCMap(buf, nBits); - } - delete buf; - return ctu; -} - -void GfxFont::findExtFontFile() { - static const char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL }; - static const char *ttExts[] = { ".ttf", ".ttc", NULL }; - - if (name) { - if (type == fontType1) { - extFontFile = globalParams->findFontFile(name, type1Exts); - } else if (type == fontTrueType) { - extFontFile = globalParams->findFontFile(name, ttExts); - } - } -} - -char *GfxFont::readExtFontFile(int *len) { - FILE *f; - char *buf; - - if (!(f = fopen(extFontFile->getCString(), "rb"))) { - error(-1, "External font file '%s' vanished", extFontFile->getCString()); - return NULL; - } - fseek(f, 0, SEEK_END); - *len = (int)ftell(f); - fseek(f, 0, SEEK_SET); - buf = (char *)gmalloc(*len); - if ((int)fread(buf, 1, *len, f) != *len) { - error(-1, "Error reading external font file '%s'", - extFontFile->getCString()); - } - fclose(f); - return buf; -} - -char *GfxFont::readEmbFontFile(XRef *xref, int *len) { - char *buf; - Object obj1, obj2; - Stream *str; - int c; - int size, i; - - obj1.initRef(embFontID.num, embFontID.gen); - obj1.fetch(xref, &obj2); - if (!obj2.isStream()) { - error(-1, "Embedded font file is not a stream"); - obj2.free(); - obj1.free(); - embFontID.num = -1; - return NULL; - } - str = obj2.getStream(); - - buf = NULL; - i = size = 0; - str->reset(); - while ((c = str->getChar()) != EOF) { - if (i == size) { - size += 4096; - buf = (char *)grealloc(buf, size); - } - buf[i++] = c; - } - *len = i; - str->close(); - - obj2.free(); - obj1.free(); - - return buf; -} - -//------------------------------------------------------------------------ -// Gfx8BitFont -//------------------------------------------------------------------------ - -Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, - GfxFontType typeA, Dict *fontDict): - GfxFont(tagA, idA, nameA) -{ - GString *name2; - BuiltinFont *builtinFont; - const char **baseEnc; - GBool baseEncFromFontFile; - char *buf; - int len; - FoFiType1 *ffT1; - FoFiType1C *ffT1C; - int code, code2; - const char *charName; - GBool missing, hex; - Unicode toUnicode[256]; - CharCodeToUnicode *utu, *ctu2; - Unicode uBuf[8]; - double mul; - int firstChar, lastChar; - Gushort w; - Object obj1, obj2, obj3; - int n, i, a, b, m; - - type = typeA; - ctu = NULL; - - // do font name substitution for various aliases of the Base 14 font - // names - if (name) { - name2 = name->copy(); - i = 0; - while (i < name2->getLength()) { - if (name2->getChar(i) == ' ') { - name2->del(i); - } else { - ++i; - } - } - a = 0; - b = sizeof(stdFontMap) / sizeof(StdFontMapEntry); - // invariant: stdFontMap[a].altName <= name2 < stdFontMap[b].altName - while (b - a > 1) { - m = (a + b) / 2; - if (name2->cmp(stdFontMap[m].altName) >= 0) { - a = m; - } else { - b = m; - } - } - if (!name2->cmp(stdFontMap[a].altName)) { - name = new GString(stdFontMap[a].properName); - } - delete name2; - } - - // is it a built-in font? - builtinFont = NULL; - if (name) { - for (i = 0; i < nBuiltinFonts; ++i) { - if (!name->cmp(builtinFonts[i].name)) { - builtinFont = &builtinFonts[i]; - break; - } - } - } - - // default ascent/descent values - if (builtinFont) { - ascent = 0.001 * builtinFont->ascent; - descent = 0.001 * builtinFont->descent; - fontBBox[0] = 0.001 * builtinFont->bbox[0]; - fontBBox[1] = 0.001 * builtinFont->bbox[1]; - fontBBox[2] = 0.001 * builtinFont->bbox[2]; - fontBBox[3] = 0.001 * builtinFont->bbox[3]; - } else { - ascent = 0.95; - descent = -0.35; - fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; - } - - // get info from font descriptor - readFontDescriptor(xref, fontDict); - - // for non-embedded fonts, don't trust the ascent/descent/bbox - // values from the font descriptor - if (builtinFont && embFontID.num < 0) { - ascent = 0.001 * builtinFont->ascent; - descent = 0.001 * builtinFont->descent; - fontBBox[0] = 0.001 * builtinFont->bbox[0]; - fontBBox[1] = 0.001 * builtinFont->bbox[1]; - fontBBox[2] = 0.001 * builtinFont->bbox[2]; - fontBBox[3] = 0.001 * builtinFont->bbox[3]; - } - - // look for an external font file - findExtFontFile(); - - // get font matrix - fontMat[0] = fontMat[3] = 1; - fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0; - if (fontDict->lookup("FontMatrix", &obj1)->isArray()) { - for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) { - if (obj1.arrayGet(i, &obj2)->isNum()) { - fontMat[i] = obj2.getNum(); - } - obj2.free(); - } - } - obj1.free(); - - // get Type 3 bounding box, font definition, and resources - if (type == fontType3) { - if (fontDict->lookup("FontBBox", &obj1)->isArray()) { - for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) { - if (obj1.arrayGet(i, &obj2)->isNum()) { - fontBBox[i] = obj2.getNum(); - } - obj2.free(); - } - } - obj1.free(); - if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) { - error(-1, "Missing or invalid CharProcs dictionary in Type 3 font"); - charProcs.free(); - } - if (!fontDict->lookup("Resources", &resources)->isDict()) { - resources.free(); - } - } - - //----- build the font encoding ----- - - // Encodings start with a base encoding, which can come from - // (in order of priority): - // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding - // - MacRoman / MacExpert / WinAnsi / Standard - // 2. embedded or external font file - // 3. default: - // - builtin --> builtin encoding - // - TrueType --> WinAnsiEncoding - // - others --> StandardEncoding - // and then add a list of differences (if any) from - // FontDict.Encoding.Differences. - - // check FontDict for base encoding - hasEncoding = gFalse; - usesMacRomanEnc = gFalse; - baseEnc = NULL; - baseEncFromFontFile = gFalse; - fontDict->lookup("Encoding", &obj1); - if (obj1.isDict()) { - obj1.dictLookup("BaseEncoding", &obj2); - if (obj2.isName("MacRomanEncoding")) { - hasEncoding = gTrue; - usesMacRomanEnc = gTrue; - baseEnc = macRomanEncoding; - } else if (obj2.isName("MacExpertEncoding")) { - hasEncoding = gTrue; - baseEnc = macExpertEncoding; - } else if (obj2.isName("WinAnsiEncoding")) { - hasEncoding = gTrue; - baseEnc = winAnsiEncoding; - } - obj2.free(); - } else if (obj1.isName("MacRomanEncoding")) { - hasEncoding = gTrue; - usesMacRomanEnc = gTrue; - baseEnc = macRomanEncoding; - } else if (obj1.isName("MacExpertEncoding")) { - hasEncoding = gTrue; - baseEnc = macExpertEncoding; - } else if (obj1.isName("WinAnsiEncoding")) { - hasEncoding = gTrue; - baseEnc = winAnsiEncoding; - } - - // check embedded or external font file for base encoding - // (only for Type 1 fonts - trying to get an encoding out of a - // TrueType font is a losing proposition) - ffT1 = NULL; - ffT1C = NULL; - buf = NULL; - if (type == fontType1 && (extFontFile || embFontID.num >= 0)) { - if (extFontFile) { - ffT1 = FoFiType1::load(extFontFile->getCString()); - } else { - buf = readEmbFontFile(xref, &len); - ffT1 = FoFiType1::make(buf, len); - } - if (ffT1) { - if (ffT1->getName()) { - if (embFontName) { - delete embFontName; - } - embFontName = new GString(ffT1->getName()); - } - if (!baseEnc) { - baseEnc = ffT1->getEncoding(); - baseEncFromFontFile = gTrue; - } - } - } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) { - if (extFontFile) { - ffT1C = FoFiType1C::load(extFontFile->getCString()); - } else { - buf = readEmbFontFile(xref, &len); - ffT1C = FoFiType1C::make(buf, len); - } - if (ffT1C) { - if (ffT1C->getName()) { - if (embFontName) { - delete embFontName; - } - embFontName = new GString(ffT1C->getName()); - } - if (!baseEnc) { - baseEnc = ffT1C->getEncoding(); - baseEncFromFontFile = gTrue; - } - } - } - if (buf) { - gfree(buf); - } - - // get default base encoding - if (!baseEnc) { - if (builtinFont && embFontID.num < 0) { - baseEnc = builtinFont->defaultBaseEnc; - hasEncoding = gTrue; - } else if (type == fontTrueType) { - baseEnc = winAnsiEncoding; - } else { - baseEnc = standardEncoding; - } - } - - // copy the base encoding - for (i = 0; i < 256; ++i) { - enc[i] = baseEnc[i]; - if ((encFree[i] = baseEncFromFontFile) && enc[i]) { - enc[i] = copyString(baseEnc[i]); - } - } - - // some Type 1C font files have empty encodings, which can break the - // T1C->T1 conversion (since the 'seac' operator depends on having - // the accents in the encoding), so we fill in any gaps from - // StandardEncoding - if (type == fontType1C && (extFontFile || embFontID.num >= 0) && - baseEncFromFontFile) { - for (i = 0; i < 256; ++i) { - if (!enc[i] && standardEncoding[i]) { - enc[i] = standardEncoding[i]; - encFree[i] = gFalse; - } - } - } - - // merge differences into encoding - if (obj1.isDict()) { - obj1.dictLookup("Differences", &obj2); - if (obj2.isArray()) { - hasEncoding = gTrue; - code = 0; - for (i = 0; i < obj2.arrayGetLength(); ++i) { - obj2.arrayGet(i, &obj3); - if (obj3.isInt()) { - code = obj3.getInt(); - } else if (obj3.isName()) { - if (code >= 0 && code < 256) { - if (encFree[code]) { - gfree((void*)enc[code]); - } - enc[code] = copyString(obj3.getName()); - encFree[code] = gTrue; - } - ++code; - } else { - error(-1, "Wrong type in font encoding resource differences (%s)", - obj3.getTypeName()); - } - obj3.free(); - } - } - obj2.free(); - } - obj1.free(); - if (ffT1) { - delete ffT1; - } - if (ffT1C) { - delete ffT1C; - } - - //----- build the mapping to Unicode ----- - - // pass 1: use the name-to-Unicode mapping table - missing = hex = gFalse; - for (code = 0; code < 256; ++code) { - if ((charName = enc[code])) { - if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) && - strcmp(charName, ".notdef")) { - // if it wasn't in the name-to-Unicode table, check for a - // name that looks like 'Axx' or 'xx', where 'A' is any letter - // and 'xx' is two hex digits - if ((strlen(charName) == 3 && - isalpha(charName[0]) && - isxdigit(charName[1]) && isxdigit(charName[2]) && - ((charName[1] >= 'a' && charName[1] <= 'f') || - (charName[1] >= 'A' && charName[1] <= 'F') || - (charName[2] >= 'a' && charName[2] <= 'f') || - (charName[2] >= 'A' && charName[2] <= 'F'))) || - (strlen(charName) == 2 && - isxdigit(charName[0]) && isxdigit(charName[1]) && - ((charName[0] >= 'a' && charName[0] <= 'f') || - (charName[0] >= 'A' && charName[0] <= 'F') || - (charName[1] >= 'a' && charName[1] <= 'f') || - (charName[1] >= 'A' && charName[1] <= 'F')))) { - hex = gTrue; - } - missing = gTrue; - } - } else { - toUnicode[code] = 0; - } - } - - // pass 2: try to fill in the missing chars, looking for names of - // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B' - // are any letters, 'xx' is two hex digits, and 'nn' is 2-4 - // decimal digits - if (missing && globalParams->getMapNumericCharNames()) { - for (code = 0; code < 256; ++code) { - if ((charName = enc[code]) && !toUnicode[code] && - strcmp(charName, ".notdef")) { - n = strlen(charName); - code2 = -1; - if (hex && n == 3 && isalpha(charName[0]) && - isxdigit(charName[1]) && isxdigit(charName[2])) { - sscanf(charName+1, "%x", &code2); - } else if (hex && n == 2 && - isxdigit(charName[0]) && isxdigit(charName[1])) { - sscanf(charName, "%x", &code2); - } else if (!hex && n >= 2 && n <= 4 && - isdigit(charName[0]) && isdigit(charName[1])) { - code2 = atoi(charName); - } else if (n >= 3 && n <= 5 && - isdigit(charName[1]) && isdigit(charName[2])) { - code2 = atoi(charName+1); - } else if (n >= 4 && n <= 6 && - isdigit(charName[2]) && isdigit(charName[3])) { - code2 = atoi(charName+2); - } - if (code2 >= 0 && code2 <= 0xff) { - toUnicode[code] = (Unicode)code2; - } - } - } - } - - // construct the char code -> Unicode mapping object - ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode); - - // merge in a ToUnicode CMap, if there is one -- this overwrites - // existing entries in ctu, i.e., the ToUnicode CMap takes - // precedence, but the other encoding info is allowed to fill in any - // holes - readToUnicodeCMap(fontDict, 8, ctu); - - // look for a Unicode-to-Unicode mapping - if (name && (utu = globalParams->getUnicodeToUnicode(name))) { - for (i = 0; i < 256; ++i) { - toUnicode[i] = 0; - } - ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode); - for (i = 0; i < 256; ++i) { - n = ctu->mapToUnicode((CharCode)i, uBuf, 8); - if (n >= 1) { - n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); - if (n >= 1) { - ctu2->setMapping((CharCode)i, uBuf, n); - } - } - } - utu->decRefCnt(); - delete ctu; - ctu = ctu2; - } - - //----- get the character widths ----- - - // initialize all widths - for (code = 0; code < 256; ++code) { - widths[code] = missingWidth * 0.001; - } - - // use widths from font dict, if present - fontDict->lookup("FirstChar", &obj1); - firstChar = obj1.isInt() ? obj1.getInt() : 0; - obj1.free(); - if (firstChar < 0 || firstChar > 255) { - firstChar = 0; - } - fontDict->lookup("LastChar", &obj1); - lastChar = obj1.isInt() ? obj1.getInt() : 255; - obj1.free(); - if (lastChar < 0 || lastChar > 255) { - lastChar = 255; - } - mul = (type == fontType3) ? fontMat[0] : 0.001; - fontDict->lookup("Widths", &obj1); - if (obj1.isArray()) { - flags |= fontFixedWidth; - if (obj1.arrayGetLength() < lastChar - firstChar + 1) { - lastChar = firstChar + obj1.arrayGetLength() - 1; - } - for (code = firstChar; code <= lastChar; ++code) { - obj1.arrayGet(code - firstChar, &obj2); - if (obj2.isNum()) { - widths[code] = obj2.getNum() * mul; - if (widths[code] != widths[firstChar]) { - flags &= ~fontFixedWidth; - } - } - obj2.free(); - } - - // use widths from built-in font - } else if (builtinFont) { - // this is a kludge for broken PDF files that encode char 32 - // as .notdef - if (builtinFont->widths->getWidth("space", &w)) { - widths[32] = 0.001 * w; - } - for (code = 0; code < 256; ++code) { - if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { - widths[code] = 0.001 * w; - } - } - - // couldn't find widths -- use defaults - } else { - // this is technically an error -- the Widths entry is required - // for all but the Base-14 fonts -- but certain PDF generators - // apparently don't include widths for Arial and TimesNewRoman - if (isFixedWidth()) { - i = 0; - } else if (isSerif()) { - i = 8; - } else { - i = 4; - } - if (isBold()) { - i += 2; - } - if (isItalic()) { - i += 1; - } - builtinFont = builtinFontSubst[i]; - // this is a kludge for broken PDF files that encode char 32 - // as .notdef - if (builtinFont->widths->getWidth("space", &w)) { - widths[32] = 0.001 * w; - } - for (code = 0; code < 256; ++code) { - if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { - widths[code] = 0.001 * w; - } - } - } - obj1.free(); - - ok = gTrue; -} - -Gfx8BitFont::~Gfx8BitFont() { - int i; - - for (i = 0; i < 256; ++i) { - if (encFree[i] && enc[i]) { - gfree((void*)enc[i]); - } - } - ctu->decRefCnt(); - if (charProcs.isDict()) { - charProcs.free(); - } - if (resources.isDict()) { - resources.free(); - } -} - -int Gfx8BitFont::getNextChar(char *s, int /*len*/, CharCode *code, - Unicode *u, int uSize, int *uLen, - double *dx, double *dy, double *ox, double *oy) { - CharCode c; - - *code = c = (CharCode)(*s & 0xff); - *uLen = ctu->mapToUnicode(c, u, uSize); - *dx = widths[c]; - *dy = *ox = *oy = 0; - return 1; -} - -CharCodeToUnicode *Gfx8BitFont::getToUnicode() { - ctu->incRefCnt(); - return ctu; -} - -Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { - Gushort *map; - int cmapPlatform, cmapEncoding; - int unicodeCmap, macRomanCmap, msSymbolCmap, cmap; - GBool useMacRoman, useUnicode; - const char *charName; - Unicode u; - int code, i, n; - - map = (Gushort *)gmallocn(256, sizeof(Gushort)); - for (i = 0; i < 256; ++i) { - map[i] = 0; - } - - // To match up with the Adobe-defined behaviour, we choose a cmap - // like this: - // 1. If the PDF font has an encoding: - // 1a. If the PDF font specified MacRomanEncoding and the - // TrueType font has a Macintosh Roman cmap, use it, and - // reverse map the char names through MacRomanEncoding to - // get char codes. - // 1b. If the TrueType font has a Microsoft Unicode cmap or a - // non-Microsoft Unicode cmap, use it, and use the Unicode - // indexes, not the char codes. - // 1c. If the PDF font is symbolic and the TrueType font has a - // Microsoft Symbol cmap, use it, and use char codes - // directly (possibly with an offset of 0xf000). - // 1d. If the TrueType font has a Macintosh Roman cmap, use it, - // as in case 1a. - // 2. If the PDF font does not have an encoding or the PDF font is - // symbolic: - // 2a. If the TrueType font has a Macintosh Roman cmap, use it, - // and use char codes directly (possibly with an offset of - // 0xf000). - // 2b. If the TrueType font has a Microsoft Symbol cmap, use it, - // and use char codes directly (possible with an offset of - // 0xf000). - // 3. If none of these rules apply, use the first cmap and hope for - // the best (this shouldn't happen). - unicodeCmap = macRomanCmap = msSymbolCmap = -1; - for (i = 0; i < ff->getNumCmaps(); ++i) { - cmapPlatform = ff->getCmapPlatform(i); - cmapEncoding = ff->getCmapEncoding(i); - if ((cmapPlatform == 3 && cmapEncoding == 1) || - cmapPlatform == 0) { - unicodeCmap = i; - } else if (cmapPlatform == 1 && cmapEncoding == 0) { - macRomanCmap = i; - } else if (cmapPlatform == 3 && cmapEncoding == 0) { - msSymbolCmap = i; - } - } - cmap = 0; - useMacRoman = gFalse; - useUnicode = gFalse; - if (hasEncoding) { - if (usesMacRomanEnc && macRomanCmap >= 0) { - cmap = macRomanCmap; - useMacRoman = gTrue; - } else if (unicodeCmap >= 0) { - cmap = unicodeCmap; - useUnicode = gTrue; - } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) { - cmap = msSymbolCmap; - } else if ((flags & fontSymbolic) && macRomanCmap >= 0) { - cmap = macRomanCmap; - } else if (macRomanCmap >= 0) { - cmap = macRomanCmap; - useMacRoman = gTrue; - } - } else { - if (macRomanCmap >= 0) { - cmap = macRomanCmap; - } else if (msSymbolCmap >= 0) { - cmap = msSymbolCmap; - } - } - - // reverse map the char names through MacRomanEncoding, then map the - // char codes through the cmap - if (useMacRoman) { - for (i = 0; i < 256; ++i) { - if ((charName = enc[i])) { - if ((code = globalParams->getMacRomanCharCode(charName))) { - map[i] = ff->mapCodeToGID(cmap, code); - } - } - } - - // map Unicode through the cmap - } else if (useUnicode) { - for (i = 0; i < 256; ++i) { - if (((charName = enc[i]) && - (u = globalParams->mapNameToUnicode(charName))) || - (n = ctu->mapToUnicode((CharCode)i, &u, 1))) { - map[i] = ff->mapCodeToGID(cmap, u); - } - } - - // map the char codes through the cmap, possibly with an offset of - // 0xf000 - } else { - for (i = 0; i < 256; ++i) { - if (!(map[i] = ff->mapCodeToGID(cmap, i))) { - map[i] = ff->mapCodeToGID(cmap, 0xf000 + i); - } - } - } - - // try the TrueType 'post' table to handle any unmapped characters - for (i = 0; i < 256; ++i) { - if (!map[i] && (charName = enc[i])) { - map[i] = (Gushort)(int)ff->mapNameToGID(charName); - } - } - - return map; -} - -Dict *Gfx8BitFont::getCharProcs() { - return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL; -} - -Object *Gfx8BitFont::getCharProc(int code, Object *proc) { - if (enc[code] && charProcs.isDict()) { - charProcs.dictLookup(enc[code], proc); - } else { - proc->initNull(); - } - return proc; -} - -Dict *Gfx8BitFont::getResources() { - return resources.isDict() ? resources.getDict() : (Dict *)NULL; -} - -//------------------------------------------------------------------------ -// GfxCIDFont -//------------------------------------------------------------------------ - -static int CDECL cmpWidthExcep(const void *w1, const void *w2) { - return ((GfxFontCIDWidthExcep *)w1)->first - - ((GfxFontCIDWidthExcep *)w2)->first; -} - -static int CDECL cmpWidthExcepV(const void *w1, const void *w2) { - return ((GfxFontCIDWidthExcepV *)w1)->first - - ((GfxFontCIDWidthExcepV *)w2)->first; -} - -GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, - Dict *fontDict): - GfxFont(tagA, idA, nameA) -{ - Dict *desFontDict; - GString *collection, *cMapName; - Object desFontDictObj; - Object obj1, obj2, obj3, obj4, obj5, obj6; - CharCodeToUnicode *utu; - CharCode c; - Unicode uBuf[8]; - int c1, c2; - int excepsSize, i, j, k, n; - - ascent = 0.95; - descent = -0.35; - fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; - cMap = NULL; - ctu = NULL; - widths.defWidth = 1.0; - widths.defHeight = -1.0; - widths.defVY = 0.880; - widths.exceps = NULL; - widths.nExceps = 0; - widths.excepsV = NULL; - widths.nExcepsV = 0; - cidToGID = NULL; - cidToGIDLen = 0; - - // get the descendant font - if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) { - error(-1, "Missing DescendantFonts entry in Type 0 font"); - obj1.free(); - goto err1; - } - if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) { - error(-1, "Bad descendant font in Type 0 font"); - goto err3; - } - obj1.free(); - desFontDict = desFontDictObj.getDict(); - - // font type - if (!desFontDict->lookup("Subtype", &obj1)) { - error(-1, "Missing Subtype entry in Type 0 descendant font"); - goto err3; - } - if (obj1.isName("CIDFontType0")) { - type = fontCIDType0; - } else if (obj1.isName("CIDFontType2")) { - type = fontCIDType2; - } else { - error(-1, "Unknown Type 0 descendant font type '%s'", - obj1.isName() ? obj1.getName() : "???"); - goto err3; - } - obj1.free(); - - // get info from font descriptor - readFontDescriptor(xref, desFontDict); - - // look for an external font file - findExtFontFile(); - - //----- encoding info ----- - - // char collection - if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) { - error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font"); - goto err3; - } - obj1.dictLookup("Registry", &obj2); - obj1.dictLookup("Ordering", &obj3); - if (!obj2.isString() || !obj3.isString()) { - error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font"); - goto err4; - } - collection = obj2.getString()->copy()->append('-')->append(obj3.getString()); - obj3.free(); - obj2.free(); - obj1.free(); - - // look for a ToUnicode CMap - if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) { - - // the "Adobe-Identity" and "Adobe-UCS" collections don't have - // cidToUnicode files - if (collection->cmp("Adobe-Identity") && - collection->cmp("Adobe-UCS")) { - - // look for a user-supplied .cidToUnicode file - if (!(ctu = globalParams->getCIDToUnicode(collection))) { - error(-1, "Unknown character collection '%s'", - collection->getCString()); - // fall-through, assuming the Identity mapping -- this appears - // to match Adobe's behavior - } - } - } - - // look for a Unicode-to-Unicode mapping - if (name && (utu = globalParams->getUnicodeToUnicode(name))) { - if (ctu) { - for (c = 0; c < ctu->getLength(); ++c) { - n = ctu->mapToUnicode(c, uBuf, 8); - if (n >= 1) { - n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); - if (n >= 1) { - ctu->setMapping(c, uBuf, n); - } - } - } - utu->decRefCnt(); - } else { - ctu = utu; - } - } - - // encoding (i.e., CMap) - //~ need to handle a CMap stream here - //~ also need to deal with the UseCMap entry in the stream dict - if (!fontDict->lookup("Encoding", &obj1)->isName()) { - error(-1, "Missing or invalid Encoding entry in Type 0 font"); - delete collection; - goto err3; - } - cMapName = new GString(obj1.getName()); - obj1.free(); - if (!(cMap = globalParams->getCMap(collection, cMapName))) { - error(-1, "Unknown CMap '%s' for character collection '%s'", - cMapName->getCString(), collection->getCString()); - delete collection; - delete cMapName; - goto err2; - } - delete collection; - delete cMapName; - - // CIDToGIDMap (for embedded TrueType fonts) - if (type == fontCIDType2) { - desFontDict->lookup("CIDToGIDMap", &obj1); - if (obj1.isStream()) { - cidToGIDLen = 0; - i = 64; - cidToGID = (Gushort *)gmallocn(i, sizeof(Gushort)); - obj1.streamReset(); - while ((c1 = obj1.streamGetChar()) != EOF && - (c2 = obj1.streamGetChar()) != EOF) { - if (cidToGIDLen == i) { - i *= 2; - cidToGID = (Gushort *)greallocn(cidToGID, i, sizeof(Gushort)); - } - cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2); - } - } else if (!obj1.isName("Identity") && !obj1.isNull()) { - error(-1, "Invalid CIDToGIDMap entry in CID font"); - } - obj1.free(); - } - - //----- character metrics ----- - - // default char width - if (desFontDict->lookup("DW", &obj1)->isInt()) { - widths.defWidth = obj1.getInt() * 0.001; - } - obj1.free(); - - // char width exceptions - if (desFontDict->lookup("W", &obj1)->isArray()) { - excepsSize = 0; - i = 0; - while (i + 1 < obj1.arrayGetLength()) { - obj1.arrayGet(i, &obj2); - obj1.arrayGet(i + 1, &obj3); - if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) { - if (obj1.arrayGet(i + 2, &obj4)->isNum()) { - if (widths.nExceps == excepsSize) { - excepsSize += 16; - widths.exceps = (GfxFontCIDWidthExcep *) - greallocn(widths.exceps, - excepsSize, sizeof(GfxFontCIDWidthExcep)); - } - widths.exceps[widths.nExceps].first = obj2.getInt(); - widths.exceps[widths.nExceps].last = obj3.getInt(); - widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001; - ++widths.nExceps; - } else { - error(-1, "Bad widths array in Type 0 font"); - } - obj4.free(); - i += 3; - } else if (obj2.isInt() && obj3.isArray()) { - if (widths.nExceps + obj3.arrayGetLength() > excepsSize) { - excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15; - widths.exceps = (GfxFontCIDWidthExcep *) - greallocn(widths.exceps, - excepsSize, sizeof(GfxFontCIDWidthExcep)); - } - j = obj2.getInt(); - for (k = 0; k < obj3.arrayGetLength(); ++k) { - if (obj3.arrayGet(k, &obj4)->isNum()) { - widths.exceps[widths.nExceps].first = j; - widths.exceps[widths.nExceps].last = j; - widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001; - ++j; - ++widths.nExceps; - } else { - error(-1, "Bad widths array in Type 0 font"); - } - obj4.free(); - } - i += 2; - } else { - error(-1, "Bad widths array in Type 0 font"); - ++i; - } - obj3.free(); - obj2.free(); - } - qsort(widths.exceps, widths.nExceps, sizeof(GfxFontCIDWidthExcep), - &cmpWidthExcep); - } - obj1.free(); - - // default metrics for vertical font - if (desFontDict->lookup("DW2", &obj1)->isArray() && - obj1.arrayGetLength() == 2) { - if (obj1.arrayGet(0, &obj2)->isNum()) { - widths.defVY = obj2.getNum() * 0.001; - } - obj2.free(); - if (obj1.arrayGet(1, &obj2)->isNum()) { - widths.defHeight = obj2.getNum() * 0.001; - } - obj2.free(); - } - obj1.free(); - - // char metric exceptions for vertical font - if (desFontDict->lookup("W2", &obj1)->isArray()) { - excepsSize = 0; - i = 0; - while (i + 1 < obj1.arrayGetLength()) { - obj1.arrayGet(i, &obj2); - obj1.arrayGet(i+ 1, &obj3); - if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) { - if (obj1.arrayGet(i + 2, &obj4)->isNum() && - obj1.arrayGet(i + 3, &obj5)->isNum() && - obj1.arrayGet(i + 4, &obj6)->isNum()) { - if (widths.nExcepsV == excepsSize) { - excepsSize += 16; - widths.excepsV = (GfxFontCIDWidthExcepV *) - greallocn(widths.excepsV, - excepsSize, sizeof(GfxFontCIDWidthExcepV)); - } - widths.excepsV[widths.nExcepsV].first = obj2.getInt(); - widths.excepsV[widths.nExcepsV].last = obj3.getInt(); - widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001; - widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001; - widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001; - ++widths.nExcepsV; - } else { - error(-1, "Bad widths (W2) array in Type 0 font"); - } - obj6.free(); - obj5.free(); - obj4.free(); - i += 5; - } else if (obj2.isInt() && obj3.isArray()) { - if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) { - excepsSize = - (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15; - widths.excepsV = (GfxFontCIDWidthExcepV *) - greallocn(widths.excepsV, - excepsSize, sizeof(GfxFontCIDWidthExcepV)); - } - j = obj2.getInt(); - for (k = 0; k < obj3.arrayGetLength(); k += 3) { - if (obj3.arrayGet(k, &obj4)->isNum() && - obj3.arrayGet(k+1, &obj5)->isNum() && - obj3.arrayGet(k+2, &obj6)->isNum()) { - widths.excepsV[widths.nExceps].first = j; - widths.excepsV[widths.nExceps].last = j; - widths.excepsV[widths.nExceps].height = obj4.getNum() * 0.001; - widths.excepsV[widths.nExceps].vx = obj5.getNum() * 0.001; - widths.excepsV[widths.nExceps].vy = obj6.getNum() * 0.001; - ++j; - ++widths.nExcepsV; - } else { - error(-1, "Bad widths (W2) array in Type 0 font"); - } - obj6.free(); - obj5.free(); - obj4.free(); - } - i += 2; - } else { - error(-1, "Bad widths (W2) array in Type 0 font"); - ++i; - } - obj3.free(); - obj2.free(); - } - qsort(widths.excepsV, widths.nExcepsV, sizeof(GfxFontCIDWidthExcepV), - &cmpWidthExcepV); - } - obj1.free(); - - desFontDictObj.free(); - ok = gTrue; - return; - - err4: - obj3.free(); - obj2.free(); - err3: - obj1.free(); - err2: - desFontDictObj.free(); - err1:; -} - -GfxCIDFont::~GfxCIDFont() { - if (cMap) { - cMap->decRefCnt(); - } - if (ctu) { - ctu->decRefCnt(); - } - gfree(widths.exceps); - gfree(widths.excepsV); - if (cidToGID) { - gfree(cidToGID); - } -} - -int GfxCIDFont::getNextChar(char *s, int len, CharCode *code, - Unicode *u, int uSize, int *uLen, - double *dx, double *dy, double *ox, double *oy) { - CID cid; - double w, h, vx, vy; - int n, a, b, m; - - if (!cMap) { - *code = 0; - *uLen = 0; - *dx = *dy = 0; - return 1; - } - - *code = (CharCode)(cid = cMap->getCID(s, len, &n)); - if (ctu) { - *uLen = ctu->mapToUnicode(cid, u, uSize); - } else { - *uLen = 0; - } - - // horizontal - if (cMap->getWMode() == 0) { - w = widths.defWidth; - h = vx = vy = 0; - if (widths.nExceps > 0 && cid >= widths.exceps[0].first) { - a = 0; - b = widths.nExceps; - // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first - while (b - a > 1) { - m = (a + b) / 2; - if (widths.exceps[m].first <= cid) { - a = m; - } else { - b = m; - } - } - if (cid <= widths.exceps[a].last) { - w = widths.exceps[a].width; - } - } - - // vertical - } else { - w = 0; - h = widths.defHeight; - vx = widths.defWidth / 2; - vy = widths.defVY; - if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) { - a = 0; - b = widths.nExcepsV; - // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first - while (b - a > 1) { - m = (a + b) / 2; - if (widths.excepsV[m].last <= cid) { - a = m; - } else { - b = m; - } - } - if (cid <= widths.excepsV[a].last) { - h = widths.excepsV[a].height; - vx = widths.excepsV[a].vx; - vy = widths.excepsV[a].vy; - } - } - } - - *dx = w; - *dy = h; - *ox = vx; - *oy = vy; - - return n; -} - -int GfxCIDFont::getWMode() { - return cMap ? cMap->getWMode() : 0; -} - -CharCodeToUnicode *GfxCIDFont::getToUnicode() { - if (ctu) { - ctu->incRefCnt(); - } - return ctu; -} - -GString *GfxCIDFont::getCollection() { - return cMap ? cMap->getCollection() : (GString *)NULL; -} - -Gushort *GfxCIDFont::getCodeToGIDMap(FoFiTrueType *ff, int *mapsizep) { - Gushort *map; - int cmapPlatform, cmapEncoding; - int /*unicodeCmap, macRomanCmap, msSymbolCmap, */cmap; -// GBool useMacRoman, useUnicode; -// char *charName; - Unicode u; - int /*code, */i; - unsigned int mapsize; - unsigned int cidlen; - - *mapsizep = 0; - if (!ctu) return NULL; - - /* we use only unicode cmap */ - cmap = -1; - for (i = 0; i < ff->getNumCmaps(); ++i) { - cmapPlatform = ff->getCmapPlatform(i); - cmapEncoding = ff->getCmapEncoding(i); - if ((cmapPlatform == 3 && cmapEncoding == 1) || cmapPlatform == 0) - cmap = i; - } - if (cmap < 0) - return NULL; - - cidlen = 0; - mapsize = 64; - map = (Gushort *)gmalloc(mapsize * sizeof(Gushort)); - - while (cidlen < ctu->getLength()) { - int n; - if ((n = ctu->mapToUnicode((CharCode)cidlen, &u, 1)) == 0) { - cidlen++; - continue; - } - if (cidlen >= mapsize) { - while (cidlen >= mapsize) - mapsize *= 2; - map = (Gushort *)grealloc(map, mapsize * sizeof(Gushort)); - } - map[cidlen] = ff->mapCodeToGID(cmap, u); - cidlen++; - } - - *mapsizep = cidlen; - return map; -} - -//------------------------------------------------------------------------ -// GfxFontDict -//------------------------------------------------------------------------ - -GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { - int i; - Object obj1, obj2; - Ref r; - - numFonts = fontDict->getLength(); - fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *)); - for (i = 0; i < numFonts; ++i) { - fontDict->getValNF(i, &obj1); - obj1.fetch(xref, &obj2); - if (obj2.isDict()) { - if (obj1.isRef()) { - r = obj1.getRef(); - } else { - // no indirect reference for this font, so invent a unique one - // (legal generation numbers are five digits, so any 6-digit - // number would be safe) - r.num = i; - if (fontDictRef) { - r.gen = 100000 + fontDictRef->num; - } else { - r.gen = 999999; - } - } - const char *aux = fontDict->getKey(i)->getCString(); - fonts[i] = GfxFont::makeFont(xref, aux, - r, obj2.getDict()); - delete[] aux; - if (fonts[i] && !fonts[i]->isOk()) { - delete fonts[i]; - fonts[i] = NULL; - } - } else { - error(-1, "font resource is not a dictionary"); - fonts[i] = NULL; - } - obj1.free(); - obj2.free(); - } -} - -GfxFontDict::~GfxFontDict() { - int i; - - for (i = 0; i < numFonts; ++i) { - if (fonts[i]) { - delete fonts[i]; - } - } - gfree(fonts); -} - -GfxFont *GfxFontDict::lookup(const char *tag) { - int i; - - for (i = 0; i < numFonts; ++i) { - if (fonts[i] && fonts[i]->matches(tag)) { - return fonts[i]; - } - } - return NULL; -} diff --git a/xpdf/xpdf/GfxFont.h b/xpdf/xpdf/GfxFont.h deleted file mode 100644 index b50cac142..000000000 --- a/xpdf/xpdf/GfxFont.h +++ /dev/null @@ -1,317 +0,0 @@ -//======================================================================== -// -// GfxFont.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef GFXFONT_H -#define GFXFONT_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "GString.h" -#include "Object.h" -#include "CharTypes.h" - -class Dict; -class CMap; -class CharCodeToUnicode; -class FoFiTrueType; -struct GfxFontCIDWidths; - -//------------------------------------------------------------------------ -// GfxFontType -//------------------------------------------------------------------------ - -enum GfxFontType { - //----- Gfx8BitFont - fontUnknownType, - fontType1, - fontType1C, - fontType3, - fontTrueType, - //----- GfxCIDFont - fontCIDType0, - fontCIDType0C, - fontCIDType2 -}; - -//------------------------------------------------------------------------ -// GfxFontCIDWidths -//------------------------------------------------------------------------ - -struct GfxFontCIDWidthExcep { - CID first; // this record applies to - CID last; // CIDs .. - double width; // char width -}; - -struct GfxFontCIDWidthExcepV { - CID first; // this record applies to - CID last; // CIDs .. - double height; // char height - double vx, vy; // origin position -}; - -struct GfxFontCIDWidths { - double defWidth; // default char width - double defHeight; // default char height - double defVY; // default origin position - GfxFontCIDWidthExcep *exceps; // exceptions - int nExceps; // number of valid entries in exceps - GfxFontCIDWidthExcepV * // exceptions for vertical font - excepsV; - int nExcepsV; // number of valid entries in excepsV -}; - -//------------------------------------------------------------------------ -// GfxFont -//------------------------------------------------------------------------ - -#define fontFixedWidth (1 << 0) -#define fontSerif (1 << 1) -#define fontSymbolic (1 << 2) -#define fontItalic (1 << 6) -#define fontBold (1 << 18) - -class GfxFont { -public: - - // Build a GfxFont object. - static GfxFont *makeFont(XRef *xref, const char *tagA, Ref idA, Dict *fontDict); - - GfxFont(const char *tagA, Ref idA, GString *nameA); - - virtual ~GfxFont(); - - GBool isOk() { return ok; } - - // Get font tag. - GString *getTag() { return tag; } - - // Get font dictionary ID. - Ref *getID() { return &id; } - - // Does this font match the tag? - GBool matches(const char *tagA) { return !tag->cmp(tagA); } - - // Get base font name. - GString *getName() { return name; } - - // Get the original font name (ignornig any munging that might have - // been done to map to a canonical Base-14 font name). - GString *getOrigName() { return origName; } - - // Get font type. - GfxFontType getType() { return type; } - virtual GBool isCIDFont() { return gFalse; } - - // Get embedded font ID, i.e., a ref for the font file stream. - // Returns false if there is no embedded font. - GBool getEmbeddedFontID(Ref *embID) - { *embID = embFontID; return embFontID.num >= 0; } - - // Get the PostScript font name for the embedded font. Returns - // NULL if there is no embedded font. - GString *getEmbeddedFontName() { return embFontName; } - - // Get the name of the external font file. Returns NULL if there - // is no external font file. - GString *getExtFontFile() { return extFontFile; } - - // Get font descriptor flags. - GBool isFixedWidth() { return flags & fontFixedWidth; } - GBool isSerif() { return flags & fontSerif; } - GBool isSymbolic() { return flags & fontSymbolic; } - GBool isItalic() { return flags & fontItalic; } - GBool isBold() { return flags & fontBold; } - - // Return the font matrix. - double *getFontMatrix() { return fontMat; } - - // Return the font bounding box. - double *getFontBBox() { return fontBBox; } - - // Return the ascent and descent values. - double getAscent() { return ascent; } - double getDescent() { return descent; } - - // Return the writing mode (0=horizontal, 1=vertical). - virtual int getWMode() { return 0; } - - // Read an external or embedded font file into a buffer. - char *readExtFontFile(int *len); - char *readEmbFontFile(XRef *xref, int *len); - - // Get the next char from a string of bytes, returning the - // char , its Unicode mapping , its displacement vector - // (, ), and its origin offset vector (, ). - // is the number of entries available in , and is set to - // the number actually used. Returns the number of bytes used by - // the char code. - virtual int getNextChar(char *s, int len, CharCode *code, - Unicode *u, int uSize, int *uLen, - double *dx, double *dy, double *ox, double *oy) = 0; - -protected: - - void readFontDescriptor(XRef *xref, Dict *fontDict); - CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits, - CharCodeToUnicode *ctu); - void findExtFontFile(); - - GString *tag; // PDF font tag - Ref id; // reference (used as unique ID) - GString *name; // font name - GString *origName; // original font name - GfxFontType type; // type of font - int flags; // font descriptor flags - GString *embFontName; // name of embedded font - Ref embFontID; // ref to embedded font file stream - GString *extFontFile; // external font file name - double fontMat[6]; // font matrix (Type 3 only) - double fontBBox[4]; // font bounding box (Type 3 only) - double missingWidth; // "default" width - double ascent; // max height above baseline - double descent; // max depth below baseline - GBool ok; -}; - -//------------------------------------------------------------------------ -// Gfx8BitFont -//------------------------------------------------------------------------ - -class Gfx8BitFont: public GfxFont { -public: - - Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, - GfxFontType typeA, Dict *fontDict); - - virtual ~Gfx8BitFont(); - - virtual int getNextChar(char *s, int len, CharCode *code, - Unicode *u, int uSize, int *uLen, - double *dx, double *dy, double *ox, double *oy); - - // Return the encoding. - const char **getEncoding() { return enc; } - - // Return the Unicode map. - CharCodeToUnicode *getToUnicode(); - - // Return the character name associated with . - const char *getCharName(int code) { return enc[code]; } - - // Returns true if the PDF font specified an encoding. - GBool getHasEncoding() { return hasEncoding; } - - // Returns true if the PDF font specified MacRomanEncoding. - GBool getUsesMacRomanEnc() { return usesMacRomanEnc; } - - // Get width of a character. - double getWidth(Guchar c) { return widths[c]; } - - // Return a char code-to-GID mapping for the provided font file. - // (This is only useful for TrueType fonts.) - Gushort *getCodeToGIDMap(FoFiTrueType *ff); - - // Return the Type 3 CharProc dictionary, or NULL if none. - Dict *getCharProcs(); - - // Return the Type 3 CharProc for the character associated with . - Object *getCharProc(int code, Object *proc); - - // Return the Type 3 Resources dictionary, or NULL if none. - Dict *getResources(); - -private: - - const char *enc[256]; // char code --> char name - char encFree[256]; // boolean for each char name: if set, - // the string is malloc'ed - CharCodeToUnicode *ctu; // char code --> Unicode - GBool hasEncoding; - GBool usesMacRomanEnc; - double widths[256]; // character widths - Object charProcs; // Type 3 CharProcs dictionary - Object resources; // Type 3 Resources dictionary -}; - -//------------------------------------------------------------------------ -// GfxCIDFont -//------------------------------------------------------------------------ - -class GfxCIDFont: public GfxFont { -public: - - GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, - Dict *fontDict); - - virtual ~GfxCIDFont(); - - virtual GBool isCIDFont() { return gTrue; } - - virtual int getNextChar(char *s, int len, CharCode *code, - Unicode *u, int uSize, int *uLen, - double *dx, double *dy, double *ox, double *oy); - - // Return the writing mode (0=horizontal, 1=vertical). - virtual int getWMode(); - - // Return the Unicode map. - CharCodeToUnicode *getToUnicode(); - - // Get the collection name (-). - GString *getCollection(); - - // Return the CID-to-GID mapping table. These should only be called - // if type is fontCIDType2. - Gushort *getCIDToGID() { return cidToGID; } - int getCIDToGIDLen() { return cidToGIDLen; } - - Gushort *getCodeToGIDMap(FoFiTrueType *ff, int *length); - -private: - - CMap *cMap; // char code --> CID - CharCodeToUnicode *ctu; // CID --> Unicode - GfxFontCIDWidths widths; // character widths - Gushort *cidToGID; // CID --> GID mapping (for embedded - // TrueType fonts) - int cidToGIDLen; -}; - -//------------------------------------------------------------------------ -// GfxFontDict -//------------------------------------------------------------------------ - -class GfxFontDict { -public: - - // Build the font dictionary, given the PDF font dictionary. - GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict); - - // Destructor. - ~GfxFontDict(); - - // Get the specified font. - GfxFont *lookup(const char *tag); - - // Iterative access. - int getNumFonts() { return numFonts; } - GfxFont *getFont(int i) { return fonts[i]; } - -private: - - GfxFont **fonts; // list of fonts - int numFonts; // number of fonts -}; - -#endif diff --git a/xpdf/xpdf/GfxState.cc b/xpdf/xpdf/GfxState.cc deleted file mode 100644 index a2219b8be..000000000 --- a/xpdf/xpdf/GfxState.cc +++ /dev/null @@ -1,3947 +0,0 @@ -//======================================================================== -// -// GfxState.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include "gmem.h" -#include "Error.h" -#include "Object.h" -#include "Array.h" -#include "Page.h" -#include "UGString.h" -#include "GfxState.h" - -//------------------------------------------------------------------------ - -static inline GfxColorComp clip01(GfxColorComp x) { - return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x; -} - -static inline double clip01(double x) { - return (x < 0) ? 0 : (x > 1) ? 1 : x; -} - -//------------------------------------------------------------------------ - -static struct { - char *name; - GfxBlendMode mode; -} gfxBlendModeNames[] = { - { "Normal", gfxBlendNormal }, - { "Compatible", gfxBlendNormal }, - { "Multiply", gfxBlendMultiply }, - { "Screen", gfxBlendScreen }, - { "Overlay", gfxBlendOverlay }, - { "Darken", gfxBlendDarken }, - { "Lighten", gfxBlendLighten }, - { "ColorDodge", gfxBlendColorDodge }, - { "ColorBurn", gfxBlendColorBurn }, - { "HardLight", gfxBlendHardLight }, - { "SoftLight", gfxBlendSoftLight }, - { "Difference", gfxBlendDifference }, - { "Exclusion", gfxBlendExclusion }, - { "Hue", gfxBlendHue }, - { "Saturation", gfxBlendSaturation }, - { "Color", gfxBlendColor }, - { "Luminosity", gfxBlendLuminosity } -}; - -#define nGfxBlendModeNames \ - ((int)((sizeof(gfxBlendModeNames) / sizeof(char *)))) - -//------------------------------------------------------------------------ - -// NB: This must match the GfxColorSpaceMode enum defined in -// GfxState.h -static const char *gfxColorSpaceModeNames[] = { - "DeviceGray", - "CalGray", - "DeviceRGB", - "CalRGB", - "DeviceCMYK", - "Lab", - "ICCBased", - "Indexed", - "Separation", - "DeviceN", - "Pattern" -}; - -#define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *))) - -//------------------------------------------------------------------------ -// GfxColorSpace -//------------------------------------------------------------------------ - -GfxColorSpace::GfxColorSpace() { -} - -GfxColorSpace::~GfxColorSpace() { -} - -GfxColorSpace *GfxColorSpace::parse(Object *csObj) { - GfxColorSpace *cs; - Object obj1; - - cs = NULL; - if (csObj->isName()) { - if (csObj->isName("DeviceGray") || csObj->isName("G")) { - cs = new GfxDeviceGrayColorSpace(); - } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) { - cs = new GfxDeviceRGBColorSpace(); - } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) { - cs = new GfxDeviceCMYKColorSpace(); - } else if (csObj->isName("Pattern")) { - cs = new GfxPatternColorSpace(NULL); - } else { - error(-1, "Bad color space '%s'", csObj->getName()); - } - } else if (csObj->isArray()) { - csObj->arrayGet(0, &obj1); - if (obj1.isName("DeviceGray") || obj1.isName("G")) { - cs = new GfxDeviceGrayColorSpace(); - } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) { - cs = new GfxDeviceRGBColorSpace(); - } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) { - cs = new GfxDeviceCMYKColorSpace(); - } else if (obj1.isName("CalGray")) { - cs = GfxCalGrayColorSpace::parse(csObj->getArray()); - } else if (obj1.isName("CalRGB")) { - cs = GfxCalRGBColorSpace::parse(csObj->getArray()); - } else if (obj1.isName("Lab")) { - cs = GfxLabColorSpace::parse(csObj->getArray()); - } else if (obj1.isName("ICCBased")) { - cs = GfxICCBasedColorSpace::parse(csObj->getArray()); - } else if (obj1.isName("Indexed") || obj1.isName("I")) { - cs = GfxIndexedColorSpace::parse(csObj->getArray()); - } else if (obj1.isName("Separation")) { - cs = GfxSeparationColorSpace::parse(csObj->getArray()); - } else if (obj1.isName("DeviceN")) { - cs = GfxDeviceNColorSpace::parse(csObj->getArray()); - } else if (obj1.isName("Pattern")) { - cs = GfxPatternColorSpace::parse(csObj->getArray()); - } else { - error(-1, "Bad color space"); - } - obj1.free(); - } else { - error(-1, "Bad color space - expected name or array"); - } - return cs; -} - -void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, - int /*maxImgPixel*/) { - int i; - - for (i = 0; i < getNComps(); ++i) { - decodeLow[i] = 0; - decodeRange[i] = 1; - } -} - -int GfxColorSpace::getNumColorSpaceModes() { - return nGfxColorSpaceModes; -} - -const char *GfxColorSpace::getColorSpaceModeName(int idx) { - return gfxColorSpaceModeNames[idx]; -} - -//------------------------------------------------------------------------ -// GfxDeviceGrayColorSpace -//------------------------------------------------------------------------ - -GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() { -} - -GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() { -} - -GfxColorSpace *GfxDeviceGrayColorSpace::copy() { - return new GfxDeviceGrayColorSpace(); -} - -void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { - *gray = clip01(color->c[0]); -} - -void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - rgb->r = rgb->g = rgb->b = clip01(color->c[0]); -} - -void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - cmyk->c = cmyk->m = cmyk->y = 0; - cmyk->k = clip01(gfxColorComp1 - color->c[0]); -} - -//------------------------------------------------------------------------ -// GfxCalGrayColorSpace -//------------------------------------------------------------------------ - -GfxCalGrayColorSpace::GfxCalGrayColorSpace() { - whiteX = whiteY = whiteZ = 1; - blackX = blackY = blackZ = 0; - gamma = 1; -} - -GfxCalGrayColorSpace::~GfxCalGrayColorSpace() { -} - -GfxColorSpace *GfxCalGrayColorSpace::copy() { - GfxCalGrayColorSpace *cs; - - cs = new GfxCalGrayColorSpace(); - cs->whiteX = whiteX; - cs->whiteY = whiteY; - cs->whiteZ = whiteZ; - cs->blackX = blackX; - cs->blackY = blackY; - cs->blackZ = blackZ; - cs->gamma = gamma; - return cs; -} - -GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) { - GfxCalGrayColorSpace *cs; - Object obj1, obj2, obj3; - - arr->get(1, &obj1); - if (!obj1.isDict()) { - error(-1, "Bad CalGray color space"); - obj1.free(); - return NULL; - } - cs = new GfxCalGrayColorSpace(); - if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && - obj2.arrayGetLength() == 3) { - obj2.arrayGet(0, &obj3); - cs->whiteX = obj3.getNum(); - obj3.free(); - obj2.arrayGet(1, &obj3); - cs->whiteY = obj3.getNum(); - obj3.free(); - obj2.arrayGet(2, &obj3); - cs->whiteZ = obj3.getNum(); - obj3.free(); - } - obj2.free(); - if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && - obj2.arrayGetLength() == 3) { - obj2.arrayGet(0, &obj3); - cs->blackX = obj3.getNum(); - obj3.free(); - obj2.arrayGet(1, &obj3); - cs->blackY = obj3.getNum(); - obj3.free(); - obj2.arrayGet(2, &obj3); - cs->blackZ = obj3.getNum(); - obj3.free(); - } - obj2.free(); - if (obj1.dictLookup("Gamma", &obj2)->isNum()) { - cs->gamma = obj2.getNum(); - } - obj2.free(); - obj1.free(); - return cs; -} - -void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { - *gray = clip01(color->c[0]); -} - -void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - rgb->r = rgb->g = rgb->b = clip01(color->c[0]); -} - -void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - cmyk->c = cmyk->m = cmyk->y = 0; - cmyk->k = clip01(gfxColorComp1 - color->c[0]); -} - -//------------------------------------------------------------------------ -// GfxDeviceRGBColorSpace -//------------------------------------------------------------------------ - -GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() { -} - -GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() { -} - -GfxColorSpace *GfxDeviceRGBColorSpace::copy() { - return new GfxDeviceRGBColorSpace(); -} - -void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { - *gray = clip01((GfxColorComp)(0.3 * color->c[0] + - 0.59 * color->c[1] + - 0.11 * color->c[2] + 0.5)); -} - -void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - rgb->r = clip01(color->c[0]); - rgb->g = clip01(color->c[1]); - rgb->b = clip01(color->c[2]); -} - -void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - GfxColorComp c, m, y, k; - - c = clip01(gfxColorComp1 - color->c[0]); - m = clip01(gfxColorComp1 - color->c[1]); - y = clip01(gfxColorComp1 - color->c[2]); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - cmyk->c = c - k; - cmyk->m = m - k; - cmyk->y = y - k; - cmyk->k = k; -} - -//------------------------------------------------------------------------ -// GfxCalRGBColorSpace -//------------------------------------------------------------------------ - -GfxCalRGBColorSpace::GfxCalRGBColorSpace() { - whiteX = whiteY = whiteZ = 1; - blackX = blackY = blackZ = 0; - gammaR = gammaG = gammaB = 1; - mat[0] = 1; mat[1] = 0; mat[2] = 0; - mat[3] = 0; mat[4] = 1; mat[5] = 0; - mat[6] = 0; mat[7] = 0; mat[8] = 1; -} - -GfxCalRGBColorSpace::~GfxCalRGBColorSpace() { -} - -GfxColorSpace *GfxCalRGBColorSpace::copy() { - GfxCalRGBColorSpace *cs; - int i; - - cs = new GfxCalRGBColorSpace(); - cs->whiteX = whiteX; - cs->whiteY = whiteY; - cs->whiteZ = whiteZ; - cs->blackX = blackX; - cs->blackY = blackY; - cs->blackZ = blackZ; - cs->gammaR = gammaR; - cs->gammaG = gammaG; - cs->gammaB = gammaB; - for (i = 0; i < 9; ++i) { - cs->mat[i] = mat[i]; - } - return cs; -} - -GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) { - GfxCalRGBColorSpace *cs; - Object obj1, obj2, obj3; - int i; - - arr->get(1, &obj1); - if (!obj1.isDict()) { - error(-1, "Bad CalRGB color space"); - obj1.free(); - return NULL; - } - cs = new GfxCalRGBColorSpace(); - if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && - obj2.arrayGetLength() == 3) { - obj2.arrayGet(0, &obj3); - cs->whiteX = obj3.getNum(); - obj3.free(); - obj2.arrayGet(1, &obj3); - cs->whiteY = obj3.getNum(); - obj3.free(); - obj2.arrayGet(2, &obj3); - cs->whiteZ = obj3.getNum(); - obj3.free(); - } - obj2.free(); - if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && - obj2.arrayGetLength() == 3) { - obj2.arrayGet(0, &obj3); - cs->blackX = obj3.getNum(); - obj3.free(); - obj2.arrayGet(1, &obj3); - cs->blackY = obj3.getNum(); - obj3.free(); - obj2.arrayGet(2, &obj3); - cs->blackZ = obj3.getNum(); - obj3.free(); - } - obj2.free(); - if (obj1.dictLookup("Gamma", &obj2)->isArray() && - obj2.arrayGetLength() == 3) { - obj2.arrayGet(0, &obj3); - cs->gammaR = obj3.getNum(); - obj3.free(); - obj2.arrayGet(1, &obj3); - cs->gammaG = obj3.getNum(); - obj3.free(); - obj2.arrayGet(2, &obj3); - cs->gammaB = obj3.getNum(); - obj3.free(); - } - obj2.free(); - if (obj1.dictLookup("Matrix", &obj2)->isArray() && - obj2.arrayGetLength() == 9) { - for (i = 0; i < 9; ++i) { - obj2.arrayGet(i, &obj3); - cs->mat[i] = obj3.getNum(); - obj3.free(); - } - } - obj2.free(); - obj1.free(); - return cs; -} - -void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { - *gray = clip01((GfxColorComp)(0.299 * color->c[0] + - 0.587 * color->c[1] + - 0.114 * color->c[2] + 0.5)); -} - -void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - rgb->r = clip01(color->c[0]); - rgb->g = clip01(color->c[1]); - rgb->b = clip01(color->c[2]); -} - -void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - GfxColorComp c, m, y, k; - - c = clip01(gfxColorComp1 - color->c[0]); - m = clip01(gfxColorComp1 - color->c[1]); - y = clip01(gfxColorComp1 - color->c[2]); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - cmyk->c = c - k; - cmyk->m = m - k; - cmyk->y = y - k; - cmyk->k = k; -} - -//------------------------------------------------------------------------ -// GfxDeviceCMYKColorSpace -//------------------------------------------------------------------------ - -GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() { -} - -GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() { -} - -GfxColorSpace *GfxDeviceCMYKColorSpace::copy() { - return new GfxDeviceCMYKColorSpace(); -} - -void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) { - *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3] - - 0.3 * color->c[0] - - 0.59 * color->c[1] - - 0.11 * color->c[2] + 0.5)); -} - -void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double c, m, y, k, c1, m1, y1, k1, r, g, b, x; - - c = colToDbl(color->c[0]); - m = colToDbl(color->c[1]); - y = colToDbl(color->c[2]); - k = colToDbl(color->c[3]); - c1 = 1 - c; - m1 = 1 - m; - y1 = 1 - y; - k1 = 1 - k; - // this is a matrix multiplication, unrolled for performance - // C M Y K - x = c1 * m1 * y1 * k1; // 0 0 0 0 - r = g = b = x; - x = c1 * m1 * y1 * k; // 0 0 0 1 - r += 0.1373 * x; - g += 0.1216 * x; - b += 0.1255 * x; - x = c1 * m1 * y * k1; // 0 0 1 0 - r += x; - g += 0.9490 * x; - x = c1 * m1 * y * k; // 0 0 1 1 - r += 0.1098 * x; - g += 0.1020 * x; - x = c1 * m * y1 * k1; // 0 1 0 0 - r += 0.9255 * x; - b += 0.5490 * x; - x = c1 * m * y1 * k; // 0 1 0 1 - r += 0.1412 * x; - x = c1 * m * y * k1; // 0 1 1 0 - r += 0.9294 * x; - g += 0.1098 * x; - b += 0.1412 * x; - x = c1 * m * y * k; // 0 1 1 1 - r += 0.1333 * x; - x = c * m1 * y1 * k1; // 1 0 0 0 - g += 0.6784 * x; - b += 0.9373 * x; - x = c * m1 * y1 * k; // 1 0 0 1 - g += 0.0588 * x; - b += 0.1412 * x; - x = c * m1 * y * k1; // 1 0 1 0 - g += 0.6510 * x; - b += 0.3137 * x; - x = c * m1 * y * k; // 1 0 1 1 - g += 0.0745 * x; - x = c * m * y1 * k1; // 1 1 0 0 - r += 0.1804 * x; - g += 0.1922 * x; - b += 0.5725 * x; - x = c * m * y1 * k; // 1 1 0 1 - b += 0.0078 * x; - x = c * m * y * k1; // 1 1 1 0 - r += 0.2118 * x; - g += 0.2119 * x; - b += 0.2235 * x; - rgb->r = clip01(dblToCol(r)); - rgb->g = clip01(dblToCol(g)); - rgb->b = clip01(dblToCol(b)); -} - -void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - cmyk->c = clip01(color->c[0]); - cmyk->m = clip01(color->c[1]); - cmyk->y = clip01(color->c[2]); - cmyk->k = clip01(color->c[3]); -} - -//------------------------------------------------------------------------ -// GfxLabColorSpace -//------------------------------------------------------------------------ - -// This is the inverse of MatrixLMN in Example 4.10 from the PostScript -// Language Reference, Third Edition. -static double xyzrgb[3][3] = { - { 3.240449, -1.537136, -0.498531 }, - { -0.969265, 1.876011, 0.041556 }, - { 0.055643, -0.204026, 1.057229 } -}; - -GfxLabColorSpace::GfxLabColorSpace() { - whiteX = whiteY = whiteZ = 1; - blackX = blackY = blackZ = 0; - aMin = bMin = -100; - aMax = bMax = 100; -} - -GfxLabColorSpace::~GfxLabColorSpace() { -} - -GfxColorSpace *GfxLabColorSpace::copy() { - GfxLabColorSpace *cs; - - cs = new GfxLabColorSpace(); - cs->whiteX = whiteX; - cs->whiteY = whiteY; - cs->whiteZ = whiteZ; - cs->blackX = blackX; - cs->blackY = blackY; - cs->blackZ = blackZ; - cs->aMin = aMin; - cs->aMax = aMax; - cs->bMin = bMin; - cs->bMax = bMax; - cs->kr = kr; - cs->kg = kg; - cs->kb = kb; - return cs; -} - -GfxColorSpace *GfxLabColorSpace::parse(Array *arr) { - GfxLabColorSpace *cs; - Object obj1, obj2, obj3; - - arr->get(1, &obj1); - if (!obj1.isDict()) { - error(-1, "Bad Lab color space"); - obj1.free(); - return NULL; - } - cs = new GfxLabColorSpace(); - if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && - obj2.arrayGetLength() == 3) { - obj2.arrayGet(0, &obj3); - cs->whiteX = obj3.getNum(); - obj3.free(); - obj2.arrayGet(1, &obj3); - cs->whiteY = obj3.getNum(); - obj3.free(); - obj2.arrayGet(2, &obj3); - cs->whiteZ = obj3.getNum(); - obj3.free(); - } - obj2.free(); - if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && - obj2.arrayGetLength() == 3) { - obj2.arrayGet(0, &obj3); - cs->blackX = obj3.getNum(); - obj3.free(); - obj2.arrayGet(1, &obj3); - cs->blackY = obj3.getNum(); - obj3.free(); - obj2.arrayGet(2, &obj3); - cs->blackZ = obj3.getNum(); - obj3.free(); - } - obj2.free(); - if (obj1.dictLookup("Range", &obj2)->isArray() && - obj2.arrayGetLength() == 4) { - obj2.arrayGet(0, &obj3); - cs->aMin = obj3.getNum(); - obj3.free(); - obj2.arrayGet(1, &obj3); - cs->aMax = obj3.getNum(); - obj3.free(); - obj2.arrayGet(2, &obj3); - cs->bMin = obj3.getNum(); - obj3.free(); - obj2.arrayGet(3, &obj3); - cs->bMax = obj3.getNum(); - obj3.free(); - } - obj2.free(); - obj1.free(); - - cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX + - xyzrgb[0][1] * cs->whiteY + - xyzrgb[0][2] * cs->whiteZ); - cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX + - xyzrgb[1][1] * cs->whiteY + - xyzrgb[1][2] * cs->whiteZ); - cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX + - xyzrgb[2][1] * cs->whiteY + - xyzrgb[2][2] * cs->whiteZ); - - return cs; -} - -void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) { - GfxRGB rgb; - - getRGB(color, &rgb); - *gray = clip01((GfxColorComp)(0.299 * rgb.r + - 0.587 * rgb.g + - 0.114 * rgb.b + 0.5)); -} - -void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double X, Y, Z; - double t1, t2; - double r, g, b; - - // convert L*a*b* to CIE 1931 XYZ color space - t1 = (colToDbl(color->c[0]) + 16) / 116; - t2 = t1 + colToDbl(color->c[1]) / 500; - if (t2 >= (6.0 / 29.0)) { - X = t2 * t2 * t2; - } else { - X = (108.0 / 841.0) * (t2 - (4.0 / 29.0)); - } - X *= whiteX; - if (t1 >= (6.0 / 29.0)) { - Y = t1 * t1 * t1; - } else { - Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0)); - } - Y *= whiteY; - t2 = t1 - colToDbl(color->c[2]) / 200; - if (t2 >= (6.0 / 29.0)) { - Z = t2 * t2 * t2; - } else { - Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0)); - } - Z *= whiteZ; - - // convert XYZ to RGB, including gamut mapping and gamma correction - r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z; - g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z; - b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z; - rgb->r = dblToCol(pow(clip01(r * kr), 0.5)); - rgb->g = dblToCol(pow(clip01(g * kg), 0.5)); - rgb->b = dblToCol(pow(clip01(b * kb), 0.5)); -} - -void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - GfxRGB rgb; - GfxColorComp c, m, y, k; - - getRGB(color, &rgb); - c = clip01(gfxColorComp1 - rgb.r); - m = clip01(gfxColorComp1 - rgb.g); - y = clip01(gfxColorComp1 - rgb.b); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - cmyk->c = c - k; - cmyk->m = m - k; - cmyk->y = y - k; - cmyk->k = k; -} - -void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, - int /*maxImgPixel*/) { - decodeLow[0] = 0; - decodeRange[0] = 100; - decodeLow[1] = aMin; - decodeRange[1] = aMax - aMin; - decodeLow[2] = bMin; - decodeRange[2] = bMax - bMin; -} - -//------------------------------------------------------------------------ -// GfxICCBasedColorSpace -//------------------------------------------------------------------------ - -GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA, - Ref *iccProfileStreamA) { - nComps = nCompsA; - alt = altA; - iccProfileStream = *iccProfileStreamA; - rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0; - rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1; -} - -GfxICCBasedColorSpace::~GfxICCBasedColorSpace() { - delete alt; -} - -GfxColorSpace *GfxICCBasedColorSpace::copy() { - GfxICCBasedColorSpace *cs; - int i; - - cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream); - for (i = 0; i < 4; ++i) { - cs->rangeMin[i] = rangeMin[i]; - cs->rangeMax[i] = rangeMax[i]; - } - return cs; -} - -GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) { - GfxICCBasedColorSpace *cs; - Ref iccProfileStreamA; - int nCompsA; - GfxColorSpace *altA; - Dict *dict; - Object obj1, obj2, obj3; - int i; - - arr->getNF(1, &obj1); - if (obj1.isRef()) { - iccProfileStreamA = obj1.getRef(); - } else { - iccProfileStreamA.num = 0; - iccProfileStreamA.gen = 0; - } - obj1.free(); - arr->get(1, &obj1); - if (!obj1.isStream()) { - error(-1, "Bad ICCBased color space (stream)"); - obj1.free(); - return NULL; - } - dict = obj1.streamGetDict(); - if (!dict->lookup("N", &obj2)->isInt()) { - error(-1, "Bad ICCBased color space (N)"); - obj2.free(); - obj1.free(); - return NULL; - } - nCompsA = obj2.getInt(); - obj2.free(); - if (nCompsA > gfxColorMaxComps) { - error(-1, "ICCBased color space with too many (%d > %d) components", - nCompsA, gfxColorMaxComps); - nCompsA = gfxColorMaxComps; - } - if (dict->lookup("Alternate", &obj2)->isNull() || - !(altA = GfxColorSpace::parse(&obj2))) { - switch (nCompsA) { - case 1: - altA = new GfxDeviceGrayColorSpace(); - break; - case 3: - altA = new GfxDeviceRGBColorSpace(); - break; - case 4: - altA = new GfxDeviceCMYKColorSpace(); - break; - default: - error(-1, "Bad ICCBased color space - invalid N"); - obj2.free(); - obj1.free(); - return NULL; - } - } - obj2.free(); - cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA); - if (dict->lookup("Range", &obj2)->isArray() && - obj2.arrayGetLength() == 2 * nCompsA) { - for (i = 0; i < nCompsA; ++i) { - obj2.arrayGet(2*i, &obj3); - cs->rangeMin[i] = obj3.getNum(); - obj3.free(); - obj2.arrayGet(2*i+1, &obj3); - cs->rangeMax[i] = obj3.getNum(); - obj3.free(); - } - } - obj2.free(); - obj1.free(); - return cs; -} - -void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) { - alt->getGray(color, gray); -} - -void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - alt->getRGB(color, rgb); -} - -void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - alt->getCMYK(color, cmyk); -} - -void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow, - double *decodeRange, - int maxImgPixel) { - alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel); - -#if 0 - // this is nominally correct, but some PDF files don't set the - // correct ranges in the ICCBased dict - int i; - - for (i = 0; i < nComps; ++i) { - decodeLow[i] = rangeMin[i]; - decodeRange[i] = rangeMax[i] - rangeMin[i]; - } -#endif -} - -//------------------------------------------------------------------------ -// GfxIndexedColorSpace -//------------------------------------------------------------------------ - -GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA, - int indexHighA) { - base = baseA; - indexHigh = indexHighA; - lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(), - sizeof(Guchar)); -} - -GfxIndexedColorSpace::~GfxIndexedColorSpace() { - delete base; - gfree(lookup); -} - -GfxColorSpace *GfxIndexedColorSpace::copy() { - GfxIndexedColorSpace *cs; - - cs = new GfxIndexedColorSpace(base->copy(), indexHigh); - memcpy(cs->lookup, lookup, - (indexHigh + 1) * base->getNComps() * sizeof(Guchar)); - return cs; -} - -GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) { - GfxIndexedColorSpace *cs; - GfxColorSpace *baseA; - int indexHighA; - Object obj1; - int x; - char *s; - int n, i, j; - - if (arr->getLength() != 4) { - error(-1, "Bad Indexed color space"); - goto err1; - } - arr->get(1, &obj1); - if (!(baseA = GfxColorSpace::parse(&obj1))) { - error(-1, "Bad Indexed color space (base color space)"); - goto err2; - } - obj1.free(); - if (!arr->get(2, &obj1)->isInt()) { - error(-1, "Bad Indexed color space (hival)"); - delete baseA; - goto err2; - } - indexHighA = obj1.getInt(); - if (indexHighA < 0 || indexHighA > 255) { - // the PDF spec requires indexHigh to be in [0,255] -- allowing - // values larger than 255 creates a security hole: if nComps * - // indexHigh is greater than 2^31, the loop below may overwrite - // past the end of the array - error(-1, "Bad Indexed color space (invalid indexHigh value)"); - delete baseA; - goto err2; - } - obj1.free(); - cs = new GfxIndexedColorSpace(baseA, indexHighA); - arr->get(3, &obj1); - n = baseA->getNComps(); - if (obj1.isStream()) { - obj1.streamReset(); - for (i = 0; i <= indexHighA; ++i) { - for (j = 0; j < n; ++j) { - if ((x = obj1.streamGetChar()) == EOF) { - error(-1, "Bad Indexed color space (lookup table stream too short)"); - goto err3; - } - cs->lookup[i*n + j] = (Guchar)x; - } - } - obj1.streamClose(); - } else if (obj1.isString()) { - if (obj1.getString()->getLength() < (indexHighA + 1) * n) { - error(-1, "Bad Indexed color space (lookup table string too short)"); - goto err3; - } - s = obj1.getString()->getCString(); - for (i = 0; i <= indexHighA; ++i) { - for (j = 0; j < n; ++j) { - cs->lookup[i*n + j] = (Guchar)*s++; - } - } - } else { - error(-1, "Bad Indexed color space (lookup table)"); - goto err3; - } - obj1.free(); - return cs; - - err3: - delete cs; - err2: - obj1.free(); - err1: - return NULL; -} - -GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color, - GfxColor *baseColor) { - Guchar *p; - double low[gfxColorMaxComps], range[gfxColorMaxComps]; - int n, i; - - n = base->getNComps(); - base->getDefaultRanges(low, range, indexHigh); - p = &lookup[(int)(colToDbl(color->c[0]) + 0.5) * n]; - for (i = 0; i < n; ++i) { - baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]); - } - return baseColor; -} - -void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) { - GfxColor color2; - - base->getGray(mapColorToBase(color, &color2), gray); -} - -void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - GfxColor color2; - - base->getRGB(mapColorToBase(color, &color2), rgb); -} - -void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - GfxColor color2; - - base->getCMYK(mapColorToBase(color, &color2), cmyk); -} - -void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow, - double *decodeRange, - int maxImgPixel) { - decodeLow[0] = 0; - decodeRange[0] = maxImgPixel; -} - -//------------------------------------------------------------------------ -// GfxSeparationColorSpace -//------------------------------------------------------------------------ - -GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA, - GfxColorSpace *altA, - Function *funcA) { - name = nameA; - alt = altA; - func = funcA; -} - -GfxSeparationColorSpace::~GfxSeparationColorSpace() { - delete name; - delete alt; - delete func; -} - -GfxColorSpace *GfxSeparationColorSpace::copy() { - return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy()); -} - -//~ handle the 'All' and 'None' colorants -GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) { - GfxSeparationColorSpace *cs; - GString *nameA; - GfxColorSpace *altA; - Function *funcA; - Object obj1; - - if (arr->getLength() != 4) { - error(-1, "Bad Separation color space"); - goto err1; - } - if (!arr->get(1, &obj1)->isName()) { - error(-1, "Bad Separation color space (name)"); - goto err2; - } - nameA = new GString(obj1.getName()); - obj1.free(); - arr->get(2, &obj1); - if (!(altA = GfxColorSpace::parse(&obj1))) { - error(-1, "Bad Separation color space (alternate color space)"); - goto err3; - } - obj1.free(); - arr->get(3, &obj1); - if (!(funcA = Function::parse(&obj1))) { - goto err4; - } - obj1.free(); - cs = new GfxSeparationColorSpace(nameA, altA, funcA); - return cs; - - err4: - delete altA; - err3: - delete nameA; - err2: - obj1.free(); - err1: - return NULL; -} - -void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) { - double x; - double c[gfxColorMaxComps]; - GfxColor color2; - int i; - - x = colToDbl(color->c[0]); - func->transform(&x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getGray(&color2, gray); -} - -void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double x; - double c[gfxColorMaxComps]; - GfxColor color2; - int i; - - x = colToDbl(color->c[0]); - func->transform(&x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getRGB(&color2, rgb); -} - -void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - double x; - double c[gfxColorMaxComps]; - GfxColor color2; - int i; - - x = colToDbl(color->c[0]); - func->transform(&x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getCMYK(&color2, cmyk); -} - -//------------------------------------------------------------------------ -// GfxDeviceNColorSpace -//------------------------------------------------------------------------ - -GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, - GfxColorSpace *altA, - Function *funcA) { - nComps = nCompsA; - alt = altA; - func = funcA; -} - -GfxDeviceNColorSpace::~GfxDeviceNColorSpace() { - int i; - - for (i = 0; i < nComps; ++i) { - delete names[i]; - } - delete alt; - delete func; -} - -GfxColorSpace *GfxDeviceNColorSpace::copy() { - GfxDeviceNColorSpace *cs; - int i; - - cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy()); - for (i = 0; i < nComps; ++i) { - cs->names[i] = names[i]->copy(); - } - return cs; -} - -//~ handle the 'None' colorant -GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) { - GfxDeviceNColorSpace *cs; - int nCompsA; - GString *namesA[gfxColorMaxComps]; - GfxColorSpace *altA; - Function *funcA; - Object obj1, obj2; - int i; - - if (arr->getLength() != 4 && arr->getLength() != 5) { - error(-1, "Bad DeviceN color space"); - goto err1; - } - if (!arr->get(1, &obj1)->isArray()) { - error(-1, "Bad DeviceN color space (names)"); - goto err2; - } - nCompsA = obj1.arrayGetLength(); - if (nCompsA > gfxColorMaxComps) { - error(-1, "DeviceN color space with too many (%d > %d) components", - nCompsA, gfxColorMaxComps); - nCompsA = gfxColorMaxComps; - } - for (i = 0; i < nCompsA; ++i) { - if (!obj1.arrayGet(i, &obj2)->isName()) { - error(-1, "Bad DeviceN color space (names)"); - obj2.free(); - goto err2; - } - namesA[i] = new GString(obj2.getName()); - obj2.free(); - } - obj1.free(); - arr->get(2, &obj1); - if (!(altA = GfxColorSpace::parse(&obj1))) { - error(-1, "Bad DeviceN color space (alternate color space)"); - goto err3; - } - obj1.free(); - arr->get(3, &obj1); - if (!(funcA = Function::parse(&obj1))) { - goto err4; - } - obj1.free(); - cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA); - for (i = 0; i < nCompsA; ++i) { - cs->names[i] = namesA[i]; - } - return cs; - - err4: - delete altA; - err3: - for (i = 0; i < nCompsA; ++i) { - delete namesA[i]; - } - err2: - obj1.free(); - err1: - return NULL; -} - -void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) { - double x[gfxColorMaxComps], c[gfxColorMaxComps]; - GfxColor color2; - int i; - - for (i = 0; i < nComps; ++i) { - x[i] = colToDbl(color->c[i]); - } - func->transform(x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getGray(&color2, gray); -} - -void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double x[gfxColorMaxComps], c[gfxColorMaxComps]; - GfxColor color2; - int i; - - for (i = 0; i < nComps; ++i) { - x[i] = colToDbl(color->c[i]); - } - func->transform(x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getRGB(&color2, rgb); -} - -void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - double x[gfxColorMaxComps], c[gfxColorMaxComps]; - GfxColor color2; - int i; - - for (i = 0; i < nComps; ++i) { - x[i] = colToDbl(color->c[i]); - } - func->transform(x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getCMYK(&color2, cmyk); -} - -//------------------------------------------------------------------------ -// GfxPatternColorSpace -//------------------------------------------------------------------------ - -GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) { - under = underA; -} - -GfxPatternColorSpace::~GfxPatternColorSpace() { - if (under) { - delete under; - } -} - -GfxColorSpace *GfxPatternColorSpace::copy() { - return new GfxPatternColorSpace(under ? under->copy() : - (GfxColorSpace *)NULL); -} - -GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) { - GfxPatternColorSpace *cs; - GfxColorSpace *underA; - Object obj1; - - if (arr->getLength() != 1 && arr->getLength() != 2) { - error(-1, "Bad Pattern color space"); - return NULL; - } - underA = NULL; - if (arr->getLength() == 2) { - arr->get(1, &obj1); - if (!(underA = GfxColorSpace::parse(&obj1))) { - error(-1, "Bad Pattern color space (underlying color space)"); - obj1.free(); - return NULL; - } - obj1.free(); - } - cs = new GfxPatternColorSpace(underA); - return cs; -} - -void GfxPatternColorSpace::getGray(GfxColor */*color*/, GfxGray *gray) { - *gray = 0; -} - -void GfxPatternColorSpace::getRGB(GfxColor */*color*/, GfxRGB *rgb) { - rgb->r = rgb->g = rgb->b = 0; -} - -void GfxPatternColorSpace::getCMYK(GfxColor */*color*/, GfxCMYK *cmyk) { - cmyk->c = cmyk->m = cmyk->y = 0; - cmyk->k = 1; -} - -//------------------------------------------------------------------------ -// Pattern -//------------------------------------------------------------------------ - -GfxPattern::GfxPattern(int typeA) { - type = typeA; -} - -GfxPattern::~GfxPattern() { -} - -GfxPattern *GfxPattern::parse(Object *obj) { - GfxPattern *pattern; - Object obj1; - - if (obj->isDict()) { - obj->dictLookup("PatternType", &obj1); - } else if (obj->isStream()) { - obj->streamGetDict()->lookup("PatternType", &obj1); - } else { - return NULL; - } - pattern = NULL; - if (obj1.isInt() && obj1.getInt() == 1) { - pattern = GfxTilingPattern::parse(obj); - } else if (obj1.isInt() && obj1.getInt() == 2) { - pattern = GfxShadingPattern::parse(obj); - } - obj1.free(); - return pattern; -} - -//------------------------------------------------------------------------ -// GfxTilingPattern -//------------------------------------------------------------------------ - -GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) { - GfxTilingPattern *pat; - Dict *dict; - int paintTypeA, tilingTypeA; - double bboxA[4], matrixA[6]; - double xStepA, yStepA; - Object resDictA; - Object obj1, obj2; - int i; - - if (!patObj->isStream()) { - return NULL; - } - dict = patObj->streamGetDict(); - - if (dict->lookup("PaintType", &obj1)->isInt()) { - paintTypeA = obj1.getInt(); - } else { - paintTypeA = 1; - error(-1, "Invalid or missing PaintType in pattern"); - } - obj1.free(); - if (dict->lookup("TilingType", &obj1)->isInt()) { - tilingTypeA = obj1.getInt(); - } else { - tilingTypeA = 1; - error(-1, "Invalid or missing TilingType in pattern"); - } - obj1.free(); - bboxA[0] = bboxA[1] = 0; - bboxA[2] = bboxA[3] = 1; - if (dict->lookup("BBox", &obj1)->isArray() && - obj1.arrayGetLength() == 4) { - for (i = 0; i < 4; ++i) { - if (obj1.arrayGet(i, &obj2)->isNum()) { - bboxA[i] = obj2.getNum(); - } - obj2.free(); - } - } else { - error(-1, "Invalid or missing BBox in pattern"); - } - obj1.free(); - if (dict->lookup("XStep", &obj1)->isNum()) { - xStepA = obj1.getNum(); - } else { - xStepA = 1; - error(-1, "Invalid or missing XStep in pattern"); - } - obj1.free(); - if (dict->lookup("YStep", &obj1)->isNum()) { - yStepA = obj1.getNum(); - } else { - yStepA = 1; - error(-1, "Invalid or missing YStep in pattern"); - } - obj1.free(); - if (!dict->lookup("Resources", &resDictA)->isDict()) { - resDictA.free(); - resDictA.initNull(); - error(-1, "Invalid or missing Resources in pattern"); - } - matrixA[0] = 1; matrixA[1] = 0; - matrixA[2] = 0; matrixA[3] = 1; - matrixA[4] = 0; matrixA[5] = 0; - if (dict->lookup("Matrix", &obj1)->isArray() && - obj1.arrayGetLength() == 6) { - for (i = 0; i < 6; ++i) { - if (obj1.arrayGet(i, &obj2)->isNum()) { - matrixA[i] = obj2.getNum(); - } - obj2.free(); - } - } - obj1.free(); - - pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA, - &resDictA, matrixA, patObj); - resDictA.free(); - return pat; -} - -GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA, - double *bboxA, double xStepA, double yStepA, - Object *resDictA, double *matrixA, - Object *contentStreamA): - GfxPattern(1) -{ - int i; - - paintType = paintTypeA; - tilingType = tilingTypeA; - for (i = 0; i < 4; ++i) { - bbox[i] = bboxA[i]; - } - xStep = xStepA; - yStep = yStepA; - resDictA->copy(&resDict); - for (i = 0; i < 6; ++i) { - matrix[i] = matrixA[i]; - } - contentStreamA->copy(&contentStream); -} - -GfxTilingPattern::~GfxTilingPattern() { - resDict.free(); - contentStream.free(); -} - -GfxPattern *GfxTilingPattern::copy() { - return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep, - &resDict, matrix, &contentStream); -} - -//------------------------------------------------------------------------ -// GfxShadingPattern -//------------------------------------------------------------------------ - -GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) { - Dict *dict; - GfxShading *shadingA; - double matrixA[6]; - Object obj1, obj2; - int i; - - if (!patObj->isDict()) { - return NULL; - } - dict = patObj->getDict(); - - dict->lookup("Shading", &obj1); - shadingA = GfxShading::parse(&obj1); - obj1.free(); - if (!shadingA) { - return NULL; - } - - matrixA[0] = 1; matrixA[1] = 0; - matrixA[2] = 0; matrixA[3] = 1; - matrixA[4] = 0; matrixA[5] = 0; - if (dict->lookup("Matrix", &obj1)->isArray() && - obj1.arrayGetLength() == 6) { - for (i = 0; i < 6; ++i) { - if (obj1.arrayGet(i, &obj2)->isNum()) { - matrixA[i] = obj2.getNum(); - } - obj2.free(); - } - } - obj1.free(); - - return new GfxShadingPattern(shadingA, matrixA); -} - -GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA): - GfxPattern(2) -{ - int i; - - shading = shadingA; - for (i = 0; i < 6; ++i) { - matrix[i] = matrixA[i]; - } -} - -GfxShadingPattern::~GfxShadingPattern() { - delete shading; -} - -GfxPattern *GfxShadingPattern::copy() { - return new GfxShadingPattern(shading->copy(), matrix); -} - -//------------------------------------------------------------------------ -// GfxShading -//------------------------------------------------------------------------ - -GfxShading::GfxShading(int typeA) { - type = typeA; - colorSpace = NULL; -} - -GfxShading::GfxShading(GfxShading *shading) { - int i; - - type = shading->type; - colorSpace = shading->colorSpace->copy(); - for (i = 0; i < gfxColorMaxComps; ++i) { - background.c[i] = shading->background.c[i]; - } - hasBackground = shading->hasBackground; - xMin = shading->xMin; - yMin = shading->yMin; - xMax = shading->xMax; - yMax = shading->yMax; - hasBBox = shading->hasBBox; -} - -GfxShading::~GfxShading() { - if (colorSpace) { - delete colorSpace; - } -} - -GfxShading *GfxShading::parse(Object *obj) { - GfxShading *shading; - Dict *dict; - int typeA; - Object obj1; - - if (obj->isDict()) { - dict = obj->getDict(); - } else if (obj->isStream()) { - dict = obj->streamGetDict(); - } else { - return NULL; - } - - if (!dict->lookup("ShadingType", &obj1)->isInt()) { - error(-1, "Invalid ShadingType in shading dictionary"); - obj1.free(); - return NULL; - } - typeA = obj1.getInt(); - obj1.free(); - - switch (typeA) { - case 1: - shading = GfxFunctionShading::parse(dict); - break; - case 2: - shading = GfxAxialShading::parse(dict); - break; - case 3: - shading = GfxRadialShading::parse(dict); - break; - case 4: - if (obj->isStream()) { - shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream()); - } else { - error(-1, "Invalid Type 4 shading object"); - goto err1; - } - break; - case 5: - if (obj->isStream()) { - shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream()); - } else { - error(-1, "Invalid Type 5 shading object"); - goto err1; - } - break; - case 6: - if (obj->isStream()) { - shading = GfxPatchMeshShading::parse(6, dict, obj->getStream()); - } else { - error(-1, "Invalid Type 6 shading object"); - goto err1; - } - break; - case 7: - if (obj->isStream()) { - shading = GfxPatchMeshShading::parse(7, dict, obj->getStream()); - } else { - error(-1, "Invalid Type 7 shading object"); - goto err1; - } - break; - default: - error(-1, "Unimplemented shading type %d", typeA); - goto err1; - } - - return shading; - - err1: - return NULL; -} - -GBool GfxShading::init(Dict *dict) { - Object obj1, obj2; - int i; - - dict->lookup("ColorSpace", &obj1); - if (!(colorSpace = GfxColorSpace::parse(&obj1))) { - error(-1, "Bad color space in shading dictionary"); - obj1.free(); - return gFalse; - } - obj1.free(); - - for (i = 0; i < gfxColorMaxComps; ++i) { - background.c[i] = 0; - } - hasBackground = gFalse; - if (dict->lookup("Background", &obj1)->isArray()) { - if (obj1.arrayGetLength() == colorSpace->getNComps()) { - hasBackground = gTrue; - for (i = 0; i < colorSpace->getNComps(); ++i) { - background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum()); - obj2.free(); - } - } else { - error(-1, "Bad Background in shading dictionary"); - } - } - obj1.free(); - - xMin = yMin = xMax = yMax = 0; - hasBBox = gFalse; - if (dict->lookup("BBox", &obj1)->isArray()) { - if (obj1.arrayGetLength() == 4) { - hasBBox = gTrue; - xMin = obj1.arrayGet(0, &obj2)->getNum(); - obj2.free(); - yMin = obj1.arrayGet(1, &obj2)->getNum(); - obj2.free(); - xMax = obj1.arrayGet(2, &obj2)->getNum(); - obj2.free(); - yMax = obj1.arrayGet(3, &obj2)->getNum(); - obj2.free(); - } else { - error(-1, "Bad BBox in shading dictionary"); - } - } - obj1.free(); - - return gTrue; -} - -//------------------------------------------------------------------------ -// GfxFunctionShading -//------------------------------------------------------------------------ - -GfxFunctionShading::GfxFunctionShading(double x0A, double y0A, - double x1A, double y1A, - double *matrixA, - Function **funcsA, int nFuncsA): - GfxShading(1) -{ - int i; - - x0 = x0A; - y0 = y0A; - x1 = x1A; - y1 = y1A; - for (i = 0; i < 6; ++i) { - matrix[i] = matrixA[i]; - } - nFuncs = nFuncsA; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = funcsA[i]; - } -} - -GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading): - GfxShading(shading) -{ - int i; - - x0 = shading->x0; - y0 = shading->y0; - x1 = shading->x1; - y1 = shading->y1; - for (i = 0; i < 6; ++i) { - matrix[i] = shading->matrix[i]; - } - nFuncs = shading->nFuncs; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = shading->funcs[i]->copy(); - } -} - -GfxFunctionShading::~GfxFunctionShading() { - int i; - - for (i = 0; i < nFuncs; ++i) { - delete funcs[i]; - } -} - -GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) { - GfxFunctionShading *shading; - double x0A, y0A, x1A, y1A; - double matrixA[6]; - Function *funcsA[gfxColorMaxComps]; - int nFuncsA; - Object obj1, obj2; - int i; - - x0A = y0A = 0; - x1A = y1A = 1; - if (dict->lookup("Domain", &obj1)->isArray() && - obj1.arrayGetLength() == 4) { - x0A = obj1.arrayGet(0, &obj2)->getNum(); - obj2.free(); - y0A = obj1.arrayGet(1, &obj2)->getNum(); - obj2.free(); - x1A = obj1.arrayGet(2, &obj2)->getNum(); - obj2.free(); - y1A = obj1.arrayGet(3, &obj2)->getNum(); - obj2.free(); - } - obj1.free(); - - matrixA[0] = 1; matrixA[1] = 0; - matrixA[2] = 0; matrixA[3] = 1; - matrixA[4] = 0; matrixA[5] = 0; - if (dict->lookup("Matrix", &obj1)->isArray() && - obj1.arrayGetLength() == 6) { - matrixA[0] = obj1.arrayGet(0, &obj2)->getNum(); - obj2.free(); - matrixA[1] = obj1.arrayGet(1, &obj2)->getNum(); - obj2.free(); - matrixA[2] = obj1.arrayGet(2, &obj2)->getNum(); - obj2.free(); - matrixA[3] = obj1.arrayGet(3, &obj2)->getNum(); - obj2.free(); - matrixA[4] = obj1.arrayGet(4, &obj2)->getNum(); - obj2.free(); - matrixA[5] = obj1.arrayGet(5, &obj2)->getNum(); - obj2.free(); - } - obj1.free(); - - dict->lookup("Function", &obj1); - if (obj1.isArray()) { - nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps) { - error(-1, "Invalid Function array in shading dictionary"); - goto err1; - } - for (i = 0; i < nFuncsA; ++i) { - obj1.arrayGet(i, &obj2); - if (!(funcsA[i] = Function::parse(&obj2))) { - goto err2; - } - obj2.free(); - } - } else { - nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { - goto err1; - } - } - obj1.free(); - - shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA, - funcsA, nFuncsA); - if (!shading->init(dict)) { - delete shading; - return NULL; - } - return shading; - - err2: - obj2.free(); - err1: - obj1.free(); - return NULL; -} - -GfxShading *GfxFunctionShading::copy() { - return new GfxFunctionShading(this); -} - -void GfxFunctionShading::getColor(double x, double y, GfxColor *color) { - double in[2], out[gfxColorMaxComps]; - int i; - - // NB: there can be one function with n outputs or n functions with - // one output each (where n = number of color components) - for (i = 0; i < gfxColorMaxComps; ++i) { - out[i] = 0; - } - in[0] = x; - in[1] = y; - for (i = 0; i < nFuncs; ++i) { - funcs[i]->transform(in, &out[i]); - } - for (i = 0; i < gfxColorMaxComps; ++i) { - color->c[i] = dblToCol(out[i]); - } -} - -//------------------------------------------------------------------------ -// GfxAxialShading -//------------------------------------------------------------------------ - -GfxAxialShading::GfxAxialShading(double x0A, double y0A, - double x1A, double y1A, - double t0A, double t1A, - Function **funcsA, int nFuncsA, - GBool extend0A, GBool extend1A): - GfxShading(2) -{ - int i; - - x0 = x0A; - y0 = y0A; - x1 = x1A; - y1 = y1A; - t0 = t0A; - t1 = t1A; - nFuncs = nFuncsA; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = funcsA[i]; - } - extend0 = extend0A; - extend1 = extend1A; -} - -GfxAxialShading::GfxAxialShading(GfxAxialShading *shading): - GfxShading(shading) -{ - int i; - - x0 = shading->x0; - y0 = shading->y0; - x1 = shading->x1; - y1 = shading->y1; - t0 = shading->t0; - y1 = shading->t1; - nFuncs = shading->nFuncs; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = shading->funcs[i]->copy(); - } - extend0 = shading->extend0; - extend1 = shading->extend1; -} - -GfxAxialShading::~GfxAxialShading() { - int i; - - for (i = 0; i < nFuncs; ++i) { - delete funcs[i]; - } -} - -GfxAxialShading *GfxAxialShading::parse(Dict *dict) { - GfxAxialShading *shading; - double x0A, y0A, x1A, y1A; - double t0A, t1A; - Function *funcsA[gfxColorMaxComps]; - int nFuncsA; - GBool extend0A, extend1A; - Object obj1, obj2; - int i; - - x0A = y0A = x1A = y1A = 0; - if (dict->lookup("Coords", &obj1)->isArray() && - obj1.arrayGetLength() == 4) { - x0A = obj1.arrayGet(0, &obj2)->getNum(); - obj2.free(); - y0A = obj1.arrayGet(1, &obj2)->getNum(); - obj2.free(); - x1A = obj1.arrayGet(2, &obj2)->getNum(); - obj2.free(); - y1A = obj1.arrayGet(3, &obj2)->getNum(); - obj2.free(); - } else { - error(-1, "Missing or invalid Coords in shading dictionary"); - goto err1; - } - obj1.free(); - - t0A = 0; - t1A = 1; - if (dict->lookup("Domain", &obj1)->isArray() && - obj1.arrayGetLength() == 2) { - t0A = obj1.arrayGet(0, &obj2)->getNum(); - obj2.free(); - t1A = obj1.arrayGet(1, &obj2)->getNum(); - obj2.free(); - } - obj1.free(); - - dict->lookup("Function", &obj1); - if (obj1.isArray()) { - nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps) { - error(-1, "Invalid Function array in shading dictionary"); - goto err1; - } - for (i = 0; i < nFuncsA; ++i) { - obj1.arrayGet(i, &obj2); - if (!(funcsA[i] = Function::parse(&obj2))) { - obj1.free(); - obj2.free(); - goto err1; - } - obj2.free(); - } - } else { - nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { - obj1.free(); - goto err1; - } - } - obj1.free(); - - extend0A = extend1A = gFalse; - if (dict->lookup("Extend", &obj1)->isArray() && - obj1.arrayGetLength() == 2) { - extend0A = obj1.arrayGet(0, &obj2)->getBool(); - obj2.free(); - extend1A = obj1.arrayGet(1, &obj2)->getBool(); - obj2.free(); - } - obj1.free(); - - shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A, - funcsA, nFuncsA, extend0A, extend1A); - if (!shading->init(dict)) { - delete shading; - return NULL; - } - return shading; - - err1: - return NULL; -} - -GfxShading *GfxAxialShading::copy() { - return new GfxAxialShading(this); -} - -void GfxAxialShading::getColor(double t, GfxColor *color) { - double out[gfxColorMaxComps]; - int i; - - // NB: there can be one function with n outputs or n functions with - // one output each (where n = number of color components) - for (i = 0; i < gfxColorMaxComps; ++i) { - out[i] = 0; - } - for (i = 0; i < nFuncs; ++i) { - funcs[i]->transform(&t, &out[i]); - } - for (i = 0; i < gfxColorMaxComps; ++i) { - color->c[i] = dblToCol(out[i]); - } -} - -//------------------------------------------------------------------------ -// GfxRadialShading -//------------------------------------------------------------------------ - -GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A, - double x1A, double y1A, double r1A, - double t0A, double t1A, - Function **funcsA, int nFuncsA, - GBool extend0A, GBool extend1A): - GfxShading(3) -{ - int i; - - x0 = x0A; - y0 = y0A; - r0 = r0A; - x1 = x1A; - y1 = y1A; - r1 = r1A; - t0 = t0A; - t1 = t1A; - nFuncs = nFuncsA; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = funcsA[i]; - } - extend0 = extend0A; - extend1 = extend1A; -} - -GfxRadialShading::GfxRadialShading(GfxRadialShading *shading): - GfxShading(shading) -{ - int i; - - x0 = shading->x0; - y0 = shading->y0; - r0 = shading->r0; - x1 = shading->x1; - y1 = shading->y1; - r1 = shading->r1; - t0 = shading->t0; - y1 = shading->t1; - nFuncs = shading->nFuncs; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = shading->funcs[i]->copy(); - } - extend0 = shading->extend0; - extend1 = shading->extend1; -} - -GfxRadialShading::~GfxRadialShading() { - int i; - - for (i = 0; i < nFuncs; ++i) { - delete funcs[i]; - } -} - -GfxRadialShading *GfxRadialShading::parse(Dict *dict) { - GfxRadialShading *shading; - double x0A, y0A, r0A, x1A, y1A, r1A; - double t0A, t1A; - Function *funcsA[gfxColorMaxComps]; - int nFuncsA; - GBool extend0A, extend1A; - Object obj1, obj2; - int i; - - x0A = y0A = r0A = x1A = y1A = r1A = 0; - if (dict->lookup("Coords", &obj1)->isArray() && - obj1.arrayGetLength() == 6) { - x0A = obj1.arrayGet(0, &obj2)->getNum(); - obj2.free(); - y0A = obj1.arrayGet(1, &obj2)->getNum(); - obj2.free(); - r0A = obj1.arrayGet(2, &obj2)->getNum(); - obj2.free(); - x1A = obj1.arrayGet(3, &obj2)->getNum(); - obj2.free(); - y1A = obj1.arrayGet(4, &obj2)->getNum(); - obj2.free(); - r1A = obj1.arrayGet(5, &obj2)->getNum(); - obj2.free(); - } else { - error(-1, "Missing or invalid Coords in shading dictionary"); - goto err1; - } - obj1.free(); - - t0A = 0; - t1A = 1; - if (dict->lookup("Domain", &obj1)->isArray() && - obj1.arrayGetLength() == 2) { - t0A = obj1.arrayGet(0, &obj2)->getNum(); - obj2.free(); - t1A = obj1.arrayGet(1, &obj2)->getNum(); - obj2.free(); - } - obj1.free(); - - dict->lookup("Function", &obj1); - if (obj1.isArray()) { - nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps) { - error(-1, "Invalid Function array in shading dictionary"); - goto err1; - } - for (i = 0; i < nFuncsA; ++i) { - obj1.arrayGet(i, &obj2); - if (!(funcsA[i] = Function::parse(&obj2))) { - obj1.free(); - obj2.free(); - goto err1; - } - obj2.free(); - } - } else { - nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { - obj1.free(); - goto err1; - } - } - obj1.free(); - - extend0A = extend1A = gFalse; - if (dict->lookup("Extend", &obj1)->isArray() && - obj1.arrayGetLength() == 2) { - extend0A = obj1.arrayGet(0, &obj2)->getBool(); - obj2.free(); - extend1A = obj1.arrayGet(1, &obj2)->getBool(); - obj2.free(); - } - obj1.free(); - - shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A, - funcsA, nFuncsA, extend0A, extend1A); - if (!shading->init(dict)) { - delete shading; - return NULL; - } - return shading; - - err1: - return NULL; -} - -GfxShading *GfxRadialShading::copy() { - return new GfxRadialShading(this); -} - -void GfxRadialShading::getColor(double t, GfxColor *color) { - double out[gfxColorMaxComps]; - int i; - - // NB: there can be one function with n outputs or n functions with - // one output each (where n = number of color components) - for (i = 0; i < gfxColorMaxComps; ++i) { - out[i] = 0; - } - for (i = 0; i < nFuncs; ++i) { - funcs[i]->transform(&t, &out[i]); - } - for (i = 0; i < gfxColorMaxComps; ++i) { - color->c[i] = dblToCol(out[i]); - } -} - -//------------------------------------------------------------------------ -// GfxShadingBitBuf -//------------------------------------------------------------------------ - -class GfxShadingBitBuf { -public: - - GfxShadingBitBuf(Stream *strA); - ~GfxShadingBitBuf(); - GBool getBits(int n, Guint *val); - void flushBits(); - -private: - - Stream *str; - int bitBuf; - int nBits; -}; - -GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) { - str = strA; - str->reset(); - bitBuf = 0; - nBits = 0; -} - -GfxShadingBitBuf::~GfxShadingBitBuf() { - str->close(); -} - -GBool GfxShadingBitBuf::getBits(int n, Guint *val) { - int x; - - if (nBits >= n) { - x = (bitBuf >> (nBits - n)) & ((1 << n) - 1); - nBits -= n; - } else { - x = 0; - if (nBits > 0) { - x = bitBuf & ((1 << nBits) - 1); - n -= nBits; - nBits = 0; - } - while (n > 0) { - if ((bitBuf = str->getChar()) == EOF) { - nBits = 0; - return gFalse; - } - if (n >= 8) { - x = (x << 8) | bitBuf; - n -= 8; - } else { - x = (x << n) | (bitBuf >> (8 - n)); - nBits = 8 - n; - n = 0; - } - } - } - *val = x; - return gTrue; -} - -void GfxShadingBitBuf::flushBits() { - bitBuf = 0; - nBits = 0; -} - -//------------------------------------------------------------------------ -// GfxGouraudTriangleShading -//------------------------------------------------------------------------ - -GfxGouraudTriangleShading::GfxGouraudTriangleShading( - int typeA, - GfxGouraudVertex *verticesA, int nVerticesA, - int (*trianglesA)[3], int nTrianglesA, - Function **funcsA, int nFuncsA): - GfxShading(typeA) -{ - int i; - - vertices = verticesA; - nVertices = nVerticesA; - triangles = trianglesA; - nTriangles = nTrianglesA; - nFuncs = nFuncsA; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = funcsA[i]; - } -} - -GfxGouraudTriangleShading::GfxGouraudTriangleShading( - GfxGouraudTriangleShading *shading): - GfxShading(shading) -{ - int i; - - nVertices = shading->nVertices; - vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex)); - memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex)); - nTriangles = shading->nTriangles; - triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int)); - memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int)); - nFuncs = shading->nFuncs; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = shading->funcs[i]->copy(); - } -} - -GfxGouraudTriangleShading::~GfxGouraudTriangleShading() { - int i; - - gfree(vertices); - gfree(triangles); - for (i = 0; i < nFuncs; ++i) { - delete funcs[i]; - } -} - -GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA, - Dict *dict, - Stream *str) { - GfxGouraudTriangleShading *shading; - Function *funcsA[gfxColorMaxComps]; - int nFuncsA; - int coordBits, compBits, flagBits, vertsPerRow, nRows; - double xMin, xMax, yMin, yMax; - double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; - double xMul, yMul; - double cMul[gfxColorMaxComps]; - GfxGouraudVertex *verticesA; - int (*trianglesA)[3]; - int nComps, nVerticesA, nTrianglesA, vertSize, triSize; - Guint x, y, flag; - Guint c[gfxColorMaxComps]; - GfxShadingBitBuf *bitBuf; - Object obj1, obj2; - int i, j, k, state; - - if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) { - coordBits = obj1.getInt(); - } else { - error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary"); - goto err2; - } - obj1.free(); - if (dict->lookup("BitsPerComponent", &obj1)->isInt()) { - compBits = obj1.getInt(); - } else { - error(-1, "Missing or invalid BitsPerComponent in shading dictionary"); - goto err2; - } - obj1.free(); - flagBits = vertsPerRow = 0; // make gcc happy - if (typeA == 4) { - if (dict->lookup("BitsPerFlag", &obj1)->isInt()) { - flagBits = obj1.getInt(); - } else { - error(-1, "Missing or invalid BitsPerFlag in shading dictionary"); - goto err2; - } - obj1.free(); - } else { - if (dict->lookup("VerticesPerRow", &obj1)->isInt()) { - vertsPerRow = obj1.getInt(); - } else { - error(-1, "Missing or invalid VerticesPerRow in shading dictionary"); - goto err2; - } - obj1.free(); - } - if (dict->lookup("Decode", &obj1)->isArray() && - obj1.arrayGetLength() >= 6) { - xMin = obj1.arrayGet(0, &obj2)->getNum(); - obj2.free(); - xMax = obj1.arrayGet(1, &obj2)->getNum(); - obj2.free(); - xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); - yMin = obj1.arrayGet(2, &obj2)->getNum(); - obj2.free(); - yMax = obj1.arrayGet(3, &obj2)->getNum(); - obj2.free(); - yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); - for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { - cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(); - obj2.free(); - cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(); - obj2.free(); - cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1); - } - nComps = i; - } else { - error(-1, "Missing or invalid Decode array in shading dictionary"); - goto err2; - } - obj1.free(); - - if (!dict->lookup("Function", &obj1)->isNull()) { - if (obj1.isArray()) { - nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps) { - error(-1, "Invalid Function array in shading dictionary"); - goto err1; - } - for (i = 0; i < nFuncsA; ++i) { - obj1.arrayGet(i, &obj2); - if (!(funcsA[i] = Function::parse(&obj2))) { - obj1.free(); - obj2.free(); - goto err1; - } - obj2.free(); - } - } else { - nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { - obj1.free(); - goto err1; - } - } - } else { - nFuncsA = 0; - } - obj1.free(); - - nVerticesA = nTrianglesA = 0; - verticesA = NULL; - trianglesA = NULL; - vertSize = triSize = 0; - state = 0; - flag = 0; // make gcc happy - bitBuf = new GfxShadingBitBuf(str); - while (1) { - if (typeA == 4) { - if (!bitBuf->getBits(flagBits, &flag)) { - break; - } - } - if (!bitBuf->getBits(coordBits, &x) || - !bitBuf->getBits(coordBits, &y)) { - break; - } - for (i = 0; i < nComps; ++i) { - if (!bitBuf->getBits(compBits, &c[i])) { - break; - } - } - if (i < nComps) { - break; - } - if (nVerticesA == vertSize) { - vertSize = (vertSize == 0) ? 16 : 2 * vertSize; - verticesA = (GfxGouraudVertex *) - greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex)); - } - verticesA[nVerticesA].x = xMin + xMul * (double)x; - verticesA[nVerticesA].y = yMin + yMul * (double)y; - for (i = 0; i < nComps; ++i) { - verticesA[nVerticesA].color.c[i] = - dblToCol(cMin[i] + cMul[i] * (double)c[i]); - } - ++nVerticesA; - bitBuf->flushBits(); - if (typeA == 4) { - if (state == 0 || state == 1) { - ++state; - } else if (state == 2 || flag > 0) { - if (nTrianglesA == triSize) { - triSize = (triSize == 0) ? 16 : 2 * triSize; - trianglesA = (int (*)[3]) - greallocn(trianglesA, triSize * 3, sizeof(int)); - } - if (state == 2) { - trianglesA[nTrianglesA][0] = nVerticesA - 3; - trianglesA[nTrianglesA][1] = nVerticesA - 2; - trianglesA[nTrianglesA][2] = nVerticesA - 1; - ++state; - } else if (flag == 1) { - trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1]; - trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; - trianglesA[nTrianglesA][2] = nVerticesA - 1; - } else { // flag == 2 - trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0]; - trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; - trianglesA[nTrianglesA][2] = nVerticesA - 1; - } - ++nTrianglesA; - } else { // state == 3 && flag == 0 - state = 1; - } - } - } - delete bitBuf; - if (typeA == 5) { - nRows = nVerticesA / vertsPerRow; - nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1); - trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int)); - k = 0; - for (i = 0; i < nRows - 1; ++i) { - for (j = 0; j < vertsPerRow - 1; ++j) { - trianglesA[k][0] = i * vertsPerRow + j; - trianglesA[k][1] = i * vertsPerRow + j+1; - trianglesA[k][2] = (i+1) * vertsPerRow + j; - ++k; - trianglesA[k][0] = i * vertsPerRow + j+1; - trianglesA[k][1] = (i+1) * vertsPerRow + j; - trianglesA[k][2] = (i+1) * vertsPerRow + j+1; - ++k; - } - } - } - - shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA, - trianglesA, nTrianglesA, - funcsA, nFuncsA); - if (!shading->init(dict)) { - delete shading; - return NULL; - } - return shading; - - err2: - obj1.free(); - err1: - return NULL; -} - -GfxShading *GfxGouraudTriangleShading::copy() { - return new GfxGouraudTriangleShading(this); -} - -void GfxGouraudTriangleShading::getTriangle( - int i, - double *x0, double *y0, GfxColor *color0, - double *x1, double *y1, GfxColor *color1, - double *x2, double *y2, GfxColor *color2) { - double in; - double out[gfxColorMaxComps]; - int v, j; - - v = triangles[i][0]; - *x0 = vertices[v].x; - *y0 = vertices[v].y; - if (nFuncs > 0) { - in = colToDbl(vertices[v].color.c[0]); - for (j = 0; j < nFuncs; ++j) { - funcs[j]->transform(&in, &out[j]); - } - for (j = 0; j < gfxColorMaxComps; ++j) { - color0->c[j] = dblToCol(out[j]); - } - } else { - *color0 = vertices[v].color; - } - v = triangles[i][1]; - *x1 = vertices[v].x; - *y1 = vertices[v].y; - if (nFuncs > 0) { - in = colToDbl(vertices[v].color.c[0]); - for (j = 0; j < nFuncs; ++j) { - funcs[j]->transform(&in, &out[j]); - } - for (j = 0; j < gfxColorMaxComps; ++j) { - color1->c[j] = dblToCol(out[j]); - } - } else { - *color1 = vertices[v].color; - } - v = triangles[i][2]; - *x2 = vertices[v].x; - *y2 = vertices[v].y; - if (nFuncs > 0) { - in = colToDbl(vertices[v].color.c[0]); - for (j = 0; j < nFuncs; ++j) { - funcs[j]->transform(&in, &out[j]); - } - for (j = 0; j < gfxColorMaxComps; ++j) { - color2->c[j] = dblToCol(out[j]); - } - } else { - *color2 = vertices[v].color; - } -} - -//------------------------------------------------------------------------ -// GfxPatchMeshShading -//------------------------------------------------------------------------ - -GfxPatchMeshShading::GfxPatchMeshShading(int typeA, - GfxPatch *patchesA, int nPatchesA, - Function **funcsA, int nFuncsA): - GfxShading(typeA) -{ - int i; - - patches = patchesA; - nPatches = nPatchesA; - nFuncs = nFuncsA; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = funcsA[i]; - } -} - -GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading): - GfxShading(shading) -{ - int i; - - nPatches = shading->nPatches; - patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch)); - memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch)); - nFuncs = shading->nFuncs; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = shading->funcs[i]->copy(); - } -} - -GfxPatchMeshShading::~GfxPatchMeshShading() { - int i; - - gfree(patches); - for (i = 0; i < nFuncs; ++i) { - delete funcs[i]; - } -} - -GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, - Stream *str) { - GfxPatchMeshShading *shading; - Function *funcsA[gfxColorMaxComps]; - int nFuncsA; - int coordBits, compBits, flagBits; - double xMin, xMax, yMin, yMax; - double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; - double xMul, yMul; - double cMul[gfxColorMaxComps]; - GfxPatch *patchesA, *p; - int nComps, nPatchesA, patchesSize, nPts, nColors; - Guint flag; - double x[16], y[16]; - Guint xi, yi; - GfxColorComp c[4][gfxColorMaxComps]; - Guint ci[4]; - GfxShadingBitBuf *bitBuf; - Object obj1, obj2; - int i, j; - - if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) { - coordBits = obj1.getInt(); - } else { - error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary"); - goto err2; - } - obj1.free(); - if (dict->lookup("BitsPerComponent", &obj1)->isInt()) { - compBits = obj1.getInt(); - } else { - error(-1, "Missing or invalid BitsPerComponent in shading dictionary"); - goto err2; - } - obj1.free(); - if (dict->lookup("BitsPerFlag", &obj1)->isInt()) { - flagBits = obj1.getInt(); - } else { - error(-1, "Missing or invalid BitsPerFlag in shading dictionary"); - goto err2; - } - obj1.free(); - if (dict->lookup("Decode", &obj1)->isArray() && - obj1.arrayGetLength() >= 6) { - xMin = obj1.arrayGet(0, &obj2)->getNum(); - obj2.free(); - xMax = obj1.arrayGet(1, &obj2)->getNum(); - obj2.free(); - xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); - yMin = obj1.arrayGet(2, &obj2)->getNum(); - obj2.free(); - yMax = obj1.arrayGet(3, &obj2)->getNum(); - obj2.free(); - yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); - for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { - cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(); - obj2.free(); - cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(); - obj2.free(); - cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1); - } - nComps = i; - } else { - error(-1, "Missing or invalid Decode array in shading dictionary"); - goto err2; - } - obj1.free(); - - if (!dict->lookup("Function", &obj1)->isNull()) { - if (obj1.isArray()) { - nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps) { - error(-1, "Invalid Function array in shading dictionary"); - goto err1; - } - for (i = 0; i < nFuncsA; ++i) { - obj1.arrayGet(i, &obj2); - if (!(funcsA[i] = Function::parse(&obj2))) { - obj1.free(); - obj2.free(); - goto err1; - } - obj2.free(); - } - } else { - nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { - obj1.free(); - goto err1; - } - } - } else { - nFuncsA = 0; - } - obj1.free(); - - nPatchesA = 0; - patchesA = NULL; - patchesSize = 0; - bitBuf = new GfxShadingBitBuf(str); - while (1) { - if (!bitBuf->getBits(flagBits, &flag)) { - break; - } - if (typeA == 6) { - switch (flag) { - case 0: nPts = 12; nColors = 4; break; - case 1: - case 2: - case 3: - default: nPts = 8; nColors = 2; break; - } - } else { - switch (flag) { - case 0: nPts = 16; nColors = 4; break; - case 1: - case 2: - case 3: - default: nPts = 12; nColors = 2; break; - } - } - for (i = 0; i < nPts; ++i) { - if (!bitBuf->getBits(coordBits, &xi) || - !bitBuf->getBits(coordBits, &yi)) { - break; - } - x[i] = xMin + xMul * (double)xi; - y[i] = yMin + yMul * (double)yi; - } - if (i < nPts) { - break; - } - for (i = 0; i < nColors; ++i) { - for (j = 0; j < nComps; ++j) { - if (!bitBuf->getBits(compBits, &ci[j])) { - break; - } - c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]); - } - if (j < nComps) { - break; - } - } - if (i < nColors) { - break; - } - if (nPatchesA == patchesSize) { - patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize; - patchesA = (GfxPatch *)greallocn(patchesA, - patchesSize, sizeof(GfxPatch)); - } - p = &patchesA[nPatchesA]; - if (typeA == 6) { - switch (flag) { - case 0: - p->x[0][0] = x[0]; - p->y[0][0] = y[0]; - p->x[0][1] = x[1]; - p->y[0][1] = y[1]; - p->x[0][2] = x[2]; - p->y[0][2] = y[2]; - p->x[0][3] = x[3]; - p->y[0][3] = y[3]; - p->x[1][3] = x[4]; - p->y[1][3] = y[4]; - p->x[2][3] = x[5]; - p->y[2][3] = y[5]; - p->x[3][3] = x[6]; - p->y[3][3] = y[6]; - p->x[3][2] = x[7]; - p->y[3][2] = y[7]; - p->x[3][1] = x[8]; - p->y[3][1] = y[8]; - p->x[3][0] = x[9]; - p->y[3][0] = y[9]; - p->x[2][0] = x[10]; - p->y[2][0] = y[10]; - p->x[1][0] = x[11]; - p->y[1][0] = y[11]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = c[0][j]; - p->color[0][1].c[j] = c[1][j]; - p->color[1][1].c[j] = c[2][j]; - p->color[1][0].c[j] = c[3][j]; - } - break; - case 1: - p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; - p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; - p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; - p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; - p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; - p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; - p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; - p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - case 2: - p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; - p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; - p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; - p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; - p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; - p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; - p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; - p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - case 3: - p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; - p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; - p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; - p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; - p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; - p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; - p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; - p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - for (j = 0; j < nComps; ++j) { - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - } - } else { - switch (flag) { - case 0: - p->x[0][0] = x[0]; - p->y[0][0] = y[0]; - p->x[0][1] = x[1]; - p->y[0][1] = y[1]; - p->x[0][2] = x[2]; - p->y[0][2] = y[2]; - p->x[0][3] = x[3]; - p->y[0][3] = y[3]; - p->x[1][3] = x[4]; - p->y[1][3] = y[4]; - p->x[2][3] = x[5]; - p->y[2][3] = y[5]; - p->x[3][3] = x[6]; - p->y[3][3] = y[6]; - p->x[3][2] = x[7]; - p->y[3][2] = y[7]; - p->x[3][1] = x[8]; - p->y[3][1] = y[8]; - p->x[3][0] = x[9]; - p->y[3][0] = y[9]; - p->x[2][0] = x[10]; - p->y[2][0] = y[10]; - p->x[1][0] = x[11]; - p->y[1][0] = y[11]; - p->x[1][1] = x[12]; - p->y[1][1] = y[12]; - p->x[1][2] = x[13]; - p->y[1][2] = y[13]; - p->x[2][2] = x[14]; - p->y[2][2] = y[14]; - p->x[2][1] = x[15]; - p->y[2][1] = y[15]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = c[0][j]; - p->color[0][1].c[j] = c[1][j]; - p->color[1][1].c[j] = c[2][j]; - p->color[1][0].c[j] = c[3][j]; - } - break; - case 1: - p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; - p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; - p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; - p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; - p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; - p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; - p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; - p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - p->x[1][1] = x[8]; - p->y[1][1] = y[8]; - p->x[1][2] = x[9]; - p->y[1][2] = y[9]; - p->x[2][2] = x[10]; - p->y[2][2] = y[10]; - p->x[2][1] = x[11]; - p->y[2][1] = y[11]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - case 2: - p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; - p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; - p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; - p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; - p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; - p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; - p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; - p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - p->x[1][1] = x[8]; - p->y[1][1] = y[8]; - p->x[1][2] = x[9]; - p->y[1][2] = y[9]; - p->x[2][2] = x[10]; - p->y[2][2] = y[10]; - p->x[2][1] = x[11]; - p->y[2][1] = y[11]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - case 3: - p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; - p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; - p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; - p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; - p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; - p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; - p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; - p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - p->x[1][1] = x[8]; - p->y[1][1] = y[8]; - p->x[1][2] = x[9]; - p->y[1][2] = y[9]; - p->x[2][2] = x[10]; - p->y[2][2] = y[10]; - p->x[2][1] = x[11]; - p->y[2][1] = y[11]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - } - } - ++nPatchesA; - bitBuf->flushBits(); - } - delete bitBuf; - - if (typeA == 6) { - for (i = 0; i < nPatchesA; ++i) { - p = &patchesA[i]; - p->x[1][1] = (-4 * p->x[0][0] - +6 * (p->x[0][1] + p->x[1][0]) - -2 * (p->x[0][3] + p->x[3][0]) - +3 * (p->x[3][1] + p->x[1][3]) - - p->x[3][3]) / 9; - p->y[1][1] = (-4 * p->y[0][0] - +6 * (p->y[0][1] + p->y[1][0]) - -2 * (p->y[0][3] + p->y[3][0]) - +3 * (p->y[3][1] + p->y[1][3]) - - p->y[3][3]) / 9; - p->x[1][2] = (-4 * p->x[0][3] - +6 * (p->x[0][2] + p->x[1][3]) - -2 * (p->x[0][0] + p->x[3][3]) - +3 * (p->x[3][2] + p->x[1][0]) - - p->x[3][0]) / 9; - p->y[1][2] = (-4 * p->y[0][3] - +6 * (p->y[0][2] + p->y[1][3]) - -2 * (p->y[0][0] + p->y[3][3]) - +3 * (p->y[3][2] + p->y[1][0]) - - p->y[3][0]) / 9; - p->x[2][1] = (-4 * p->x[3][0] - +6 * (p->x[3][1] + p->x[2][0]) - -2 * (p->x[3][3] + p->x[0][0]) - +3 * (p->x[0][1] + p->x[2][3]) - - p->x[0][3]) / 9; - p->y[2][1] = (-4 * p->y[3][0] - +6 * (p->y[3][1] + p->y[2][0]) - -2 * (p->y[3][3] + p->y[0][0]) - +3 * (p->y[0][1] + p->y[2][3]) - - p->y[0][3]) / 9; - p->x[2][2] = (-4 * p->x[3][3] - +6 * (p->x[3][2] + p->x[2][3]) - -2 * (p->x[3][0] + p->x[0][3]) - +3 * (p->x[0][2] + p->x[2][0]) - - p->x[0][0]) / 9; - p->y[2][2] = (-4 * p->y[3][3] - +6 * (p->y[3][2] + p->y[2][3]) - -2 * (p->y[3][0] + p->y[0][3]) - +3 * (p->y[0][2] + p->y[2][0]) - - p->y[0][0]) / 9; - } - } - - shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA, - funcsA, nFuncsA); - if (!shading->init(dict)) { - delete shading; - return NULL; - } - return shading; - - err2: - obj1.free(); - err1: - return NULL; -} - -GfxShading *GfxPatchMeshShading::copy() { - return new GfxPatchMeshShading(this); -} - -//------------------------------------------------------------------------ -// GfxImageColorMap -//------------------------------------------------------------------------ - -GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, - GfxColorSpace *colorSpaceA) { - GfxIndexedColorSpace *indexedCS; - GfxSeparationColorSpace *sepCS; - int maxPixel, indexHigh; - Guchar *lookup2; - Function *sepFunc; - Object obj; - double x[gfxColorMaxComps]; - double y[gfxColorMaxComps]; - int i, j, k; - - ok = gTrue; - - // bits per component and color space - bits = bitsA; - maxPixel = (1 << bits) - 1; - colorSpace = colorSpaceA; - - // get decode map - if (decode->isNull()) { - nComps = colorSpace->getNComps(); - colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel); - } else if (decode->isArray()) { - nComps = decode->arrayGetLength() / 2; - if (nComps != colorSpace->getNComps()) { - goto err1; - } - for (i = 0; i < nComps; ++i) { - decode->arrayGet(2*i, &obj); - if (!obj.isNum()) { - goto err2; - } - decodeLow[i] = obj.getNum(); - obj.free(); - decode->arrayGet(2*i+1, &obj); - if (!obj.isNum()) { - goto err2; - } - decodeRange[i] = obj.getNum() - decodeLow[i]; - obj.free(); - } - } else { - goto err1; - } - - // Construct a lookup table -- this stores pre-computed decoded - // values for each component, i.e., the result of applying the - // decode mapping to each possible image pixel component value. - // - // Optimization: for Indexed and Separation color spaces (which have - // only one component), we store color values in the lookup table - // rather than component values. - for (k = 0; k < gfxColorMaxComps; ++k) { - lookup[k] = NULL; - } - colorSpace2 = NULL; - nComps2 = 0; - if (colorSpace->getMode() == csIndexed) { - // Note that indexHigh may not be the same as maxPixel -- - // Distiller will remove unused palette entries, resulting in - // indexHigh < maxPixel. - indexedCS = (GfxIndexedColorSpace *)colorSpace; - colorSpace2 = indexedCS->getBase(); - indexHigh = indexedCS->getIndexHigh(); - nComps2 = colorSpace2->getNComps(); - lookup2 = indexedCS->getLookup(); - colorSpace2->getDefaultRanges(x, y, indexHigh); - for (k = 0; k < nComps2; ++k) { - lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, - sizeof(GfxColorComp)); - for (i = 0; i <= maxPixel; ++i) { - j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5); - if (j < 0) { - j = 0; - } else if (j > indexHigh) { - j = indexHigh; - } - lookup[k][i] = - dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]); - } - } - } else if (colorSpace->getMode() == csSeparation) { - sepCS = (GfxSeparationColorSpace *)colorSpace; - colorSpace2 = sepCS->getAlt(); - nComps2 = colorSpace2->getNComps(); - sepFunc = sepCS->getFunc(); - for (k = 0; k < nComps2; ++k) { - lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, - sizeof(GfxColorComp)); - for (i = 0; i <= maxPixel; ++i) { - x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel; - sepFunc->transform(x, y); - lookup[k][i] = dblToCol(y[k]); - } - } - } else { - for (k = 0; k < nComps; ++k) { - lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, - sizeof(GfxColorComp)); - for (i = 0; i <= maxPixel; ++i) { - lookup[k][i] = dblToCol(decodeLow[k] + - (i * decodeRange[k]) / maxPixel); - } - } - } - - return; - - err2: - obj.free(); - err1: - ok = gFalse; -} - -GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) { - int n, i, k; - - colorSpace = colorMap->colorSpace->copy(); - bits = colorMap->bits; - nComps = colorMap->nComps; - nComps2 = colorMap->nComps2; - colorSpace2 = NULL; - for (k = 0; k < gfxColorMaxComps; ++k) { - lookup[k] = NULL; - } - n = 1 << bits; - if (colorSpace->getMode() == csIndexed) { - colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase(); - for (k = 0; k < nComps2; ++k) { - lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); - memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); - } - } else if (colorSpace->getMode() == csSeparation) { - colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt(); - for (k = 0; k < nComps2; ++k) { - lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); - memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); - } - } else { - for (k = 0; k < nComps; ++k) { - lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); - memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); - } - } - for (i = 0; i < nComps; ++i) { - decodeLow[i] = colorMap->decodeLow[i]; - decodeRange[i] = colorMap->decodeRange[i]; - } - ok = gTrue; -} - -GfxImageColorMap::~GfxImageColorMap() { - int i; - - delete colorSpace; - for (i = 0; i < gfxColorMaxComps; ++i) { - gfree(lookup[i]); - } -} - -void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) { - GfxColor color; - int i; - - if (colorSpace2) { - for (i = 0; i < nComps2; ++i) { - color.c[i] = lookup[i][x[0]]; - } - colorSpace2->getGray(&color, gray); - } else { - for (i = 0; i < nComps; ++i) { - color.c[i] = lookup[i][x[i]]; - } - colorSpace->getGray(&color, gray); - } -} - -void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) { - GfxColor color; - int i; - - if (colorSpace2) { - for (i = 0; i < nComps2; ++i) { - color.c[i] = lookup[i][x[0]]; - } - colorSpace2->getRGB(&color, rgb); - } else { - for (i = 0; i < nComps; ++i) { - color.c[i] = lookup[i][x[i]]; - } - colorSpace->getRGB(&color, rgb); - } -} - -void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) { - GfxColor color; - int i; - - if (colorSpace2) { - for (i = 0; i < nComps2; ++i) { - color.c[i] = lookup[i][x[0]]; - } - colorSpace2->getCMYK(&color, cmyk); - } else { - for (i = 0; i < nComps; ++i) { - color.c[i] = lookup[i][x[i]]; - } - colorSpace->getCMYK(&color, cmyk); - } -} - -void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) { - int maxPixel, i; - - maxPixel = (1 << bits) - 1; - for (i = 0; i < nComps; ++i) { - color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel); - } -} - -//------------------------------------------------------------------------ -// GfxSubpath and GfxPath -//------------------------------------------------------------------------ - -GfxSubpath::GfxSubpath(double x1, double y1) { - size = 16; - x = (double *)gmallocn(size, sizeof(double)); - y = (double *)gmallocn(size, sizeof(double)); - curve = (GBool *)gmallocn(size, sizeof(GBool)); - n = 1; - x[0] = x1; - y[0] = y1; - curve[0] = gFalse; - closed = gFalse; -} - -GfxSubpath::~GfxSubpath() { - gfree(x); - gfree(y); - gfree(curve); -} - -// Used for copy(). -GfxSubpath::GfxSubpath(GfxSubpath *subpath) { - size = subpath->size; - n = subpath->n; - x = (double *)gmallocn(size, sizeof(double)); - y = (double *)gmallocn(size, sizeof(double)); - curve = (GBool *)gmallocn(size, sizeof(GBool)); - memcpy(x, subpath->x, n * sizeof(double)); - memcpy(y, subpath->y, n * sizeof(double)); - memcpy(curve, subpath->curve, n * sizeof(GBool)); - closed = subpath->closed; -} - -void GfxSubpath::lineTo(double x1, double y1) { - if (n >= size) { - size += 16; - x = (double *)greallocn(x, size, sizeof(double)); - y = (double *)greallocn(y, size, sizeof(double)); - curve = (GBool *)greallocn(curve, size, sizeof(GBool)); - } - x[n] = x1; - y[n] = y1; - curve[n] = gFalse; - ++n; -} - -void GfxSubpath::curveTo(double x1, double y1, double x2, double y2, - double x3, double y3) { - if (n+3 > size) { - size += 16; - x = (double *)greallocn(x, size, sizeof(double)); - y = (double *)greallocn(y, size, sizeof(double)); - curve = (GBool *)greallocn(curve, size, sizeof(GBool)); - } - x[n] = x1; - y[n] = y1; - x[n+1] = x2; - y[n+1] = y2; - x[n+2] = x3; - y[n+2] = y3; - curve[n] = curve[n+1] = gTrue; - curve[n+2] = gFalse; - n += 3; -} - -void GfxSubpath::close() { - if (x[n-1] != x[0] || y[n-1] != y[0]) { - lineTo(x[0], y[0]); - } - closed = gTrue; -} - -void GfxSubpath::offset(double dx, double dy) { - int i; - - for (i = 0; i < n; ++i) { - x[i] += dx; - y[i] += dy; - } -} - -GfxPath::GfxPath() { - justMoved = gFalse; - size = 16; - n = 0; - firstX = firstY = 0; - subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *)); -} - -GfxPath::~GfxPath() { - int i; - - for (i = 0; i < n; ++i) - delete subpaths[i]; - gfree(subpaths); -} - -// Used for copy(). -GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1, - GfxSubpath **subpaths1, int n1, int size1) { - int i; - - justMoved = justMoved1; - firstX = firstX1; - firstY = firstY1; - size = size1; - n = n1; - subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *)); - for (i = 0; i < n; ++i) - subpaths[i] = subpaths1[i]->copy(); -} - -void GfxPath::moveTo(double x, double y) { - justMoved = gTrue; - firstX = x; - firstY = y; -} - -void GfxPath::lineTo(double x, double y) { - if (justMoved) { - if (n >= size) { - size += 16; - subpaths = (GfxSubpath **) - greallocn(subpaths, size, sizeof(GfxSubpath *)); - } - subpaths[n] = new GfxSubpath(firstX, firstY); - ++n; - justMoved = gFalse; - } - subpaths[n-1]->lineTo(x, y); -} - -void GfxPath::curveTo(double x1, double y1, double x2, double y2, - double x3, double y3) { - if (justMoved) { - if (n >= size) { - size += 16; - subpaths = (GfxSubpath **) - greallocn(subpaths, size, sizeof(GfxSubpath *)); - } - subpaths[n] = new GfxSubpath(firstX, firstY); - ++n; - justMoved = gFalse; - } - subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3); -} - -void GfxPath::close() { - // this is necessary to handle the pathological case of - // moveto/closepath/clip, which defines an empty clipping region - if (justMoved) { - if (n >= size) { - size += 16; - subpaths = (GfxSubpath **) - greallocn(subpaths, size, sizeof(GfxSubpath *)); - } - subpaths[n] = new GfxSubpath(firstX, firstY); - ++n; - justMoved = gFalse; - } - subpaths[n-1]->close(); -} - -void GfxPath::append(GfxPath *path) { - int i; - - if (n + path->n > size) { - size = n + path->n; - subpaths = (GfxSubpath **) - greallocn(subpaths, size, sizeof(GfxSubpath *)); - } - for (i = 0; i < path->n; ++i) { - subpaths[n++] = path->subpaths[i]->copy(); - } - justMoved = gFalse; -} - -void GfxPath::offset(double dx, double dy) { - int i; - - for (i = 0; i < n; ++i) { - subpaths[i]->offset(dx, dy); - } -} - -//------------------------------------------------------------------------ -// GfxState -//------------------------------------------------------------------------ - -GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, - int rotateA, GBool upsideDown) { - double kx, ky; - - rotate = rotateA; - px1 = pageBox->x1; - py1 = pageBox->y1; - px2 = pageBox->x2; - py2 = pageBox->y2; - kx = hDPI / 72.0; - ky = vDPI / 72.0; - if (rotate == 90) { - ctm[0] = 0; - ctm[1] = upsideDown ? ky : -ky; - ctm[2] = kx; - ctm[3] = 0; - ctm[4] = -kx * py1; - ctm[5] = ky * (upsideDown ? -px1 : px2); - pageWidth = kx * (py2 - py1); - pageHeight = ky * (px2 - px1); - } else if (rotate == 180) { - ctm[0] = -kx; - ctm[1] = 0; - ctm[2] = 0; - ctm[3] = upsideDown ? ky : -ky; - ctm[4] = kx * px2; - ctm[5] = ky * (upsideDown ? -py1 : py2); - pageWidth = kx * (px2 - px1); - pageHeight = ky * (py2 - py1); - } else if (rotate == 270) { - ctm[0] = 0; - ctm[1] = upsideDown ? -ky : ky; - ctm[2] = -kx; - ctm[3] = 0; - ctm[4] = kx * py2; - ctm[5] = ky * (upsideDown ? px2 : -px1); - pageWidth = kx * (py2 - py1); - pageHeight = ky * (px2 - px1); - } else { - ctm[0] = kx; - ctm[1] = 0; - ctm[2] = 0; - ctm[3] = upsideDown ? -ky : ky; - ctm[4] = -kx * px1; - ctm[5] = ky * (upsideDown ? py2 : -py1); - pageWidth = kx * (px2 - px1); - pageHeight = ky * (py2 - py1); - } - - fillColorSpace = new GfxDeviceGrayColorSpace(); - strokeColorSpace = new GfxDeviceGrayColorSpace(); - fillColor.c[0] = 0; - strokeColor.c[0] = 0; - fillPattern = NULL; - strokePattern = NULL; - blendMode = gfxBlendNormal; - fillOpacity = 1; - strokeOpacity = 1; - fillOverprint = gFalse; - strokeOverprint = gFalse; - - lineWidth = 1; - lineDash = NULL; - lineDashLength = 0; - lineDashStart = 0; - flatness = 1; - lineJoin = 0; - lineCap = 0; - miterLimit = 10; - - font = NULL; - fontSize = 0; - textMat[0] = 1; textMat[1] = 0; - textMat[2] = 0; textMat[3] = 1; - textMat[4] = 0; textMat[5] = 0; - charSpace = 0; - wordSpace = 0; - horizScaling = 1; - leading = 0; - rise = 0; - render = 0; - - path = new GfxPath(); - curX = curY = 0; - lineX = lineY = 0; - - clipXMin = 0; - clipYMin = 0; - clipXMax = pageWidth; - clipYMax = pageHeight; - - saved = NULL; -} - -GfxState::~GfxState() { - if (fillColorSpace) { - delete fillColorSpace; - } - if (strokeColorSpace) { - delete strokeColorSpace; - } - if (fillPattern) { - delete fillPattern; - } - if (strokePattern) { - delete strokePattern; - } - gfree(lineDash); - if (path) { - // this gets set to NULL by restore() - delete path; - } - if (saved) { - delete saved; - } -} - -// Used for copy(); -GfxState::GfxState(GfxState *state) { - memcpy(this, state, sizeof(GfxState)); - if (fillColorSpace) { - fillColorSpace = state->fillColorSpace->copy(); - } - if (strokeColorSpace) { - strokeColorSpace = state->strokeColorSpace->copy(); - } - if (fillPattern) { - fillPattern = state->fillPattern->copy(); - } - if (strokePattern) { - strokePattern = state->strokePattern->copy(); - } - if (lineDashLength > 0) { - lineDash = (double *)gmallocn(lineDashLength, sizeof(double)); - memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double)); - } - saved = NULL; -} - -void GfxState::setPath(GfxPath *pathA) { - delete path; - path = pathA; -} - -void GfxState::getUserClipBBox(double *xMin, double *yMin, - double *xMax, double *yMax) { - double ictm[6]; - double xMin1, yMin1, xMax1, yMax1, det, tx, ty; - - // invert the CTM - det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); - ictm[0] = ctm[3] * det; - ictm[1] = -ctm[1] * det; - ictm[2] = -ctm[2] * det; - ictm[3] = ctm[0] * det; - ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; - ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; - - // transform all four corners of the clip bbox; find the min and max - // x and y values - xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4]; - yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5]; - tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4]; - ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5]; - if (tx < xMin1) { - xMin1 = tx; - } else if (tx > xMax1) { - xMax1 = tx; - } - if (ty < yMin1) { - yMin1 = ty; - } else if (ty > yMax1) { - yMax1 = ty; - } - tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4]; - ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5]; - if (tx < xMin1) { - xMin1 = tx; - } else if (tx > xMax1) { - xMax1 = tx; - } - if (ty < yMin1) { - yMin1 = ty; - } else if (ty > yMax1) { - yMax1 = ty; - } - tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4]; - ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5]; - if (tx < xMin1) { - xMin1 = tx; - } else if (tx > xMax1) { - xMax1 = tx; - } - if (ty < yMin1) { - yMin1 = ty; - } else if (ty > yMax1) { - yMax1 = ty; - } - - *xMin = xMin1; - *yMin = yMin1; - *xMax = xMax1; - *yMax = yMax1; -} - -double GfxState::transformWidth(double w) { - double x, y; - - x = ctm[0] + ctm[2]; - y = ctm[1] + ctm[3]; - return w * sqrt(0.5 * (x * x + y * y)); -} - -double GfxState::getTransformedFontSize() { - double x1, y1, x2, y2; - - x1 = textMat[2] * fontSize; - y1 = textMat[3] * fontSize; - x2 = ctm[0] * x1 + ctm[2] * y1; - y2 = ctm[1] * x1 + ctm[3] * y1; - return sqrt(x2 * x2 + y2 * y2); -} - -void GfxState::getFontTransMat(double *m11, double *m12, - double *m21, double *m22) { - *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize; - *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize; - *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize; - *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize; -} - -void GfxState::setCTM(double a, double b, double c, - double d, double e, double f) { - int i; - - ctm[0] = a; - ctm[1] = b; - ctm[2] = c; - ctm[3] = d; - ctm[4] = e; - ctm[5] = f; - - // avoid FP exceptions on badly messed up PDF files - for (i = 0; i < 6; ++i) { - if (ctm[i] > 1e10) { - ctm[i] = 1e10; - } else if (ctm[i] < -1e10) { - ctm[i] = -1e10; - } - } -} - -void GfxState::concatCTM(double a, double b, double c, - double d, double e, double f) { - double a1 = ctm[0]; - double b1 = ctm[1]; - double c1 = ctm[2]; - double d1 = ctm[3]; - int i; - - ctm[0] = a * a1 + b * c1; - ctm[1] = a * b1 + b * d1; - ctm[2] = c * a1 + d * c1; - ctm[3] = c * b1 + d * d1; - ctm[4] = e * a1 + f * c1 + ctm[4]; - ctm[5] = e * b1 + f * d1 + ctm[5]; - - // avoid FP exceptions on badly messed up PDF files - for (i = 0; i < 6; ++i) { - if (ctm[i] > 1e10) { - ctm[i] = 1e10; - } else if (ctm[i] < -1e10) { - ctm[i] = -1e10; - } - } -} - -void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) { - if (fillColorSpace) { - delete fillColorSpace; - } - fillColorSpace = colorSpace; -} - -void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) { - if (strokeColorSpace) { - delete strokeColorSpace; - } - strokeColorSpace = colorSpace; -} - -void GfxState::setFillPattern(GfxPattern *pattern) { - if (fillPattern) { - delete fillPattern; - } - fillPattern = pattern; -} - -void GfxState::setStrokePattern(GfxPattern *pattern) { - if (strokePattern) { - delete strokePattern; - } - strokePattern = pattern; -} - -void GfxState::setLineDash(double *dash, int length, double start) { - if (lineDash) - gfree(lineDash); - lineDash = dash; - lineDashLength = length; - lineDashStart = start; -} - -void GfxState::clearPath() { - delete path; - path = new GfxPath(); -} - -void GfxState::clip() { - double xMin, yMin, xMax, yMax, x, y; - GfxSubpath *subpath; - int i, j; - - xMin = xMax = yMin = yMax = 0; // make gcc happy - for (i = 0; i < path->getNumSubpaths(); ++i) { - subpath = path->getSubpath(i); - for (j = 0; j < subpath->getNumPoints(); ++j) { - transform(subpath->getX(j), subpath->getY(j), &x, &y); - if (i == 0 && j == 0) { - xMin = xMax = x; - yMin = yMax = y; - } else { - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - } - } - } - if (xMin > clipXMin) { - clipXMin = xMin; - } - if (yMin > clipYMin) { - clipYMin = yMin; - } - if (xMax < clipXMax) { - clipXMax = xMax; - } - if (yMax < clipYMax) { - clipYMax = yMax; - } -} - -void GfxState::textShift(double tx, double ty) { - double dx, dy; - - textTransformDelta(tx, ty, &dx, &dy); - curX += dx; - curY += dy; -} - -void GfxState::shift(double dx, double dy) { - curX += dx; - curY += dy; -} - -GfxState *GfxState::save() { - GfxState *newState; - - newState = copy(); - newState->saved = this; - return newState; -} - -GfxState *GfxState::restore() { - GfxState *oldState; - - if (saved) { - oldState = saved; - - // these attributes aren't saved/restored by the q/Q operators - oldState->path = path; - oldState->curX = curX; - oldState->curY = curY; - oldState->lineX = lineX; - oldState->lineY = lineY; - - path = NULL; - saved = NULL; - delete this; - - } else { - oldState = this; - } - - return oldState; -} - -GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) { - Object obj2; - int i, j; - - if (obj->isName()) { - for (i = 0; i < nGfxBlendModeNames; ++i) { - if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) { - *mode = gfxBlendModeNames[i].mode; - return gTrue; - } - } - return gFalse; - } else if (obj->isArray()) { - for (i = 0; i < obj->arrayGetLength(); ++i) { - obj->arrayGet(i, &obj2); - if (!obj2.isName()) { - obj2.free(); - return gFalse; - } - for (j = 0; j < nGfxBlendModeNames; ++j) { - if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) { - obj2.free(); - *mode = gfxBlendModeNames[j].mode; - return gTrue; - } - } - obj2.free(); - } - *mode = gfxBlendNormal; - return gTrue; - } else { - return gFalse; - } -} diff --git a/xpdf/xpdf/GfxState.h b/xpdf/xpdf/GfxState.h deleted file mode 100644 index 202318d0d..000000000 --- a/xpdf/xpdf/GfxState.h +++ /dev/null @@ -1,1206 +0,0 @@ -//======================================================================== -// -// GfxState.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef GFXSTATE_H -#define GFXSTATE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "Object.h" -#include "Function.h" - -class Array; -class GfxFont; -class PDFRectangle; -class GfxShading; - -//------------------------------------------------------------------------ -// GfxBlendMode -//------------------------------------------------------------------------ - -enum GfxBlendMode { - gfxBlendNormal, - gfxBlendMultiply, - gfxBlendScreen, - gfxBlendOverlay, - gfxBlendDarken, - gfxBlendLighten, - gfxBlendColorDodge, - gfxBlendColorBurn, - gfxBlendHardLight, - gfxBlendSoftLight, - gfxBlendDifference, - gfxBlendExclusion, - gfxBlendHue, - gfxBlendSaturation, - gfxBlendColor, - gfxBlendLuminosity -}; - -//------------------------------------------------------------------------ -// GfxColorComp -//------------------------------------------------------------------------ - -// 16.16 fixed point color component -typedef int GfxColorComp; - -#define gfxColorComp1 0x10000 - -static inline GfxColorComp dblToCol(double x) { - return (GfxColorComp)(x * gfxColorComp1); -} - -static inline double colToDbl(GfxColorComp x) { - return (double)x / (double)gfxColorComp1; -} - -static inline GfxColorComp byteToCol(Guchar x) { - // (x / 255) << 16 = (0.0000000100000001... * x) << 16 - // = ((x << 8) + (x) + (x >> 8) + ...) << 16 - // = (x << 8) + (x) + (x >> 7) - // [for rounding] - return (GfxColorComp)((x << 8) + x + (x >> 7)); -} - -static inline Guchar colToByte(GfxColorComp x) { - // 255 * x + 0.5 = 256 * x - x + 0x8000 - return (Guchar)(((x << 8) - x + 0x8000) >> 16); -} - -//------------------------------------------------------------------------ -// GfxColor -//------------------------------------------------------------------------ - -#define gfxColorMaxComps funcMaxOutputs - -struct GfxColor { - GfxColorComp c[gfxColorMaxComps]; -}; - -//------------------------------------------------------------------------ -// GfxGray -//------------------------------------------------------------------------ - -typedef GfxColorComp GfxGray; - -//------------------------------------------------------------------------ -// GfxRGB -//------------------------------------------------------------------------ - -struct GfxRGB { - GfxColorComp r, g, b; -}; - -//------------------------------------------------------------------------ -// GfxCMYK -//------------------------------------------------------------------------ - -struct GfxCMYK { - GfxColorComp c, m, y, k; -}; - -//------------------------------------------------------------------------ -// GfxColorSpace -//------------------------------------------------------------------------ - -// NB: The nGfxColorSpaceModes constant and the gfxColorSpaceModeNames -// array defined in GfxState.cc must match this enum. -enum GfxColorSpaceMode { - csDeviceGray, - csCalGray, - csDeviceRGB, - csCalRGB, - csDeviceCMYK, - csLab, - csICCBased, - csIndexed, - csSeparation, - csDeviceN, - csPattern -}; - -class GfxColorSpace { -public: - - GfxColorSpace(); - virtual ~GfxColorSpace(); - virtual GfxColorSpace *copy() = 0; - virtual GfxColorSpaceMode getMode() = 0; - - // Construct a color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Object *csObj); - - // Convert to gray, RGB, or CMYK. - virtual void getGray(GfxColor *color, GfxGray *gray) = 0; - virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0; - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0; - - // Return the number of color components. - virtual int getNComps() = 0; - - // Return the default ranges for each component, assuming an image - // with a max pixel value of . - virtual void getDefaultRanges(double *decodeLow, double *decodeRange, - int maxImgPixel); - - // Return the number of color space modes - static int getNumColorSpaceModes(); - - // Return the name of the th color space mode. - static const char *getColorSpaceModeName(int idx); - -private: -}; - -//------------------------------------------------------------------------ -// GfxDeviceGrayColorSpace -//------------------------------------------------------------------------ - -class GfxDeviceGrayColorSpace: public GfxColorSpace { -public: - - GfxDeviceGrayColorSpace(); - virtual ~GfxDeviceGrayColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csDeviceGray; } - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return 1; } - -private: -}; - -//------------------------------------------------------------------------ -// GfxCalGrayColorSpace -//------------------------------------------------------------------------ - -class GfxCalGrayColorSpace: public GfxColorSpace { -public: - - GfxCalGrayColorSpace(); - virtual ~GfxCalGrayColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csCalGray; } - - // Construct a CalGray color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return 1; } - - // CalGray-specific access. - double getWhiteX() { return whiteX; } - double getWhiteY() { return whiteY; } - double getWhiteZ() { return whiteZ; } - double getBlackX() { return blackX; } - double getBlackY() { return blackY; } - double getBlackZ() { return blackZ; } - double getGamma() { return gamma; } - -private: - - double whiteX, whiteY, whiteZ; // white point - double blackX, blackY, blackZ; // black point - double gamma; // gamma value -}; - -//------------------------------------------------------------------------ -// GfxDeviceRGBColorSpace -//------------------------------------------------------------------------ - -class GfxDeviceRGBColorSpace: public GfxColorSpace { -public: - - GfxDeviceRGBColorSpace(); - virtual ~GfxDeviceRGBColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csDeviceRGB; } - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return 3; } - -private: -}; - -//------------------------------------------------------------------------ -// GfxCalRGBColorSpace -//------------------------------------------------------------------------ - -class GfxCalRGBColorSpace: public GfxColorSpace { -public: - - GfxCalRGBColorSpace(); - virtual ~GfxCalRGBColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csCalRGB; } - - // Construct a CalRGB color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return 3; } - - // CalRGB-specific access. - double getWhiteX() { return whiteX; } - double getWhiteY() { return whiteY; } - double getWhiteZ() { return whiteZ; } - double getBlackX() { return blackX; } - double getBlackY() { return blackY; } - double getBlackZ() { return blackZ; } - double getGammaR() { return gammaR; } - double getGammaG() { return gammaG; } - double getGammaB() { return gammaB; } - double *getMatrix() { return mat; } - -private: - - double whiteX, whiteY, whiteZ; // white point - double blackX, blackY, blackZ; // black point - double gammaR, gammaG, gammaB; // gamma values - double mat[9]; // ABC -> XYZ transform matrix -}; - -//------------------------------------------------------------------------ -// GfxDeviceCMYKColorSpace -//------------------------------------------------------------------------ - -class GfxDeviceCMYKColorSpace: public GfxColorSpace { -public: - - GfxDeviceCMYKColorSpace(); - virtual ~GfxDeviceCMYKColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csDeviceCMYK; } - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return 4; } - -private: -}; - -//------------------------------------------------------------------------ -// GfxLabColorSpace -//------------------------------------------------------------------------ - -class GfxLabColorSpace: public GfxColorSpace { -public: - - GfxLabColorSpace(); - virtual ~GfxLabColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csLab; } - - // Construct a Lab color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return 3; } - - virtual void getDefaultRanges(double *decodeLow, double *decodeRange, - int maxImgPixel); - - // Lab-specific access. - double getWhiteX() { return whiteX; } - double getWhiteY() { return whiteY; } - double getWhiteZ() { return whiteZ; } - double getBlackX() { return blackX; } - double getBlackY() { return blackY; } - double getBlackZ() { return blackZ; } - double getAMin() { return aMin; } - double getAMax() { return aMax; } - double getBMin() { return bMin; } - double getBMax() { return bMax; } - -private: - - double whiteX, whiteY, whiteZ; // white point - double blackX, blackY, blackZ; // black point - double aMin, aMax, bMin, bMax; // range for the a and b components - double kr, kg, kb; // gamut mapping mulitpliers -}; - -//------------------------------------------------------------------------ -// GfxICCBasedColorSpace -//------------------------------------------------------------------------ - -class GfxICCBasedColorSpace: public GfxColorSpace { -public: - - GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA, - Ref *iccProfileStreamA); - virtual ~GfxICCBasedColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csICCBased; } - - // Construct an ICCBased color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return nComps; } - - virtual void getDefaultRanges(double *decodeLow, double *decodeRange, - int maxImgPixel); - - // ICCBased-specific access. - GfxColorSpace *getAlt() { return alt; } - -private: - - int nComps; // number of color components (1, 3, or 4) - GfxColorSpace *alt; // alternate color space - double rangeMin[4]; // min values for each component - double rangeMax[4]; // max values for each component - Ref iccProfileStream; // the ICC profile -}; - -//------------------------------------------------------------------------ -// GfxIndexedColorSpace -//------------------------------------------------------------------------ - -class GfxIndexedColorSpace: public GfxColorSpace { -public: - - GfxIndexedColorSpace(GfxColorSpace *baseA, int indexHighA); - virtual ~GfxIndexedColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csIndexed; } - - // Construct a Lab color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return 1; } - - virtual void getDefaultRanges(double *decodeLow, double *decodeRange, - int maxImgPixel); - - // Indexed-specific access. - GfxColorSpace *getBase() { return base; } - int getIndexHigh() { return indexHigh; } - Guchar *getLookup() { return lookup; } - GfxColor *mapColorToBase(GfxColor *color, GfxColor *baseColor); - -private: - - GfxColorSpace *base; // base color space - int indexHigh; // max pixel value - Guchar *lookup; // lookup table -}; - -//------------------------------------------------------------------------ -// GfxSeparationColorSpace -//------------------------------------------------------------------------ - -class GfxSeparationColorSpace: public GfxColorSpace { -public: - - GfxSeparationColorSpace(GString *nameA, GfxColorSpace *altA, - Function *funcA); - virtual ~GfxSeparationColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csSeparation; } - - // Construct a Separation color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return 1; } - - // Separation-specific access. - GString *getName() { return name; } - GfxColorSpace *getAlt() { return alt; } - Function *getFunc() { return func; } - -private: - - GString *name; // colorant name - GfxColorSpace *alt; // alternate color space - Function *func; // tint transform (into alternate color space) -}; - -//------------------------------------------------------------------------ -// GfxDeviceNColorSpace -//------------------------------------------------------------------------ - -class GfxDeviceNColorSpace: public GfxColorSpace { -public: - - GfxDeviceNColorSpace(int nCompsA, GfxColorSpace *alt, Function *func); - virtual ~GfxDeviceNColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csDeviceN; } - - // Construct a DeviceN color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return nComps; } - - // DeviceN-specific access. - GString *getColorantName(int i) { return names[i]; } - GfxColorSpace *getAlt() { return alt; } - Function *getTintTransformFunc() { return func; } - -private: - - int nComps; // number of components - GString // colorant names - *names[gfxColorMaxComps]; - GfxColorSpace *alt; // alternate color space - Function *func; // tint transform (into alternate color space) -}; - -//------------------------------------------------------------------------ -// GfxPatternColorSpace -//------------------------------------------------------------------------ - -class GfxPatternColorSpace: public GfxColorSpace { -public: - - GfxPatternColorSpace(GfxColorSpace *underA); - virtual ~GfxPatternColorSpace(); - virtual GfxColorSpace *copy(); - virtual GfxColorSpaceMode getMode() { return csPattern; } - - // Construct a Pattern color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); - - virtual void getGray(GfxColor *color, GfxGray *gray); - virtual void getRGB(GfxColor *color, GfxRGB *rgb); - virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); - - virtual int getNComps() { return 0; } - - // Pattern-specific access. - GfxColorSpace *getUnder() { return under; } - -private: - - GfxColorSpace *under; // underlying color space (for uncolored - // patterns) -}; - -//------------------------------------------------------------------------ -// GfxPattern -//------------------------------------------------------------------------ - -class GfxPattern { -public: - - GfxPattern(int typeA); - virtual ~GfxPattern(); - - static GfxPattern *parse(Object *obj); - - virtual GfxPattern *copy() = 0; - - int getType() { return type; } - -private: - - int type; -}; - -//------------------------------------------------------------------------ -// GfxTilingPattern -//------------------------------------------------------------------------ - -class GfxTilingPattern: public GfxPattern { -public: - - static GfxTilingPattern *parse(Object *patObj); - virtual ~GfxTilingPattern(); - - virtual GfxPattern *copy(); - - int getPaintType() { return paintType; } - int getTilingType() { return tilingType; } - double *getBBox() { return bbox; } - double getXStep() { return xStep; } - double getYStep() { return yStep; } - Dict *getResDict() - { return resDict.isDict() ? resDict.getDict() : (Dict *)NULL; } - double *getMatrix() { return matrix; } - Object *getContentStream() { return &contentStream; } - -private: - - GfxTilingPattern(int paintTypeA, int tilingTypeA, - double *bboxA, double xStepA, double yStepA, - Object *resDictA, double *matrixA, - Object *contentStreamA); - - int paintType; - int tilingType; - double bbox[4]; - double xStep, yStep; - Object resDict; - double matrix[6]; - Object contentStream; -}; - -//------------------------------------------------------------------------ -// GfxShadingPattern -//------------------------------------------------------------------------ - -class GfxShadingPattern: public GfxPattern { -public: - - static GfxShadingPattern *parse(Object *patObj); - virtual ~GfxShadingPattern(); - - virtual GfxPattern *copy(); - - GfxShading *getShading() { return shading; } - double *getMatrix() { return matrix; } - -private: - - GfxShadingPattern(GfxShading *shadingA, double *matrixA); - - GfxShading *shading; - double matrix[6]; -}; - -//------------------------------------------------------------------------ -// GfxShading -//------------------------------------------------------------------------ - -class GfxShading { -public: - - GfxShading(int typeA); - GfxShading(GfxShading *shading); - virtual ~GfxShading(); - - static GfxShading *parse(Object *obj); - - virtual GfxShading *copy() = 0; - - int getType() { return type; } - GfxColorSpace *getColorSpace() { return colorSpace; } - GfxColor *getBackground() { return &background; } - GBool getHasBackground() { return hasBackground; } - void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA) - { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } - GBool getHasBBox() { return hasBBox; } - -protected: - - GBool init(Dict *dict); - - int type; - GfxColorSpace *colorSpace; - GfxColor background; - GBool hasBackground; - double xMin, yMin, xMax, yMax; - GBool hasBBox; -}; - -//------------------------------------------------------------------------ -// GfxFunctionShading -//------------------------------------------------------------------------ - -class GfxFunctionShading: public GfxShading { -public: - - GfxFunctionShading(double x0A, double y0A, - double x1A, double y1A, - double *matrixA, - Function **funcsA, int nFuncsA); - GfxFunctionShading(GfxFunctionShading *shading); - virtual ~GfxFunctionShading(); - - static GfxFunctionShading *parse(Dict *dict); - - virtual GfxShading *copy(); - - void getDomain(double *x0A, double *y0A, double *x1A, double *y1A) - { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } - double *getMatrix() { return matrix; } - int getNFuncs() { return nFuncs; } - Function *getFunc(int i) { return funcs[i]; } - void getColor(double x, double y, GfxColor *color); - -private: - - double x0, y0, x1, y1; - double matrix[6]; - Function *funcs[gfxColorMaxComps]; - int nFuncs; -}; - -//------------------------------------------------------------------------ -// GfxAxialShading -//------------------------------------------------------------------------ - -class GfxAxialShading: public GfxShading { -public: - - GfxAxialShading(double x0A, double y0A, - double x1A, double y1A, - double t0A, double t1A, - Function **funcsA, int nFuncsA, - GBool extend0A, GBool extend1A); - GfxAxialShading(GfxAxialShading *shading); - virtual ~GfxAxialShading(); - - static GfxAxialShading *parse(Dict *dict); - - virtual GfxShading *copy(); - - void getCoords(double *x0A, double *y0A, double *x1A, double *y1A) - { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } - double getDomain0() { return t0; } - double getDomain1() { return t1; } - GBool getExtend0() { return extend0; } - GBool getExtend1() { return extend1; } - int getNFuncs() { return nFuncs; } - Function *getFunc(int i) { return funcs[i]; } - void getColor(double t, GfxColor *color); - -private: - - double x0, y0, x1, y1; - double t0, t1; - Function *funcs[gfxColorMaxComps]; - int nFuncs; - GBool extend0, extend1; -}; - -//------------------------------------------------------------------------ -// GfxRadialShading -//------------------------------------------------------------------------ - -class GfxRadialShading: public GfxShading { -public: - - GfxRadialShading(double x0A, double y0A, double r0A, - double x1A, double y1A, double r1A, - double t0A, double t1A, - Function **funcsA, int nFuncsA, - GBool extend0A, GBool extend1A); - GfxRadialShading(GfxRadialShading *shading); - virtual ~GfxRadialShading(); - - static GfxRadialShading *parse(Dict *dict); - - virtual GfxShading *copy(); - - void getCoords(double *x0A, double *y0A, double *r0A, - double *x1A, double *y1A, double *r1A) - { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; } - double getDomain0() { return t0; } - double getDomain1() { return t1; } - GBool getExtend0() { return extend0; } - GBool getExtend1() { return extend1; } - int getNFuncs() { return nFuncs; } - Function *getFunc(int i) { return funcs[i]; } - void getColor(double t, GfxColor *color); - -private: - - double x0, y0, r0, x1, y1, r1; - double t0, t1; - Function *funcs[gfxColorMaxComps]; - int nFuncs; - GBool extend0, extend1; -}; - -//------------------------------------------------------------------------ -// GfxGouraudTriangleShading -//------------------------------------------------------------------------ - -struct GfxGouraudVertex { - double x, y; - GfxColor color; -}; - -class GfxGouraudTriangleShading: public GfxShading { -public: - - GfxGouraudTriangleShading(int typeA, - GfxGouraudVertex *verticesA, int nVerticesA, - int (*trianglesA)[3], int nTrianglesA, - Function **funcsA, int nFuncsA); - GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading); - virtual ~GfxGouraudTriangleShading(); - - static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str); - - virtual GfxShading *copy(); - - int getNTriangles() { return nTriangles; } - void getTriangle(int i, double *x0, double *y0, GfxColor *color0, - double *x1, double *y1, GfxColor *color1, - double *x2, double *y2, GfxColor *color2); - -private: - - GfxGouraudVertex *vertices; - int nVertices; - int (*triangles)[3]; - int nTriangles; - Function *funcs[gfxColorMaxComps]; - int nFuncs; -}; - -//------------------------------------------------------------------------ -// GfxPatchMeshShading -//------------------------------------------------------------------------ - -struct GfxPatch { - double x[4][4]; - double y[4][4]; - GfxColor color[2][2]; -}; - -class GfxPatchMeshShading: public GfxShading { -public: - - GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA, - Function **funcsA, int nFuncsA); - GfxPatchMeshShading(GfxPatchMeshShading *shading); - virtual ~GfxPatchMeshShading(); - - static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str); - - virtual GfxShading *copy(); - - int getNPatches() { return nPatches; } - GfxPatch *getPatch(int i) { return &patches[i]; } - -private: - - GfxPatch *patches; - int nPatches; - Function *funcs[gfxColorMaxComps]; - int nFuncs; -}; - -//------------------------------------------------------------------------ -// GfxImageColorMap -//------------------------------------------------------------------------ - -class GfxImageColorMap { -public: - - // Constructor. - GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA); - - // Destructor. - ~GfxImageColorMap(); - - // Return a copy of this color map. - GfxImageColorMap *copy() { return new GfxImageColorMap(this); } - - // Is color map valid? - GBool isOk() { return ok; } - - // Get the color space. - GfxColorSpace *getColorSpace() { return colorSpace; } - - // Get stream decoding info. - int getNumPixelComps() { return nComps; } - int getBits() { return bits; } - - // Get decode table. - double getDecodeLow(int i) { return decodeLow[i]; } - double getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; } - - // Convert an image pixel to a color. - void getGray(Guchar *x, GfxGray *gray); - void getRGB(Guchar *x, GfxRGB *rgb); - void getCMYK(Guchar *x, GfxCMYK *cmyk); - void getColor(Guchar *x, GfxColor *color); - -private: - - GfxImageColorMap(GfxImageColorMap *colorMap); - - GfxColorSpace *colorSpace; // the image color space - int bits; // bits per component - int nComps; // number of components in a pixel - GfxColorSpace *colorSpace2; // secondary color space - int nComps2; // number of components in colorSpace2 - GfxColorComp * // lookup table - lookup[gfxColorMaxComps]; - double // minimum values for each component - decodeLow[gfxColorMaxComps]; - double // max - min value for each component - decodeRange[gfxColorMaxComps]; - GBool ok; -}; - -//------------------------------------------------------------------------ -// GfxSubpath and GfxPath -//------------------------------------------------------------------------ - -class GfxSubpath { -public: - - // Constructor. - GfxSubpath(double x1, double y1); - - // Destructor. - ~GfxSubpath(); - - // Copy. - GfxSubpath *copy() { return new GfxSubpath(this); } - - // Get points. - int getNumPoints() { return n; } - double getX(int i) { return x[i]; } - double getY(int i) { return y[i]; } - GBool getCurve(int i) { return curve[i]; } - - // Get last point. - double getLastX() { return x[n-1]; } - double getLastY() { return y[n-1]; } - - // Add a line segment. - void lineTo(double x1, double y1); - - // Add a Bezier curve. - void curveTo(double x1, double y1, double x2, double y2, - double x3, double y3); - - // Close the subpath. - void close(); - GBool isClosed() { return closed; } - - // Add (, ) to each point in the subpath. - void offset(double dx, double dy); - -private: - - double *x, *y; // points - GBool *curve; // curve[i] => point i is a control point - // for a Bezier curve - int n; // number of points - int size; // size of x/y arrays - GBool closed; // set if path is closed - - GfxSubpath(GfxSubpath *subpath); -}; - -class GfxPath { -public: - - // Constructor. - GfxPath(); - - // Destructor. - ~GfxPath(); - - // Copy. - GfxPath *copy() - { return new GfxPath(justMoved, firstX, firstY, subpaths, n, size); } - - // Is there a current point? - GBool isCurPt() { return n > 0 || justMoved; } - - // Is the path non-empty, i.e., is there at least one segment? - GBool isPath() { return n > 0; } - - // Get subpaths. - int getNumSubpaths() { return n; } - GfxSubpath *getSubpath(int i) { return subpaths[i]; } - - // Get last point on last subpath. - double getLastX() { return subpaths[n-1]->getLastX(); } - double getLastY() { return subpaths[n-1]->getLastY(); } - - // Move the current point. - void moveTo(double x, double y); - - // Add a segment to the last subpath. - void lineTo(double x, double y); - - // Add a Bezier curve to the last subpath - void curveTo(double x1, double y1, double x2, double y2, - double x3, double y3); - - // Close the last subpath. - void close(); - - // Append to . - void append(GfxPath *path); - - // Add (, ) to each point in the path. - void offset(double dx, double dy); - -private: - - GBool justMoved; // set if a new subpath was just started - double firstX, firstY; // first point in new subpath - GfxSubpath **subpaths; // subpaths - int n; // number of subpaths - int size; // size of subpaths array - - GfxPath(GBool justMoved1, double firstX1, double firstY1, - GfxSubpath **subpaths1, int n1, int size1); -}; - -//------------------------------------------------------------------------ -// GfxState -//------------------------------------------------------------------------ - -class GfxState { -public: - - // Construct a default GfxState, for a device with resolution - // x , page box , page rotation , and - // coordinate system specified by . - GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, - int rotateA, GBool upsideDown); - - // Destructor. - ~GfxState(); - - // Copy. - GfxState *copy() { return new GfxState(this); } - - // Accessors. - double *getCTM() { return ctm; } - double getX1() { return px1; } - double getY1() { return py1; } - double getX2() { return px2; } - double getY2() { return py2; } - double getPageWidth() { return pageWidth; } - double getPageHeight() { return pageHeight; } - int getRotate() { return rotate; } - GfxColor *getFillColor() { return &fillColor; } - GfxColor *getStrokeColor() { return &strokeColor; } - void getFillGray(GfxGray *gray) - { fillColorSpace->getGray(&fillColor, gray); } - void getStrokeGray(GfxGray *gray) - { strokeColorSpace->getGray(&strokeColor, gray); } - void getFillRGB(GfxRGB *rgb) - { fillColorSpace->getRGB(&fillColor, rgb); } - void getStrokeRGB(GfxRGB *rgb) - { strokeColorSpace->getRGB(&strokeColor, rgb); } - void getFillCMYK(GfxCMYK *cmyk) - { fillColorSpace->getCMYK(&fillColor, cmyk); } - void getStrokeCMYK(GfxCMYK *cmyk) - { strokeColorSpace->getCMYK(&strokeColor, cmyk); } - GfxColorSpace *getFillColorSpace() { return fillColorSpace; } - GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; } - GfxPattern *getFillPattern() { return fillPattern; } - GfxPattern *getStrokePattern() { return strokePattern; } - GfxBlendMode getBlendMode() { return blendMode; } - double getFillOpacity() { return fillOpacity; } - double getStrokeOpacity() { return strokeOpacity; } - GBool getFillOverprint() { return fillOverprint; } - GBool getStrokeOverprint() { return strokeOverprint; } - double getLineWidth() { return lineWidth; } - void getLineDash(double **dash, int *length, double *start) - { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; } - int getFlatness() { return flatness; } - int getLineJoin() { return lineJoin; } - int getLineCap() { return lineCap; } - double getMiterLimit() { return miterLimit; } - GfxFont *getFont() { return font; } - double getFontSize() { return fontSize; } - double *getTextMat() { return textMat; } - double getCharSpace() { return charSpace; } - double getWordSpace() { return wordSpace; } - double getHorizScaling() { return horizScaling; } - double getLeading() { return leading; } - double getRise() { return rise; } - int getRender() { return render; } - GfxPath *getPath() { return path; } - void setPath(GfxPath *pathA); - double getCurX() { return curX; } - double getCurY() { return curY; } - void getClipBBox(double *xMin, double *yMin, double *xMax, double *yMax) - { *xMin = clipXMin; *yMin = clipYMin; *xMax = clipXMax; *yMax = clipYMax; } - void getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax); - double getLineX() { return lineX; } - double getLineY() { return lineY; } - - // Is there a current point/path? - GBool isCurPt() { return path->isCurPt(); } - GBool isPath() { return path->isPath(); } - - // Transforms. - void transform(double x1, double y1, double *x2, double *y2) - { *x2 = ctm[0] * x1 + ctm[2] * y1 + ctm[4]; - *y2 = ctm[1] * x1 + ctm[3] * y1 + ctm[5]; } - void transformDelta(double x1, double y1, double *x2, double *y2) - { *x2 = ctm[0] * x1 + ctm[2] * y1; - *y2 = ctm[1] * x1 + ctm[3] * y1; } - void textTransform(double x1, double y1, double *x2, double *y2) - { *x2 = textMat[0] * x1 + textMat[2] * y1 + textMat[4]; - *y2 = textMat[1] * x1 + textMat[3] * y1 + textMat[5]; } - void textTransformDelta(double x1, double y1, double *x2, double *y2) - { *x2 = textMat[0] * x1 + textMat[2] * y1; - *y2 = textMat[1] * x1 + textMat[3] * y1; } - double transformWidth(double w); - double getTransformedLineWidth() - { return transformWidth(lineWidth); } - double getTransformedFontSize(); - void getFontTransMat(double *m11, double *m12, double *m21, double *m22); - - // Change state parameters. - void setCTM(double a, double b, double c, - double d, double e, double f); - void concatCTM(double a, double b, double c, - double d, double e, double f); - void setFillColorSpace(GfxColorSpace *colorSpace); - void setStrokeColorSpace(GfxColorSpace *colorSpace); - void setFillColor(GfxColor *color) { fillColor = *color; } - void setStrokeColor(GfxColor *color) { strokeColor = *color; } - void setFillPattern(GfxPattern *pattern); - void setStrokePattern(GfxPattern *pattern); - void setBlendMode(GfxBlendMode mode) { blendMode = mode; } - void setFillOpacity(double opac) { fillOpacity = opac; } - void setStrokeOpacity(double opac) { strokeOpacity = opac; } - void setFillOverprint(GBool op) { fillOverprint = op; } - void setStrokeOverprint(GBool op) { strokeOverprint = op; } - void setLineWidth(double width) { lineWidth = width; } - void setLineDash(double *dash, int length, double start); - void setFlatness(int flatness1) { flatness = flatness1; } - void setLineJoin(int lineJoin1) { lineJoin = lineJoin1; } - void setLineCap(int lineCap1) { lineCap = lineCap1; } - void setMiterLimit(double limit) { miterLimit = limit; } - void setFont(GfxFont *fontA, double fontSizeA) - { font = fontA; fontSize = fontSizeA; } - void setTextMat(double a, double b, double c, - double d, double e, double f) - { textMat[0] = a; textMat[1] = b; textMat[2] = c; - textMat[3] = d; textMat[4] = e; textMat[5] = f; } - void setCharSpace(double space) - { charSpace = space; } - void setWordSpace(double space) - { wordSpace = space; } - void setHorizScaling(double scale) - { horizScaling = 0.01 * scale; } - void setLeading(double leadingA) - { leading = leadingA; } - void setRise(double riseA) - { rise = riseA; } - void setRender(int renderA) - { render = renderA; } - - // Add to path. - void moveTo(double x, double y) - { path->moveTo(curX = x, curY = y); } - void lineTo(double x, double y) - { path->lineTo(curX = x, curY = y); } - void curveTo(double x1, double y1, double x2, double y2, - double x3, double y3) - { path->curveTo(x1, y1, x2, y2, curX = x3, curY = y3); } - void closePath() - { path->close(); curX = path->getLastX(); curY = path->getLastY(); } - void clearPath(); - - // Update clip region. - void clip(); - - // Text position. - void textSetPos(double tx, double ty) { lineX = tx; lineY = ty; } - void textMoveTo(double tx, double ty) - { lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); } - void textShift(double tx, double ty); - void shift(double dx, double dy); - - // Push/pop GfxState on/off stack. - GfxState *save(); - GfxState *restore(); - GBool hasSaves() { return saved != NULL; } - - // Misc - GBool parseBlendMode(Object *obj, GfxBlendMode *mode); - -private: - - double ctm[6]; // coord transform matrix - double px1, py1, px2, py2; // page corners (user coords) - double pageWidth, pageHeight; // page size (pixels) - int rotate; // page rotation angle - - GfxColorSpace *fillColorSpace; // fill color space - GfxColorSpace *strokeColorSpace; // stroke color space - GfxColor fillColor; // fill color - GfxColor strokeColor; // stroke color - GfxPattern *fillPattern; // fill pattern - GfxPattern *strokePattern; // stroke pattern - GfxBlendMode blendMode; // transparency blend mode - double fillOpacity; // fill opacity - double strokeOpacity; // stroke opacity - GBool fillOverprint; // fill overprint - GBool strokeOverprint; // stroke overprint - - double lineWidth; // line width - double *lineDash; // line dash - int lineDashLength; - double lineDashStart; - int flatness; // curve flatness - int lineJoin; // line join style - int lineCap; // line cap style - double miterLimit; // line miter limit - - GfxFont *font; // font - double fontSize; // font size - double textMat[6]; // text matrix - double charSpace; // character spacing - double wordSpace; // word spacing - double horizScaling; // horizontal scaling - double leading; // text leading - double rise; // text rise - int render; // text rendering mode - - GfxPath *path; // array of path elements - double curX, curY; // current point (user coords) - double lineX, lineY; // start of current text line (text coords) - - double clipXMin, clipYMin, // bounding box for clip region - clipXMax, clipYMax; - - GfxState *saved; // next GfxState on stack - - GfxState(GfxState *state); -}; - -#endif diff --git a/xpdf/xpdf/GlobalParams.cc b/xpdf/xpdf/GlobalParams.cc deleted file mode 100644 index 12e81e7a5..000000000 --- a/xpdf/xpdf/GlobalParams.cc +++ /dev/null @@ -1,2064 +0,0 @@ -//======================================================================== -// -// GlobalParams.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -// KPDF: additional includes for Qt and Xft -#include -#include -#include -// -- gentoo compile fix (XFree 4.3.0, FC 2.2.3, FreeType 2.1.9) -- -// on other distros these 2 lines should't harm -#include -#include FT_FREETYPE_H -// -- ---------------------------------------------------------- -- -#include -#include -#include -#include -#include -#include -#if HAVE_PAPER_H -#include -#endif -#include "gmem.h" -#include "GString.h" -#include "GList.h" -#include "GHash.h" -#include "gfile.h" -#include "Error.h" -#include "NameToCharCode.h" -#include "CharCodeToUnicode.h" -#include "UnicodeMap.h" -#include "CMap.h" -#include "BuiltinFontTables.h" -#include "FontEncodingTables.h" -#ifdef ENABLE_PLUGINS -# include "XpdfPluginAPI.h" -#endif -#include "GlobalParams.h" - -#if MULTITHREADED -# define lockGlobalParams gLockMutex(&mutex) -# define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex) -# define lockCMapCache gLockMutex(&cMapCacheMutex) -# define unlockGlobalParams gUnlockMutex(&mutex) -# define unlockUnicodeMapCache gUnlockMutex(&unicodeMapCacheMutex) -# define unlockCMapCache gUnlockMutex(&cMapCacheMutex) -#else -# define lockGlobalParams -# define lockUnicodeMapCache -# define lockCMapCache -# define unlockGlobalParams -# define unlockUnicodeMapCache -# define unlockCMapCache -#endif - -#include "NameToUnicodeTable.h" -#include "UnicodeMapTables.h" -#include "UTF8.h" - -#ifdef ENABLE_PLUGINS -# ifdef WIN32 -extern XpdfPluginVecTable xpdfPluginVecTable; -# endif -#endif - -//------------------------------------------------------------------------ - -#define cidToUnicodeCacheSize 4 -#define unicodeToUnicodeCacheSize 4 - -//------------------------------------------------------------------------ - -static struct { - const char *name; - const char *t1FileName; - const char *ttFileName; -} displayFontTab[] = { - {"Courier", "n022003l.pfb", "cour.ttf"}, - {"Courier-Bold", "n022004l.pfb", "courbd.ttf"}, - {"Courier-BoldOblique", "n022024l.pfb", "courbi.ttf"}, - {"Courier-Oblique", "n022023l.pfb", "couri.ttf"}, - {"Helvetica", "n019003l.pfb", "arial.ttf"}, - {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf"}, - {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf"}, - {"Helvetica-Oblique", "n019023l.pfb", "ariali.ttf"}, - {"Symbol", "s050000l.pfb", NULL}, - {"Times-Bold", "n021004l.pfb", "timesbd.ttf"}, - {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf"}, - {"Times-Italic", "n021023l.pfb", "timesi.ttf"}, - {"Times-Roman", "n021003l.pfb", "times.ttf"}, - {"ZapfDingbats", "d050000l.pfb", NULL}, - {NULL, NULL, NULL} -}; - -#ifdef WIN32 -static const char *displayFontDirs[] = { - "c:/windows/fonts", - "c:/winnt/fonts", - NULL -}; -#else -static const char *displayFontDirs[] = { - "/usr/share/ghostscript/fonts", - "/usr/pkg/share/ghostscript/fonts", - "/usr/local/share/ghostscript/fonts", - "/usr/share/fonts/default/Type1", - "/usr/X11R6/lib/X11/fonts/Type1", - "/usr/share/fonts/default/ghostscript", - "/usr/share/fonts/type1/gsfonts", - NULL -}; -#endif - -//------------------------------------------------------------------------ - -GlobalParams *globalParams = NULL; - -//------------------------------------------------------------------------ -// DisplayFontParam -//------------------------------------------------------------------------ - -DisplayFontParam::DisplayFontParam(GString *nameA, - DisplayFontParamKind kindA) { - name = nameA; - kind = kindA; - switch (kind) { - case displayFontT1: - t1.fileName = NULL; - break; - case displayFontTT: - tt.fileName = NULL; - break; - } -} - -DisplayFontParam::~DisplayFontParam() { - delete name; - switch (kind) { - case displayFontT1: - if (t1.fileName) { - delete t1.fileName; - } - break; - case displayFontTT: - if (tt.fileName) { - delete tt.fileName; - } - break; - } -} - -//------------------------------------------------------------------------ -// PSFontParam -//------------------------------------------------------------------------ - -PSFontParam::PSFontParam(GString *pdfFontNameA, int wModeA, - GString *psFontNameA, GString *encodingA) { - pdfFontName = pdfFontNameA; - wMode = wModeA; - psFontName = psFontNameA; - encoding = encodingA; -} - -PSFontParam::~PSFontParam() { - delete pdfFontName; - delete psFontName; - if (encoding) { - delete encoding; - } -} - -#ifdef ENABLE_PLUGINS -//------------------------------------------------------------------------ -// Plugin -//------------------------------------------------------------------------ - -class Plugin { -public: - - static Plugin *load(char *type, char *name); - ~Plugin(); - -private: - -#ifdef WIN32 - Plugin(HMODULE libA); - HMODULE lib; -#else - Plugin(void *dlA); - void *dl; -#endif -}; - -Plugin *Plugin::load(char *type, char *name) { - GString *path; - Plugin *plugin; - XpdfPluginVecTable *vt; - XpdfBool (*xpdfInitPlugin)(void); -#ifdef WIN32 - HMODULE libA; -#else - void *dlA; -#endif - - path = globalParams->getBaseDir(); - appendToPath(path, "plugins"); - appendToPath(path, type); - appendToPath(path, name); - -#ifdef WIN32 - path->append(".dll"); - if (!(libA = LoadLibrary(path->getCString()))) { - error(-1, "Failed to load plugin '%s'", - path->getCString()); - goto err1; - } - if (!(vt = (XpdfPluginVecTable *) - GetProcAddress(libA, "xpdfPluginVecTable"))) { - error(-1, "Failed to find xpdfPluginVecTable in plugin '%s'", - path->getCString()); - goto err2; - } -#else - //~ need to deal with other extensions here - path->append(".so"); - if (!(dlA = dlopen(path->getCString(), RTLD_NOW))) { - error(-1, "Failed to load plugin '%s': %s", - path->getCString(), dlerror()); - goto err1; - } - if (!(vt = (XpdfPluginVecTable *)dlsym(dlA, "xpdfPluginVecTable"))) { - error(-1, "Failed to find xpdfPluginVecTable in plugin '%s'", - path->getCString()); - goto err2; - } -#endif - - if (vt->version != xpdfPluginVecTable.version) { - error(-1, "Plugin '%s' is wrong version", path->getCString()); - goto err2; - } - memcpy(vt, &xpdfPluginVecTable, sizeof(xpdfPluginVecTable)); - -#ifdef WIN32 - if (!(xpdfInitPlugin = (XpdfBool (*)(void)) - GetProcAddress(libA, "xpdfInitPlugin"))) { - error(-1, "Failed to find xpdfInitPlugin in plugin '%s'", - path->getCString()); - goto err2; - } -#else - if (!(xpdfInitPlugin = (XpdfBool (*)(void))dlsym(dlA, "xpdfInitPlugin"))) { - error(-1, "Failed to find xpdfInitPlugin in plugin '%s'", - path->getCString()); - goto err2; - } -#endif - - if (!(*xpdfInitPlugin)()) { - error(-1, "Initialization of plugin '%s' failed", - path->getCString()); - goto err2; - } - -#ifdef WIN32 - plugin = new Plugin(libA); -#else - plugin = new Plugin(dlA); -#endif - - delete path; - return plugin; - - err2: -#ifdef WIN32 - FreeLibrary(libA); -#else - dlclose(dlA); -#endif - err1: - delete path; - return NULL; -} - -#ifdef WIN32 -Plugin::Plugin(HMODULE libA) { - lib = libA; -} -#else -Plugin::Plugin(void *dlA) { - dl = dlA; -} -#endif - -Plugin::~Plugin() { - void (*xpdfFreePlugin)(void); - -#ifdef WIN32 - if ((xpdfFreePlugin = (void (*)(void)) - GetProcAddress(lib, "xpdfFreePlugin"))) { - (*xpdfFreePlugin)(); - } - FreeLibrary(lib); -#else - if ((xpdfFreePlugin = (void (*)(void))dlsym(dl, "xpdfFreePlugin"))) { - (*xpdfFreePlugin)(); - } - dlclose(dl); -#endif -} - -#endif // ENABLE_PLUGINS - -//------------------------------------------------------------------------ -// parsing -//------------------------------------------------------------------------ - -GlobalParams::GlobalParams(const char *cfgFileName) { - UnicodeMap *map; - GString *fileName; - FILE *f; - int i; - -#if MULTITHREADED - gInitMutex(&mutex); - gInitMutex(&unicodeMapCacheMutex); - gInitMutex(&cMapCacheMutex); -#endif - - initBuiltinFontTables(); - - // scan the encoding in reverse because we want the lowest-numbered - // index for each char name ('space' is encoded twice) - macRomanReverseMap = new NameToCharCode(); - for (i = 255; i >= 0; --i) { - if (macRomanEncoding[i]) { - macRomanReverseMap->add(macRomanEncoding[i], (CharCode)i); - } - } - -#ifdef WIN32 - // baseDir will be set by a call to setBaseDir - baseDir = new GString(); -#else - baseDir = appendToPath(getHomeDir(), ".xpdf"); -#endif - nameToUnicode = new NameToCharCode(); - cidToUnicodes = new GHash(gTrue); - unicodeToUnicodes = new GHash(gTrue); - residentUnicodeMaps = new GHash(); - unicodeMaps = new GHash(gTrue); - cMapDirs = new GHash(gTrue); - toUnicodeDirs = new GList(); - displayFonts = new GHash(); - displayCIDFonts = new GHash(); - displayNamedCIDFonts = new GHash(); -#if HAVE_PAPER_H - char *paperName; - const struct paper *paperType; - paperinit(); - if ((paperName = systempapername())) { - paperType = paperinfo(paperName); - psPaperWidth = (int)paperpswidth(paperType); - psPaperHeight = (int)paperpsheight(paperType); - } else { - error(-1, "No paper information available - using defaults"); - psPaperWidth = defPaperWidth; - psPaperHeight = defPaperHeight; - } - paperdone(); -#else - psPaperWidth = defPaperWidth; - psPaperHeight = defPaperHeight; -#endif - psImageableLLX = psImageableLLY = 0; - psImageableURX = psPaperWidth; - psImageableURY = psPaperHeight; - psCrop = gTrue; - psExpandSmaller = gFalse; - psShrinkLarger = gTrue; - psCenter = gTrue; - psDuplex = gFalse; - psLevel = psLevel2; - psFile = NULL; - psFonts = new GHash(); - psNamedFonts16 = new GList(); - psFonts16 = new GList(); - psEmbedType1 = gTrue; - psEmbedTrueType = gTrue; - psEmbedCIDPostScript = gTrue; - psEmbedCIDTrueType = gTrue; - psOPI = gFalse; - psASCIIHex = gFalse; - // KPDF: use always UTF-8 and QString::fromUtf - textEncoding = new GString("UTF-8"); -#if defined(WIN32) - textEOL = eolDOS; -#elif defined(MACOS) - textEOL = eolMac; -#else - textEOL = eolUnix; -#endif - textPageBreaks = gTrue; - textKeepTinyChars = gFalse; - fontDirs = new GList(); - initialZoom = new GString("125"); - continuousView = gFalse; - enableT1lib = gTrue; - enableFreeType = gTrue; - antialias = gTrue; - urlCommand = NULL; - movieCommand = NULL; - mapNumericCharNames = gTrue; - printCommands = gFalse; - errQuiet = gFalse; - - cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize); - unicodeToUnicodeCache = - new CharCodeToUnicodeCache(unicodeToUnicodeCacheSize); - unicodeMapCache = new UnicodeMapCache(); - cMapCache = new CMapCache(); - -#ifdef ENABLE_PLUGINS - plugins = new GList(); - securityHandlers = new GList(); -#endif - - // set up the initial nameToUnicode table - for (i = 0; nameToUnicodeTab[i].name; ++i) { - nameToUnicode->add(nameToUnicodeTab[i].name, nameToUnicodeTab[i].u); - } - - // set up the residentUnicodeMaps table - map = new UnicodeMap("Latin1", gFalse, - latin1UnicodeMapRanges, latin1UnicodeMapLen); - residentUnicodeMaps->add(map->getEncodingName(), map); - map = new UnicodeMap("ASCII7", gFalse, - ascii7UnicodeMapRanges, ascii7UnicodeMapLen); - residentUnicodeMaps->add(map->getEncodingName(), map); - map = new UnicodeMap("Symbol", gFalse, - symbolUnicodeMapRanges, symbolUnicodeMapLen); - residentUnicodeMaps->add(map->getEncodingName(), map); - map = new UnicodeMap("ZapfDingbats", gFalse, zapfDingbatsUnicodeMapRanges, - zapfDingbatsUnicodeMapLen); - residentUnicodeMaps->add(map->getEncodingName(), map); - map = new UnicodeMap("UTF-8", gTrue, &mapUTF8); - residentUnicodeMaps->add(map->getEncodingName(), map); - map = new UnicodeMap("UCS-2", gTrue, &mapUCS2); - residentUnicodeMaps->add(map->getEncodingName(), map); - - // look for a user config file, then a system-wide config file - f = NULL; - fileName = NULL; - if (cfgFileName && cfgFileName[0]) { - fileName = new GString(cfgFileName); - if (!(f = fopen(fileName->getCString(), "r"))) { - delete fileName; - } - } - if (!f) { - fileName = appendToPath(getHomeDir(), xpdfUserConfigFile); - if (!(f = fopen(fileName->getCString(), "r"))) { - delete fileName; - } - } - if (!f) { -#if defined(WIN32) && !defined(__CYGWIN32__) - char buf[512]; - i = GetModuleFileName(NULL, buf, sizeof(buf)); - if (i <= 0 || i >= sizeof(buf)) { - // error or path too long for buffer - just use the current dir - buf[0] = '\0'; - } - fileName = grabPath(buf); - appendToPath(fileName, xpdfSysConfigFile); -#else - fileName = new GString(xpdfSysConfigFile); -#endif - if (!(f = fopen(fileName->getCString(), "r"))) { - delete fileName; - } - } - if (f) { - parseFile(fileName, f); - delete fileName; - fclose(f); - } -} - -void GlobalParams::parseFile(GString *fileName, FILE *f) { - int line; - GList *tokens; - GString *cmd, *incFile; - char *p1, *p2; - char buf[512]; - FILE *f2; - - line = 1; - while (getLine(buf, sizeof(buf) - 1, f)) { - - // break the line into tokens - tokens = new GList(); - p1 = buf; - while (*p1) { - for (; *p1 && isspace(*p1); ++p1) ; - if (!*p1) { - break; - } - if (*p1 == '"' || *p1 == '\'') { - for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ; - ++p1; - } else { - for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ; - } - tokens->append(new GString(p1, p2 - p1)); - p1 = *p2 ? p2 + 1 : p2; - } - - if (tokens->getLength() > 0 && - ((GString *)tokens->get(0))->getChar(0) != '#') { - cmd = (GString *)tokens->get(0); - if (!cmd->cmp("include")) { - if (tokens->getLength() == 2) { - incFile = (GString *)tokens->get(1); - if ((f2 = fopen(incFile->getCString(), "r"))) { - parseFile(incFile, f2); - fclose(f2); - } else { - error(-1, "Couldn't find included config file: '%s' (%s:%d)", - incFile->getCString(), fileName->getCString(), line); - } - } else { - error(-1, "Bad 'include' config file command (%s:%d)", - fileName->getCString(), line); - } - } else if (!cmd->cmp("nameToUnicode")) { - parseNameToUnicode(tokens, fileName, line); - } else if (!cmd->cmp("cidToUnicode")) { - parseCIDToUnicode(tokens, fileName, line); - } else if (!cmd->cmp("unicodeToUnicode")) { - parseUnicodeToUnicode(tokens, fileName, line); - } else if (!cmd->cmp("unicodeMap")) { - parseUnicodeMap(tokens, fileName, line); - } else if (!cmd->cmp("cMapDir")) { - parseCMapDir(tokens, fileName, line); - } else if (!cmd->cmp("toUnicodeDir")) { - parseToUnicodeDir(tokens, fileName, line); - } else if (!cmd->cmp("displayFontT1")) { - parseDisplayFont(tokens, displayFonts, displayFontT1, fileName, line); - } else if (!cmd->cmp("displayFontTT")) { - parseDisplayFont(tokens, displayFonts, displayFontTT, fileName, line); - } else if (!cmd->cmp("displayNamedCIDFontT1")) { - parseDisplayFont(tokens, displayNamedCIDFonts, - displayFontT1, fileName, line); - } else if (!cmd->cmp("displayCIDFontT1")) { - parseDisplayFont(tokens, displayCIDFonts, - displayFontT1, fileName, line); - } else if (!cmd->cmp("displayNamedCIDFontTT")) { - parseDisplayFont(tokens, displayNamedCIDFonts, - displayFontTT, fileName, line); - } else if (!cmd->cmp("displayCIDFontTT")) { - parseDisplayFont(tokens, displayCIDFonts, - displayFontTT, fileName, line); - } else if (!cmd->cmp("psFile")) { - parsePSFile(tokens, fileName, line); - } else if (!cmd->cmp("psFont")) { - parsePSFont(tokens, fileName, line); - } else if (!cmd->cmp("psNamedFont16")) { - parsePSFont16("psNamedFont16", psNamedFonts16, - tokens, fileName, line); - } else if (!cmd->cmp("psFont16")) { - parsePSFont16("psFont16", psFonts16, tokens, fileName, line); - } else if (!cmd->cmp("psPaperSize")) { - parsePSPaperSize(tokens, fileName, line); - } else if (!cmd->cmp("psImageableArea")) { - parsePSImageableArea(tokens, fileName, line); - } else if (!cmd->cmp("psCrop")) { - parseYesNo("psCrop", &psCrop, tokens, fileName, line); - } else if (!cmd->cmp("psExpandSmaller")) { - parseYesNo("psExpandSmaller", &psExpandSmaller, - tokens, fileName, line); - } else if (!cmd->cmp("psShrinkLarger")) { - parseYesNo("psShrinkLarger", &psShrinkLarger, tokens, fileName, line); - } else if (!cmd->cmp("psCenter")) { - parseYesNo("psCenter", &psCenter, tokens, fileName, line); - } else if (!cmd->cmp("psDuplex")) { - parseYesNo("psDuplex", &psDuplex, tokens, fileName, line); - } else if (!cmd->cmp("psLevel")) { - parsePSLevel(tokens, fileName, line); - } else if (!cmd->cmp("psEmbedType1Fonts")) { - parseYesNo("psEmbedType1", &psEmbedType1, tokens, fileName, line); - } else if (!cmd->cmp("psEmbedTrueTypeFonts")) { - parseYesNo("psEmbedTrueType", &psEmbedTrueType, - tokens, fileName, line); - } else if (!cmd->cmp("psEmbedCIDPostScriptFonts")) { - parseYesNo("psEmbedCIDPostScript", &psEmbedCIDPostScript, - tokens, fileName, line); - } else if (!cmd->cmp("psEmbedCIDTrueTypeFonts")) { - parseYesNo("psEmbedCIDTrueType", &psEmbedCIDTrueType, - tokens, fileName, line); - } else if (!cmd->cmp("psOPI")) { - parseYesNo("psOPI", &psOPI, tokens, fileName, line); - } else if (!cmd->cmp("psASCIIHex")) { - parseYesNo("psASCIIHex", &psASCIIHex, tokens, fileName, line); - } else if (!cmd->cmp("textEncoding")) { -// Always use UTF-8 and allow QString do the magic -// parseTextEncoding(tokens, fileName, line); - } else if (!cmd->cmp("textEOL")) { - parseTextEOL(tokens, fileName, line); - } else if (!cmd->cmp("textPageBreaks")) { - parseYesNo("textPageBreaks", &textPageBreaks, - tokens, fileName, line); - } else if (!cmd->cmp("textKeepTinyChars")) { - parseYesNo("textKeepTinyChars", &textKeepTinyChars, - tokens, fileName, line); - } else if (!cmd->cmp("fontDir")) { - parseFontDir(tokens, fileName, line); - } else if (!cmd->cmp("initialZoom")) { - parseInitialZoom(tokens, fileName, line); - } else if (!cmd->cmp("continuousView")) { - parseYesNo("continuousView", &continuousView, tokens, fileName, line); - } else if (!cmd->cmp("enableT1lib")) { - parseYesNo("enableT1lib", &enableT1lib, tokens, fileName, line); - } else if (!cmd->cmp("enableFreeType")) { - parseYesNo("enableFreeType", &enableFreeType, tokens, fileName, line); - } else if (!cmd->cmp("antialias")) { - parseYesNo("antialias", &antialias, tokens, fileName, line); - } else if (!cmd->cmp("urlCommand")) { - parseCommand("urlCommand", &urlCommand, tokens, fileName, line); - } else if (!cmd->cmp("movieCommand")) { - parseCommand("movieCommand", &movieCommand, tokens, fileName, line); - } else if (!cmd->cmp("mapNumericCharNames")) { - parseYesNo("mapNumericCharNames", &mapNumericCharNames, - tokens, fileName, line); - } else if (!cmd->cmp("printCommands")) { - parseYesNo("printCommands", &printCommands, tokens, fileName, line); - } else if (!cmd->cmp("errQuiet")) { - parseYesNo("errQuiet", &errQuiet, tokens, fileName, line); - } else { - error(-1, "Unknown config file command '%s' (%s:%d)", - cmd->getCString(), fileName->getCString(), line); - if (!cmd->cmp("displayFontX") || - !cmd->cmp("displayNamedCIDFontX") || - !cmd->cmp("displayCIDFontX")) { - error(-1, "-- Xpdf no longer supports X fonts"); - } else if (!cmd->cmp("t1libControl") || !cmd->cmp("freetypeControl")) { - error(-1, "-- The t1libControl and freetypeControl options have been replaced"); - error(-1, " by the enableT1lib, enableFreeType, and antialias options"); - } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { - error(-1, "-- the config file format has changed since Xpdf 0.9x"); - } - } - } - - deleteGList(tokens, GString); - ++line; - } -} - -void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName, - int line) { - GString *name; - char *tok1, *tok2; - FILE *f; - char buf[256]; - int line2; - Unicode u; - - if (tokens->getLength() != 2) { - error(-1, "Bad 'nameToUnicode' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - name = (GString *)tokens->get(1); - if (!(f = fopen(name->getCString(), "r"))) { - error(-1, "Couldn't open 'nameToUnicode' file '%s'", - name->getCString()); - return; - } - line2 = 1; - while (getLine(buf, sizeof(buf), f)) { - tok1 = strtok(buf, " \t\r\n"); - tok2 = strtok(NULL, " \t\r\n"); - if (tok1 && tok2) { - sscanf(tok1, "%x", &u); - nameToUnicode->add(tok2, u); - } else { - error(-1, "Bad line in 'nameToUnicode' file (%s:%d)", name, line2); - } - ++line2; - } - fclose(f); -} - -void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName, - int line) { - GString *collection, *name, *old; - - if (tokens->getLength() != 3) { - error(-1, "Bad 'cidToUnicode' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - collection = (GString *)tokens->get(1); - name = (GString *)tokens->get(2); - if ((old = (GString *)cidToUnicodes->remove(collection))) { - delete old; - } - cidToUnicodes->add(collection->copy(), name->copy()); -} - -void GlobalParams::parseUnicodeToUnicode(GList *tokens, GString *fileName, - int line) { - GString *font, *file, *old; - - if (tokens->getLength() != 3) { - error(-1, "Bad 'unicodeToUnicode' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - font = (GString *)tokens->get(1); - file = (GString *)tokens->get(2); - if ((old = (GString *)unicodeToUnicodes->remove(font))) { - delete old; - } - unicodeToUnicodes->add(font->copy(), file->copy()); -} - -void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName, - int line) { - GString *encodingName, *name, *old; - - if (tokens->getLength() != 3) { - error(-1, "Bad 'unicodeMap' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - encodingName = (GString *)tokens->get(1); - name = (GString *)tokens->get(2); - if ((old = (GString *)unicodeMaps->remove(encodingName))) { - delete old; - } - unicodeMaps->add(encodingName->copy(), name->copy()); -} - -void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) { - GString *collection, *dir; - GList *list; - - if (tokens->getLength() != 3) { - error(-1, "Bad 'cMapDir' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - collection = (GString *)tokens->get(1); - dir = (GString *)tokens->get(2); - if (!(list = (GList *)cMapDirs->lookup(collection))) { - list = new GList(); - cMapDirs->add(collection->copy(), list); - } - list->append(dir->copy()); -} - -void GlobalParams::parseToUnicodeDir(GList *tokens, GString *fileName, - int line) { - if (tokens->getLength() != 2) { - error(-1, "Bad 'toUnicodeDir' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - toUnicodeDirs->append(((GString *)tokens->get(1))->copy()); -} - -void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash, - DisplayFontParamKind kind, - GString *fileName, int line) { - DisplayFontParam *param, *old; - struct stat statbuf; - - if (tokens->getLength() < 2) { - goto err1; - } - param = new DisplayFontParam(((GString *)tokens->get(1))->copy(), kind); - - switch (kind) { - case displayFontT1: - if (tokens->getLength() != 3) { - goto err2; - } - param->t1.fileName = ((GString *)tokens->get(2))->copy(); - if (stat((param->t1.fileName->getCString)(), &statbuf)) { - delete param; // silently ignore non-existing files - return; - } - break; - case displayFontTT: - if (tokens->getLength() < 3) { - goto err2; - } - param->tt.fileName = ((GString *)tokens->get(2))->copy(); - if (stat((param->tt.fileName->getCString)(), &statbuf)) { - delete param; // silently ignore non-existing files - return; - } - if (tokens->getLength() > 3) - param->tt.faceIndex = atoi(((GString *)tokens->get(3))->getCString()); - else - param->tt.faceIndex = 0; - break; - } - - if ((old = (DisplayFontParam *)fontHash->remove(param->name))) { - delete old; - } - fontHash->add(param->name, param); - return; - - err2: - delete param; - err1: - error(-1, "Bad 'display*Font*' config file command (%s:%d)", - fileName->getCString(), line); -} - -void GlobalParams::parsePSPaperSize(GList *tokens, GString *fileName, - int line) { - GString *tok; - - if (tokens->getLength() == 2) { - tok = (GString *)tokens->get(1); - if (!setPSPaperSize(tok->getCString())) { - error(-1, "Bad 'psPaperSize' config file command (%s:%d)", - fileName->getCString(), line); - } - } else if (tokens->getLength() == 3) { - tok = (GString *)tokens->get(1); - psPaperWidth = atoi(tok->getCString()); - tok = (GString *)tokens->get(2); - psPaperHeight = atoi(tok->getCString()); - psImageableLLX = psImageableLLY = 0; - psImageableURX = psPaperWidth; - psImageableURY = psPaperHeight; - } else { - error(-1, "Bad 'psPaperSize' config file command (%s:%d)", - fileName->getCString(), line); - } -} - -void GlobalParams::parsePSImageableArea(GList *tokens, GString *fileName, - int line) { - if (tokens->getLength() != 5) { - error(-1, "Bad 'psImageableArea' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - psImageableLLX = atoi(((GString *)tokens->get(1))->getCString()); - psImageableLLY = atoi(((GString *)tokens->get(2))->getCString()); - psImageableURX = atoi(((GString *)tokens->get(3))->getCString()); - psImageableURY = atoi(((GString *)tokens->get(4))->getCString()); -} - -void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) { - GString *tok; - - if (tokens->getLength() != 2) { - error(-1, "Bad 'psLevel' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - tok = (GString *)tokens->get(1); - if (!tok->cmp("level1")) { - psLevel = psLevel1; - } else if (!tok->cmp("level1sep")) { - psLevel = psLevel1Sep; - } else if (!tok->cmp("level2")) { - psLevel = psLevel2; - } else if (!tok->cmp("level2sep")) { - psLevel = psLevel2Sep; - } else if (!tok->cmp("level3")) { - psLevel = psLevel3; - } else if (!tok->cmp("level3Sep")) { - psLevel = psLevel3Sep; - } else { - error(-1, "Bad 'psLevel' config file command (%s:%d)", - fileName->getCString(), line); - } -} - -void GlobalParams::parsePSFile(GList *tokens, GString *fileName, int line) { - if (tokens->getLength() != 2) { - error(-1, "Bad 'psFile' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - if (psFile) { - delete psFile; - } - psFile = ((GString *)tokens->get(1))->copy(); -} - -void GlobalParams::parsePSFont(GList *tokens, GString *fileName, int line) { - PSFontParam *param; - - if (tokens->getLength() != 3) { - error(-1, "Bad 'psFont' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - param = new PSFontParam(((GString *)tokens->get(1))->copy(), 0, - ((GString *)tokens->get(2))->copy(), NULL); - psFonts->add(param->pdfFontName, param); -} - -void GlobalParams::parsePSFont16(const char *cmdName, GList *fontList, - GList *tokens, GString *fileName, int line) { - PSFontParam *param; - int wMode; - GString *tok; - - if (tokens->getLength() != 5) { - error(-1, "Bad '%s' config file command (%s:%d)", - cmdName, fileName->getCString(), line); - return; - } - tok = (GString *)tokens->get(2); - if (!tok->cmp("H")) { - wMode = 0; - } else if (!tok->cmp("V")) { - wMode = 1; - } else { - error(-1, "Bad '%s' config file command (%s:%d)", - cmdName, fileName->getCString(), line); - return; - } - param = new PSFontParam(((GString *)tokens->get(1))->copy(), - wMode, - ((GString *)tokens->get(3))->copy(), - ((GString *)tokens->get(4))->copy()); - fontList->append(param); -} - -void GlobalParams::parseTextEncoding(GList *tokens, GString *fileName, - int line) { - if (tokens->getLength() != 2) { - error(-1, "Bad 'textEncoding' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - delete textEncoding; - textEncoding = ((GString *)tokens->get(1))->copy(); -} - -void GlobalParams::parseTextEOL(GList *tokens, GString *fileName, int line) { - GString *tok; - - if (tokens->getLength() != 2) { - error(-1, "Bad 'textEOL' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - tok = (GString *)tokens->get(1); - if (!tok->cmp("unix")) { - textEOL = eolUnix; - } else if (!tok->cmp("dos")) { - textEOL = eolDOS; - } else if (!tok->cmp("mac")) { - textEOL = eolMac; - } else { - error(-1, "Bad 'textEOL' config file command (%s:%d)", - fileName->getCString(), line); - } -} - -void GlobalParams::parseFontDir(GList *tokens, GString *fileName, int line) { - if (tokens->getLength() != 2) { - error(-1, "Bad 'fontDir' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - fontDirs->append(((GString *)tokens->get(1))->copy()); -} - -void GlobalParams::parseInitialZoom(GList *tokens, - GString *fileName, int line) { - if (tokens->getLength() != 2) { - error(-1, "Bad 'initialZoom' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - delete initialZoom; - initialZoom = ((GString *)tokens->get(1))->copy(); -} - -void GlobalParams::parseCommand(const char *cmdName, GString **val, - GList *tokens, GString *fileName, int line) { - if (tokens->getLength() != 2) { - error(-1, "Bad '%s' config file command (%s:%d)", - cmdName, fileName->getCString(), line); - return; - } - if (*val) { - delete *val; - } - *val = ((GString *)tokens->get(1))->copy(); -} - -void GlobalParams::parseYesNo(const char *cmdName, GBool *flag, - GList *tokens, GString *fileName, int line) { - GString *tok; - - if (tokens->getLength() != 2) { - error(-1, "Bad '%s' config file command (%s:%d)", - cmdName, fileName->getCString(), line); - return; - } - tok = (GString *)tokens->get(1); - if (!parseYesNo2(tok->getCString(), flag)) { - error(-1, "Bad '%s' config file command (%s:%d)", - cmdName, fileName->getCString(), line); - } -} - -GBool GlobalParams::parseYesNo2(char *token, GBool *flag) { - if (!strcmp(token, "yes")) { - *flag = gTrue; - } else if (!strcmp(token, "no")) { - *flag = gFalse; - } else { - return gFalse; - } - return gTrue; -} - -GlobalParams::~GlobalParams() { - GHashIter *iter; - GString *key; - GList *list; - - freeBuiltinFontTables(); - - delete macRomanReverseMap; - - delete baseDir; - delete nameToUnicode; - deleteGHash(cidToUnicodes, GString); - deleteGHash(unicodeToUnicodes, GString); - deleteGHash(residentUnicodeMaps, UnicodeMap); - deleteGHash(unicodeMaps, GString); - deleteGList(toUnicodeDirs, GString); - deleteGHash(displayFonts, DisplayFontParam); - deleteGHash(displayCIDFonts, DisplayFontParam); - deleteGHash(displayNamedCIDFonts, DisplayFontParam); - if (psFile) { - delete psFile; - } - deleteGHash(psFonts, PSFontParam); - deleteGList(psNamedFonts16, PSFontParam); - deleteGList(psFonts16, PSFontParam); - delete textEncoding; - deleteGList(fontDirs, GString); - delete initialZoom; - if (urlCommand) { - delete urlCommand; - } - if (movieCommand) { - delete movieCommand; - } - - cMapDirs->startIter(&iter); - while (cMapDirs->getNext(&iter, &key, (void **)&list)) { - deleteGList(list, GString); - } - delete cMapDirs; - - delete cidToUnicodeCache; - delete unicodeToUnicodeCache; - delete unicodeMapCache; - delete cMapCache; - -#ifdef ENABLE_PLUGINS - delete securityHandlers; - deleteGList(plugins, Plugin); -#endif - -#if MULTITHREADED - gDestroyMutex(&mutex); - gDestroyMutex(&unicodeMapCacheMutex); - gDestroyMutex(&cMapCacheMutex); -#endif -} - -//------------------------------------------------------------------------ - -void GlobalParams::setBaseDir(char *dir) { - delete baseDir; - baseDir = new GString(dir); -} - -void GlobalParams::setupBaseFonts(char *dir) { - GString *fontName; - GString *fileName; -#ifdef WIN32 - HMODULE shell32Lib; - BOOL (__stdcall *SHGetSpecialFolderPathFunc)(HWND hwndOwner, - LPTSTR lpszPath, - int nFolder, - BOOL fCreate); - char winFontDir[MAX_PATH]; -#endif - FILE *f; - DisplayFontParamKind kind; - DisplayFontParam *dfp; - int i, j; - -#ifdef WIN32 - // SHGetSpecialFolderPath isn't available in older versions of - // shell32.dll (Win95 and WinNT4), so do a dynamic load - winFontDir[0] = '\0'; - if ((shell32Lib = LoadLibrary("shell32.dll"))) { - if ((SHGetSpecialFolderPathFunc = - (BOOL (__stdcall *)(HWND hwndOwner, LPTSTR lpszPath, - int nFolder, BOOL fCreate)) - GetProcAddress(shell32Lib, "SHGetSpecialFolderPath"))) { - if (!(*SHGetSpecialFolderPathFunc)(NULL, winFontDir, - CSIDL_FONTS, FALSE)) { - winFontDir[0] = '\0'; - } - } - } -#endif - for (i = 0; displayFontTab[i].name; ++i) { - fontName = new GString(displayFontTab[i].name); - fileName = NULL; - kind = displayFontT1; // make gcc happy - if (dir) { - fileName = appendToPath(new GString(dir), displayFontTab[i].t1FileName); - kind = displayFontT1; - if ((f = fopen(fileName->getCString(), "rb"))) { - fclose(f); - } else { - delete fileName; - fileName = NULL; - } - } -#ifdef WIN32 - if (!fileName && winFontDir[0] && displayFontTab[i].ttFileName) { - fileName = appendToPath(new GString(winFontDir), - displayFontTab[i].ttFileName); - kind = displayFontTT; - if ((f = fopen(fileName->getCString(), "rb"))) { - fclose(f); - } else { - delete fileName; - fileName = NULL; - } - } - // SHGetSpecialFolderPath(CSIDL_FONTS) doesn't work on Win 2k Server - // or Win2003 Server, or with older versions of shell32.dll, so check - // the "standard" directories - if (displayFontTab[i].ttFileName) { - for (j = 0; !fileName && displayFontDirs[j]; ++j) { - fileName = appendToPath(new GString(displayFontDirs[j]), - displayFontTab[i].ttFileName); - kind = displayFontTT; - if ((f = fopen(fileName->getCString(), "rb"))) { - fclose(f); - } else { - delete fileName; - fileName = NULL; - } - } - } -#else - for (j = 0; !fileName && displayFontDirs[j]; ++j) { - fileName = appendToPath(new GString(displayFontDirs[j]), - displayFontTab[i].t1FileName); - kind = displayFontT1; - if ((f = fopen(fileName->getCString(), "rb"))) { - fclose(f); - } else { - delete fileName; - fileName = NULL; - } - } -#endif - if (!fileName) { - error(-1, "No display font for '%s'", displayFontTab[i].name); - delete fontName; - continue; - } - dfp = new DisplayFontParam(fontName, kind); - dfp->t1.fileName = fileName; - globalParams->addDisplayFont(dfp); - } -} - -//------------------------------------------------------------------------ -// accessors -//------------------------------------------------------------------------ - -CharCode GlobalParams::getMacRomanCharCode(const char *charName) { - // no need to lock - macRomanReverseMap is constant - return macRomanReverseMap->lookup(charName); -} - -GString *GlobalParams::getBaseDir() { - GString *s; - - lockGlobalParams; - s = baseDir->copy(); - unlockGlobalParams; - return s; -} - -Unicode GlobalParams::mapNameToUnicode(const char *charName) { - // no need to lock - nameToUnicode is constant - return nameToUnicode->lookup(charName); -} - -UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) { - UnicodeMap *map; - - lockGlobalParams; - map = (UnicodeMap *)residentUnicodeMaps->lookup(encodingName); - unlockGlobalParams; - if (map) { - map->incRefCnt(); - } - return map; -} - -FILE *GlobalParams::getUnicodeMapFile(GString *encodingName) { - GString *fileName; - FILE *f; - - lockGlobalParams; - if ((fileName = (GString *)unicodeMaps->lookup(encodingName))) { - f = fopen(fileName->getCString(), "r"); - } else { - f = NULL; - } - unlockGlobalParams; - return f; -} - -FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) { - GList *list; - GString *dir; - GString *fileName; - FILE *f; - int i; - - lockGlobalParams; - if (!(list = (GList *)cMapDirs->lookup(collection))) { - unlockGlobalParams; - return NULL; - } - for (i = 0; i < list->getLength(); ++i) { - dir = (GString *)list->get(i); - fileName = appendToPath(dir->copy(), cMapName->getCString()); - f = fopen(fileName->getCString(), "r"); - delete fileName; - if (f) { - unlockGlobalParams; - return f; - } - } - unlockGlobalParams; - return NULL; -} - -FILE *GlobalParams::findToUnicodeFile(GString *name) { - GString *dir, *fileName; - FILE *f; - int i; - - lockGlobalParams; - for (i = 0; i < toUnicodeDirs->getLength(); ++i) { - dir = (GString *)toUnicodeDirs->get(i); - fileName = appendToPath(dir->copy(), name->getCString()); - f = fopen(fileName->getCString(), "r"); - delete fileName; - if (f) { - unlockGlobalParams; - return f; - } - } - unlockGlobalParams; - return NULL; -} - -// KPDF: parse xpdf font name into family and style -// Helvetica-BoldOblique => name=Helvetica, weight=Bold, slant=Oblique - -void parseStyle(QString& name, int& weight, int& slant, int& width) -{ - if (name.find("MS-") == 0) name = "MS " + name.remove(0,3); - - if (!name.contains('-') && !name.contains(',')) return; - QString type = name.section(QRegExp("[-,]"),-1); - name = name.section(QRegExp("[-,]"),0,-2); - if (type.contains("Oblique")) slant=FC_SLANT_OBLIQUE; - if (type.contains("Italic")) slant=FC_SLANT_ITALIC; - if (type.contains("Bold")) weight=FC_WEIGHT_BOLD; - if (type.contains("Light")) weight=FC_WEIGHT_LIGHT; - if (type.contains("Condensed")) width=FC_WIDTH_CONDENSED; -} - -DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { - DisplayFontParam *dfp; - FcPattern *p=0,*m=0; - FcChar8* s; - char * ext; - FcResult res; - - lockGlobalParams; - dfp = (DisplayFontParam *)displayFonts->lookup(fontName); - // KPDF: try to find font using Xft - if (!dfp) { - int weight=FC_WEIGHT_MEDIUM, slant=FC_SLANT_ROMAN, width=FC_WIDTH_NORMAL; - QString name(fontName->getCString()); - - parseStyle(name,weight,slant,width); - p = FcPatternBuild(0,FC_FAMILY,FcTypeString, name.ascii(), - FC_SLANT, FcTypeInteger, slant, FC_WEIGHT, FcTypeInteger, weight, - FC_WIDTH, FcTypeInteger, width, FC_LANG, FcTypeString, "xx", (char*)0); - if (!p) goto fin; - m = XftFontMatch(QX11Info::display(),QX11Info::appScreen(),p,&res); - if (!m) goto fin; - res = FcPatternGetString (m, FC_FILE, 0, &s); - if (res != FcResultMatch || !s) goto fin; - ext = rindex((char*)s,'.'); - if (!ext) goto fin; - if (!strncasecmp(ext,".ttf",4) || !strncasecmp(ext,".ttc",4)) { - dfp = new DisplayFontParam(fontName->copy(), displayFontTT); - dfp->tt.fileName = new GString((char*)s); - FcPatternGetInteger(m, FC_INDEX, 0, &(dfp->tt.faceIndex)); - } else if (!strncasecmp(ext,".pfa",4) || !strncasecmp(ext,".pfb",4)) { - dfp = new DisplayFontParam(fontName->copy(), displayFontT1); - dfp->t1.fileName = new GString((char*)s); - } else goto fin; - displayFonts->add(dfp->name,dfp); - } -fin: unlockGlobalParams; - if (m) FcPatternDestroy(m); - if (p) FcPatternDestroy(p); - return dfp; -} - -DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName, - GString *collection) { - DisplayFontParam *dfp; - - lockGlobalParams; - if (!fontName || - !(dfp = (DisplayFontParam *)displayNamedCIDFonts->lookup(fontName))) { - dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection); - } - unlockGlobalParams; - if (!dfp) dfp = getDisplayFont(fontName); - return dfp; -} - -GString *GlobalParams::getPSFile() { - GString *s; - - lockGlobalParams; - s = psFile ? psFile->copy() : (GString *)NULL; - unlockGlobalParams; - return s; -} - -int GlobalParams::getPSPaperWidth() { - int w; - - lockGlobalParams; - w = psPaperWidth; - unlockGlobalParams; - return w; -} - -int GlobalParams::getPSPaperHeight() { - int h; - - lockGlobalParams; - h = psPaperHeight; - unlockGlobalParams; - return h; -} - -void GlobalParams::getPSImageableArea(int *llx, int *lly, int *urx, int *ury) { - lockGlobalParams; - *llx = psImageableLLX; - *lly = psImageableLLY; - *urx = psImageableURX; - *ury = psImageableURY; - unlockGlobalParams; -} - -GBool GlobalParams::getPSCrop() { - GBool f; - - lockGlobalParams; - f = psCrop; - unlockGlobalParams; - return f; -} - -GBool GlobalParams::getPSExpandSmaller() { - GBool f; - - lockGlobalParams; - f = psExpandSmaller; - unlockGlobalParams; - return f; -} - -GBool GlobalParams::getPSShrinkLarger() { - GBool f; - - lockGlobalParams; - f = psShrinkLarger; - unlockGlobalParams; - return f; -} - -GBool GlobalParams::getPSCenter() { - GBool f; - - lockGlobalParams; - f = psCenter; - unlockGlobalParams; - return f; -} - -GBool GlobalParams::getPSDuplex() { - GBool d; - - lockGlobalParams; - d = psDuplex; - unlockGlobalParams; - return d; -} - -PSLevel GlobalParams::getPSLevel() { - PSLevel level; - - lockGlobalParams; - level = psLevel; - unlockGlobalParams; - return level; -} - -PSFontParam *GlobalParams::getPSFont(GString *fontName) { - PSFontParam *p; - - lockGlobalParams; - p = (PSFontParam *)psFonts->lookup(fontName); - unlockGlobalParams; - return p; -} - -PSFontParam *GlobalParams::getPSFont16(GString *fontName, - GString *collection, int wMode) { - PSFontParam *p; - int i; - - lockGlobalParams; - p = NULL; - if (fontName) { - for (i = 0; i < psNamedFonts16->getLength(); ++i) { - p = (PSFontParam *)psNamedFonts16->get(i); - if (!p->pdfFontName->cmp(fontName) && - p->wMode == wMode) { - break; - } - p = NULL; - } - } - if (!p && collection) { - for (i = 0; i < psFonts16->getLength(); ++i) { - p = (PSFontParam *)psFonts16->get(i); - if (!p->pdfFontName->cmp(collection) && - p->wMode == wMode) { - break; - } - p = NULL; - } - } - unlockGlobalParams; - return p; -} - -GBool GlobalParams::getPSEmbedType1() { - GBool e; - - lockGlobalParams; - e = psEmbedType1; - unlockGlobalParams; - return e; -} - -GBool GlobalParams::getPSEmbedTrueType() { - GBool e; - - lockGlobalParams; - e = psEmbedTrueType; - unlockGlobalParams; - return e; -} - -GBool GlobalParams::getPSEmbedCIDPostScript() { - GBool e; - - lockGlobalParams; - e = psEmbedCIDPostScript; - unlockGlobalParams; - return e; -} - -GBool GlobalParams::getPSEmbedCIDTrueType() { - GBool e; - - lockGlobalParams; - e = psEmbedCIDTrueType; - unlockGlobalParams; - return e; -} - -GBool GlobalParams::getPSOPI() { - GBool opi; - - lockGlobalParams; - opi = psOPI; - unlockGlobalParams; - return opi; -} - -GBool GlobalParams::getPSASCIIHex() { - GBool ah; - - lockGlobalParams; - ah = psASCIIHex; - unlockGlobalParams; - return ah; -} - -GString *GlobalParams::getTextEncodingName() { - GString *s; - - lockGlobalParams; - s = textEncoding->copy(); - unlockGlobalParams; - return s; -} - -EndOfLineKind GlobalParams::getTextEOL() { - EndOfLineKind eol; - - lockGlobalParams; - eol = textEOL; - unlockGlobalParams; - return eol; -} - -GBool GlobalParams::getTextPageBreaks() { - GBool pageBreaks; - - lockGlobalParams; - pageBreaks = textPageBreaks; - unlockGlobalParams; - return pageBreaks; -} - -GBool GlobalParams::getTextKeepTinyChars() { - GBool tiny; - - lockGlobalParams; - tiny = textKeepTinyChars; - unlockGlobalParams; - return tiny; -} - -GString *GlobalParams::findFontFile(GString *fontName, const char **exts) { - GString *dir, *fileName; - const char **ext; - FILE *f; - int i; - - lockGlobalParams; - for (i = 0; i < fontDirs->getLength(); ++i) { - dir = (GString *)fontDirs->get(i); - for (ext = exts; *ext; ++ext) { - fileName = appendToPath(dir->copy(), fontName->getCString()); - fileName->append(*ext); - if ((f = fopen(fileName->getCString(), "rb"))) { - fclose(f); - unlockGlobalParams; - return fileName; - } - delete fileName; - } - } - unlockGlobalParams; - return NULL; -} - -GString *GlobalParams::getInitialZoom() { - GString *s; - - lockGlobalParams; - s = initialZoom->copy(); - unlockGlobalParams; - return s; -} - -GBool GlobalParams::getContinuousView() { - GBool f; - - lockGlobalParams; - f = continuousView; - unlockGlobalParams; - return f; -} - -GBool GlobalParams::getEnableT1lib() { - GBool f; - - lockGlobalParams; - f = enableT1lib; - unlockGlobalParams; - return f; -} - -GBool GlobalParams::getEnableFreeType() { - GBool f; - - lockGlobalParams; - f = enableFreeType; - unlockGlobalParams; - return f; -} - - -GBool GlobalParams::getAntialias() { - GBool f; - - lockGlobalParams; - f = antialias; - unlockGlobalParams; - return f; -} - -GBool GlobalParams::getMapNumericCharNames() { - GBool map; - - lockGlobalParams; - map = mapNumericCharNames; - unlockGlobalParams; - return map; -} - -GBool GlobalParams::getPrintCommands() { - GBool p; - - lockGlobalParams; - p = printCommands; - unlockGlobalParams; - return p; -} - -GBool GlobalParams::getErrQuiet() { - GBool q; - - lockGlobalParams; - q = errQuiet; - unlockGlobalParams; - return q; -} - -CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) { - GString *fileName; - CharCodeToUnicode *ctu; - - lockGlobalParams; - if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(collection))) { - if ((fileName = (GString *)cidToUnicodes->lookup(collection)) && - (ctu = CharCodeToUnicode::parseCIDToUnicode(fileName, collection))) { - cidToUnicodeCache->add(ctu); - } - } - unlockGlobalParams; - return ctu; -} - -CharCodeToUnicode *GlobalParams::getUnicodeToUnicode(GString *fontName) { - CharCodeToUnicode *ctu; - GHashIter *iter; - GString *fontPattern, *fileName; - - lockGlobalParams; - fileName = NULL; - unicodeToUnicodes->startIter(&iter); - while (unicodeToUnicodes->getNext(&iter, &fontPattern, (void **)&fileName)) { - if (strstr(fontName->getCString(), fontPattern->getCString())) { - unicodeToUnicodes->killIter(&iter); - break; - } - fileName = NULL; - } - if (fileName) { - if (!(ctu = unicodeToUnicodeCache->getCharCodeToUnicode(fileName))) { - if ((ctu = CharCodeToUnicode::parseUnicodeToUnicode(fileName))) { - unicodeToUnicodeCache->add(ctu); - } - } - } else { - ctu = NULL; - } - unlockGlobalParams; - return ctu; -} - -UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) { - return getUnicodeMap2(encodingName); -} - -UnicodeMap *GlobalParams::getUnicodeMap2(GString *encodingName) { - UnicodeMap *map; - - if (!(map = getResidentUnicodeMap(encodingName))) { - lockUnicodeMapCache; - map = unicodeMapCache->getUnicodeMap(encodingName); - unlockUnicodeMapCache; - } - return map; -} - -CMap *GlobalParams::getCMap(GString *collection, GString *cMapName) { - CMap *cMap; - - lockCMapCache; - cMap = cMapCache->getCMap(collection, cMapName); - unlockCMapCache; - return cMap; -} - -UnicodeMap *GlobalParams::getTextEncoding() { - return getUnicodeMap2(textEncoding); -} - -//------------------------------------------------------------------------ -// functions to set parameters -//------------------------------------------------------------------------ - -void GlobalParams::addDisplayFont(DisplayFontParam *param) { - DisplayFontParam *old; - - lockGlobalParams; - if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) { - delete old; - } - displayFonts->add(param->name, param); - unlockGlobalParams; -} - -void GlobalParams::setPSFile(char *file) { - lockGlobalParams; - if (psFile) { - delete psFile; - } - psFile = new GString(file); - unlockGlobalParams; -} - -GBool GlobalParams::setPSPaperSize(char *size) { - lockGlobalParams; - if (!strcmp(size, "match")) { - psPaperWidth = psPaperHeight = -1; - } else if (!strcmp(size, "letter")) { - psPaperWidth = 612; - psPaperHeight = 792; - } else if (!strcmp(size, "legal")) { - psPaperWidth = 612; - psPaperHeight = 1008; - } else if (!strcmp(size, "A4")) { - psPaperWidth = 595; - psPaperHeight = 842; - } else if (!strcmp(size, "A3")) { - psPaperWidth = 842; - psPaperHeight = 1190; - } else { - unlockGlobalParams; - return gFalse; - } - psImageableLLX = psImageableLLY = 0; - psImageableURX = psPaperWidth; - psImageableURY = psPaperHeight; - unlockGlobalParams; - return gTrue; -} - -void GlobalParams::setPSPaperWidth(int width) { - lockGlobalParams; - psPaperWidth = width; - psImageableLLX = 0; - psImageableURX = psPaperWidth; - unlockGlobalParams; -} - -void GlobalParams::setPSPaperHeight(int height) { - lockGlobalParams; - psPaperHeight = height; - psImageableLLY = 0; - psImageableURY = psPaperHeight; - unlockGlobalParams; -} - -void GlobalParams::setPSImageableArea(int llx, int lly, int urx, int ury) { - lockGlobalParams; - psImageableLLX = llx; - psImageableLLY = lly; - psImageableURX = urx; - psImageableURY = ury; - unlockGlobalParams; -} - -void GlobalParams::setPSCrop(GBool crop) { - lockGlobalParams; - psCrop = crop; - unlockGlobalParams; -} - -void GlobalParams::setPSExpandSmaller(GBool expand) { - lockGlobalParams; - psExpandSmaller = expand; - unlockGlobalParams; -} - -void GlobalParams::setPSShrinkLarger(GBool shrink) { - lockGlobalParams; - psShrinkLarger = shrink; - unlockGlobalParams; -} - -void GlobalParams::setPSCenter(GBool center) { - lockGlobalParams; - psCenter = center; - unlockGlobalParams; -} - -void GlobalParams::setPSDuplex(GBool duplex) { - lockGlobalParams; - psDuplex = duplex; - unlockGlobalParams; -} - -void GlobalParams::setPSLevel(PSLevel level) { - lockGlobalParams; - psLevel = level; - unlockGlobalParams; -} - -void GlobalParams::setPSEmbedType1(GBool embed) { - lockGlobalParams; - psEmbedType1 = embed; - unlockGlobalParams; -} - -void GlobalParams::setPSEmbedTrueType(GBool embed) { - lockGlobalParams; - psEmbedTrueType = embed; - unlockGlobalParams; -} - -void GlobalParams::setPSEmbedCIDPostScript(GBool embed) { - lockGlobalParams; - psEmbedCIDPostScript = embed; - unlockGlobalParams; -} - -void GlobalParams::setPSEmbedCIDTrueType(GBool embed) { - lockGlobalParams; - psEmbedCIDTrueType = embed; - unlockGlobalParams; -} - -void GlobalParams::setPSOPI(GBool opi) { - lockGlobalParams; - psOPI = opi; - unlockGlobalParams; -} - -void GlobalParams::setPSASCIIHex(GBool hex) { - lockGlobalParams; - psASCIIHex = hex; - unlockGlobalParams; -} - -void GlobalParams::setTextEncoding(char *encodingName) { - lockGlobalParams; - delete textEncoding; - textEncoding = new GString(encodingName); - unlockGlobalParams; -} - -GBool GlobalParams::setTextEOL(char *s) { - lockGlobalParams; - if (!strcmp(s, "unix")) { - textEOL = eolUnix; - } else if (!strcmp(s, "dos")) { - textEOL = eolDOS; - } else if (!strcmp(s, "mac")) { - textEOL = eolMac; - } else { - unlockGlobalParams; - return gFalse; - } - unlockGlobalParams; - return gTrue; -} - -void GlobalParams::setTextPageBreaks(GBool pageBreaks) { - lockGlobalParams; - textPageBreaks = pageBreaks; - unlockGlobalParams; -} - -void GlobalParams::setTextKeepTinyChars(GBool keep) { - lockGlobalParams; - textKeepTinyChars = keep; - unlockGlobalParams; -} - -void GlobalParams::setInitialZoom(char *s) { - lockGlobalParams; - delete initialZoom; - initialZoom = new GString(s); - unlockGlobalParams; -} - -void GlobalParams::setContinuousView(GBool cont) { - lockGlobalParams; - continuousView = cont; - unlockGlobalParams; -} - -GBool GlobalParams::setEnableT1lib(char *s) { - GBool ok; - - lockGlobalParams; - ok = parseYesNo2(s, &enableT1lib); - unlockGlobalParams; - return ok; -} - -GBool GlobalParams::setEnableFreeType(char *s) { - GBool ok; - - lockGlobalParams; - ok = parseYesNo2(s, &enableFreeType); - unlockGlobalParams; - return ok; -} - - -GBool GlobalParams::setAntialias(char *s) { - GBool ok; - - lockGlobalParams; - ok = parseYesNo2(s, &antialias); - unlockGlobalParams; - return ok; -} - -void GlobalParams::setMapNumericCharNames(GBool map) { - lockGlobalParams; - mapNumericCharNames = map; - unlockGlobalParams; -} - -void GlobalParams::setPrintCommands(GBool printCommandsA) { - lockGlobalParams; - printCommands = printCommandsA; - unlockGlobalParams; -} - -void GlobalParams::setErrQuiet(GBool errQuietA) { - lockGlobalParams; - errQuiet = errQuietA; - unlockGlobalParams; -} - -void GlobalParams::addSecurityHandler(XpdfSecurityHandler */*handler**/) { -#ifdef ENABLE_PLUGINS - lockGlobalParams; - securityHandlers->append(handler); - unlockGlobalParams; -#endif -} - -XpdfSecurityHandler *GlobalParams::getSecurityHandler(char */*name*/) { -#ifdef ENABLE_PLUGINS - XpdfSecurityHandler *hdlr; - int i; - - lockGlobalParams; - for (i = 0; i < securityHandlers->getLength(); ++i) { - hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); - if (!stricmp(hdlr->name, name)) { - unlockGlobalParams; - return hdlr; - } - } - unlockGlobalParams; - - if (!loadPlugin("security", name)) { - return NULL; - } - - lockGlobalParams; - for (i = 0; i < securityHandlers->getLength(); ++i) { - hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); - if (!strcmp(hdlr->name, name)) { - unlockGlobalParams; - return hdlr; - } - } - unlockGlobalParams; -#endif - - return NULL; -} - -#ifdef ENABLE_PLUGINS -//------------------------------------------------------------------------ -// plugins -//------------------------------------------------------------------------ - -GBool GlobalParams::loadPlugin(char *type, char *name) { - Plugin *plugin; - - if (!(plugin = Plugin::load(type, name))) { - return gFalse; - } - lockGlobalParams; - plugins->append(plugin); - unlockGlobalParams; - return gTrue; -} - -#endif // ENABLE_PLUGINS diff --git a/xpdf/xpdf/GlobalParams.h b/xpdf/xpdf/GlobalParams.h deleted file mode 100644 index 31be7b71d..000000000 --- a/xpdf/xpdf/GlobalParams.h +++ /dev/null @@ -1,337 +0,0 @@ -//======================================================================== -// -// GlobalParams.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef GLOBALPARAMS_H -#define GLOBALPARAMS_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include "gtypes.h" -#include "CharTypes.h" - -#if MULTITHREADED -#include "GMutex.h" -#endif - -class GString; -class GList; -class GHash; -class NameToCharCode; -class CharCodeToUnicode; -class CharCodeToUnicodeCache; -class UnicodeMap; -class UnicodeMapCache; -class CMap; -class CMapCache; -struct XpdfSecurityHandler; -class GlobalParams; - -//------------------------------------------------------------------------ - -// The global parameters object. -extern GlobalParams *globalParams; - -//------------------------------------------------------------------------ - -enum DisplayFontParamKind { - displayFontT1, - displayFontTT -}; - -struct DisplayFontParamT1 { - GString *fileName; -}; - -struct DisplayFontParamTT { - GString *fileName; - int faceIndex; -}; - -class DisplayFontParam { -public: - - GString *name; // font name for 8-bit fonts and named - // CID fonts; collection name for - // generic CID fonts - DisplayFontParamKind kind; - union { - DisplayFontParamT1 t1; - DisplayFontParamTT tt; - }; - - DisplayFontParam(GString *nameA, DisplayFontParamKind kindA); - ~DisplayFontParam(); -}; - -//------------------------------------------------------------------------ - -class PSFontParam { -public: - - GString *pdfFontName; // PDF font name for 8-bit fonts and - // named 16-bit fonts; char collection - // name for generic 16-bit fonts - int wMode; // writing mode (0=horiz, 1=vert) for - // 16-bit fonts - GString *psFontName; // PostScript font name - GString *encoding; // encoding, for 16-bit fonts only - - PSFontParam(GString *pdfFontNameA, int wModeA, - GString *psFontNameA, GString *encodingA); - ~PSFontParam(); -}; - -//------------------------------------------------------------------------ - -enum PSLevel { - psLevel1, - psLevel1Sep, - psLevel2, - psLevel2Sep, - psLevel3, - psLevel3Sep -}; - -//------------------------------------------------------------------------ - -enum EndOfLineKind { - eolUnix, // LF - eolDOS, // CR+LF - eolMac // CR -}; - -//------------------------------------------------------------------------ - -class GlobalParams { -public: - - // Initialize the global parameters by attempting to read a config - // file. - GlobalParams(const char *cfgFileName); - - ~GlobalParams(); - - void setBaseDir(char *dir); - void setupBaseFonts(char *dir); - - //----- accessors - - CharCode getMacRomanCharCode(const char *charName); - - GString *getBaseDir(); - Unicode mapNameToUnicode(const char *charName); - UnicodeMap *getResidentUnicodeMap(GString *encodingName); - FILE *getUnicodeMapFile(GString *encodingName); - FILE *findCMapFile(GString *collection, GString *cMapName); - FILE *findToUnicodeFile(GString *name); - DisplayFontParam *getDisplayFont(GString *fontName); - DisplayFontParam *getDisplayCIDFont(GString *fontName, GString *collection); - GString *getPSFile(); - int getPSPaperWidth(); - int getPSPaperHeight(); - void getPSImageableArea(int *llx, int *lly, int *urx, int *ury); - GBool getPSDuplex(); - GBool getPSCrop(); - GBool getPSExpandSmaller(); - GBool getPSShrinkLarger(); - GBool getPSCenter(); - PSLevel getPSLevel(); - PSFontParam *getPSFont(GString *fontName); - PSFontParam *getPSFont16(GString *fontName, GString *collection, int wMode); - GBool getPSEmbedType1(); - GBool getPSEmbedTrueType(); - GBool getPSEmbedCIDPostScript(); - GBool getPSEmbedCIDTrueType(); - GBool getPSOPI(); - GBool getPSASCIIHex(); - GString *getTextEncodingName(); - EndOfLineKind getTextEOL(); - GBool getTextPageBreaks(); - GBool getTextKeepTinyChars(); - GString *findFontFile(GString *fontName, const char **exts); - GString *getInitialZoom(); - GBool getContinuousView(); - GBool getEnableT1lib(); - GBool getEnableFreeType(); - GBool getAntialias(); - GString *getURLCommand() { return urlCommand; } - GString *getMovieCommand() { return movieCommand; } - GBool getMapNumericCharNames(); - GBool getPrintCommands(); - GBool getErrQuiet(); - - CharCodeToUnicode *getCIDToUnicode(GString *collection); - CharCodeToUnicode *getUnicodeToUnicode(GString *fontName); - UnicodeMap *getUnicodeMap(GString *encodingName); - CMap *getCMap(GString *collection, GString *cMapName); - UnicodeMap *getTextEncoding(); - - //----- functions to set parameters - - void addDisplayFont(DisplayFontParam *param); - void setPSFile(char *file); - GBool setPSPaperSize(char *size); - void setPSPaperWidth(int width); - void setPSPaperHeight(int height); - void setPSImageableArea(int llx, int lly, int urx, int ury); - void setPSDuplex(GBool duplex); - void setPSCrop(GBool crop); - void setPSExpandSmaller(GBool expand); - void setPSShrinkLarger(GBool shrink); - void setPSCenter(GBool center); - void setPSLevel(PSLevel level); - void setPSEmbedType1(GBool embed); - void setPSEmbedTrueType(GBool embed); - void setPSEmbedCIDPostScript(GBool embed); - void setPSEmbedCIDTrueType(GBool embed); - void setPSOPI(GBool opi); - void setPSASCIIHex(GBool hex); - void setTextEncoding(char *encodingName); - GBool setTextEOL(char *s); - void setTextPageBreaks(GBool pageBreaks); - void setTextKeepTinyChars(GBool keep); - void setInitialZoom(char *s); - void setContinuousView(GBool cont); - GBool setEnableT1lib(char *s); - GBool setEnableFreeType(char *s); - GBool setAntialias(char *s); - void setMapNumericCharNames(GBool map); - void setPrintCommands(GBool printCommandsA); - void setErrQuiet(GBool errQuietA); - - //----- security handlers - - void addSecurityHandler(XpdfSecurityHandler *handler); - XpdfSecurityHandler *getSecurityHandler(char *name); - -private: - - void parseFile(GString *fileName, FILE *f); - void parseNameToUnicode(GList *tokens, GString *fileName, int line); - void parseCIDToUnicode(GList *tokens, GString *fileName, int line); - void parseUnicodeToUnicode(GList *tokens, GString *fileName, int line); - void parseUnicodeMap(GList *tokens, GString *fileName, int line); - void parseCMapDir(GList *tokens, GString *fileName, int line); - void parseToUnicodeDir(GList *tokens, GString *fileName, int line); - void parseDisplayFont(GList *tokens, GHash *fontHash, - DisplayFontParamKind kind, - GString *fileName, int line); - void parsePSFile(GList *tokens, GString *fileName, int line); - void parsePSPaperSize(GList *tokens, GString *fileName, int line); - void parsePSImageableArea(GList *tokens, GString *fileName, int line); - void parsePSLevel(GList *tokens, GString *fileName, int line); - void parsePSFont(GList *tokens, GString *fileName, int line); - void parsePSFont16(const char *cmdName, GList *fontList, - GList *tokens, GString *fileName, int line); - void parseTextEncoding(GList *tokens, GString *fileName, int line); - void parseTextEOL(GList *tokens, GString *fileName, int line); - void parseFontDir(GList *tokens, GString *fileName, int line); - void parseInitialZoom(GList *tokens, GString *fileName, int line); - void parseCommand(const char *cmdName, GString **val, - GList *tokens, GString *fileName, int line); - void parseYesNo(const char *cmdName, GBool *flag, - GList *tokens, GString *fileName, int line); - GBool parseYesNo2(char *token, GBool *flag); - UnicodeMap *getUnicodeMap2(GString *encodingName); -#ifdef ENABLE_PLUGINS - GBool loadPlugin(char *type, char *name); -#endif - - //----- static tables - - NameToCharCode * // mapping from char name to - macRomanReverseMap; // MacRomanEncoding index - - //----- user-modifiable settings - - GString *baseDir; // base directory - for plugins, etc. - NameToCharCode * // mapping from char name to Unicode - nameToUnicode; - GHash *cidToUnicodes; // files for mappings from char collections - // to Unicode, indexed by collection name - // [GString] - GHash *unicodeToUnicodes; // files for Unicode-to-Unicode mappings, - // indexed by font name pattern [GString] - GHash *residentUnicodeMaps; // mappings from Unicode to char codes, - // indexed by encoding name [UnicodeMap] - GHash *unicodeMaps; // files for mappings from Unicode to char - // codes, indexed by encoding name [GString] - GHash *cMapDirs; // list of CMap dirs, indexed by collection - // name [GList[GString]] - GList *toUnicodeDirs; // list of ToUnicode CMap dirs [GString] - GHash *displayFonts; // display font info, indexed by font name - // [DisplayFontParam] - GHash *displayCIDFonts; // display CID font info, indexed by - // collection [DisplayFontParam] - GHash *displayNamedCIDFonts; // display CID font info, indexed by - // font name [DisplayFontParam] - GString *psFile; // PostScript file or command (for xpdf) - int psPaperWidth; // paper size, in PostScript points, for - int psPaperHeight; // PostScript output - int psImageableLLX, // imageable area, in PostScript points, - psImageableLLY, // for PostScript output - psImageableURX, - psImageableURY; - GBool psCrop; // crop PS output to CropBox - GBool psExpandSmaller; // expand smaller pages to fill paper - GBool psShrinkLarger; // shrink larger pages to fit paper - GBool psCenter; // center pages on the paper - GBool psDuplex; // enable duplexing in PostScript? - PSLevel psLevel; // PostScript level to generate - GHash *psFonts; // PostScript font info, indexed by PDF - // font name [PSFontParam] - GList *psNamedFonts16; // named 16-bit fonts [PSFontParam] - GList *psFonts16; // generic 16-bit fonts [PSFontParam] - GBool psEmbedType1; // embed Type 1 fonts? - GBool psEmbedTrueType; // embed TrueType fonts? - GBool psEmbedCIDPostScript; // embed CID PostScript fonts? - GBool psEmbedCIDTrueType; // embed CID TrueType fonts? - GBool psOPI; // generate PostScript OPI comments? - GBool psASCIIHex; // use ASCIIHex instead of ASCII85? - GString *textEncoding; // encoding (unicodeMap) to use for text - // output - EndOfLineKind textEOL; // type of EOL marker to use for text - // output - GBool textPageBreaks; // insert end-of-page markers? - GBool textKeepTinyChars; // keep all characters in text output - GList *fontDirs; // list of font dirs [GString] - GString *initialZoom; // initial zoom level - GBool continuousView; // continuous view mode - GBool enableT1lib; // t1lib enable flag - GBool enableFreeType; // FreeType enable flag - GBool antialias; // anti-aliasing enable flag - GString *urlCommand; // command executed for URL links - GString *movieCommand; // command executed for movie annotations - GBool mapNumericCharNames; // map numeric char names (from font subsets)? - GBool printCommands; // print the drawing commands - GBool errQuiet; // suppress error messages? - - CharCodeToUnicodeCache *cidToUnicodeCache; - CharCodeToUnicodeCache *unicodeToUnicodeCache; - UnicodeMapCache *unicodeMapCache; - CMapCache *cMapCache; - -#ifdef ENABLE_PLUGINS - GList *plugins; // list of plugins [Plugin] - GList *securityHandlers; // list of loaded security handlers - // [XpdfSecurityHandler] -#endif - -#if MULTITHREADED - GMutex mutex; - GMutex unicodeMapCacheMutex; - GMutex cMapCacheMutex; -#endif -}; - -#endif diff --git a/xpdf/xpdf/JArithmeticDecoder.cc b/xpdf/xpdf/JArithmeticDecoder.cc deleted file mode 100644 index 93d6b9cf1..000000000 --- a/xpdf/xpdf/JArithmeticDecoder.cc +++ /dev/null @@ -1,322 +0,0 @@ -//======================================================================== -// -// JArithmeticDecoder.cc -// -// Copyright 2002-2004 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "Object.h" -#include "Stream.h" -#include "JArithmeticDecoder.h" - -//------------------------------------------------------------------------ -// JArithmeticDecoderStates -//------------------------------------------------------------------------ - -JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) { - contextSize = contextSizeA; - cxTab = (Guchar *)gmallocn(contextSize, sizeof(Guchar)); - reset(); -} - -JArithmeticDecoderStats::~JArithmeticDecoderStats() { - gfree(cxTab); -} - -JArithmeticDecoderStats *JArithmeticDecoderStats::copy() { - JArithmeticDecoderStats *stats; - - stats = new JArithmeticDecoderStats(contextSize); - memcpy(stats->cxTab, cxTab, contextSize); - return stats; -} - -void JArithmeticDecoderStats::reset() { - memset(cxTab, 0, contextSize); -} - -void JArithmeticDecoderStats::copyFrom(JArithmeticDecoderStats *stats) { - memcpy(cxTab, stats->cxTab, contextSize); -} - -void JArithmeticDecoderStats::setEntry(Guint cx, int i, int mps) { - cxTab[cx] = (i << 1) + mps; -} - -//------------------------------------------------------------------------ -// JArithmeticDecoder -//------------------------------------------------------------------------ - -Guint JArithmeticDecoder::qeTab[47] = { - 0x56010000, 0x34010000, 0x18010000, 0x0AC10000, - 0x05210000, 0x02210000, 0x56010000, 0x54010000, - 0x48010000, 0x38010000, 0x30010000, 0x24010000, - 0x1C010000, 0x16010000, 0x56010000, 0x54010000, - 0x51010000, 0x48010000, 0x38010000, 0x34010000, - 0x30010000, 0x28010000, 0x24010000, 0x22010000, - 0x1C010000, 0x18010000, 0x16010000, 0x14010000, - 0x12010000, 0x11010000, 0x0AC10000, 0x09C10000, - 0x08A10000, 0x05210000, 0x04410000, 0x02A10000, - 0x02210000, 0x01410000, 0x01110000, 0x00850000, - 0x00490000, 0x00250000, 0x00150000, 0x00090000, - 0x00050000, 0x00010000, 0x56010000 -}; - -int JArithmeticDecoder::nmpsTab[47] = { - 1, 2, 3, 4, 5, 38, 7, 8, 9, 10, 11, 12, 13, 29, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46 -}; - -int JArithmeticDecoder::nlpsTab[47] = { - 1, 6, 9, 12, 29, 33, 6, 14, 14, 14, 17, 18, 20, 21, 14, 14, - 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46 -}; - -int JArithmeticDecoder::switchTab[47] = { - 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -JArithmeticDecoder::JArithmeticDecoder() { - str = NULL; - dataLen = 0; - limitStream = gFalse; -} - -inline Guint JArithmeticDecoder::readByte() { - if (limitStream) { - --dataLen; - if (dataLen < 0) { - return 0xff; - } - } - return (Guint)str->getChar() & 0xff; -} - -JArithmeticDecoder::~JArithmeticDecoder() { - cleanup(); -} - -void JArithmeticDecoder::start() { - buf0 = readByte(); - buf1 = readByte(); - - // INITDEC - c = (buf0 ^ 0xff) << 16; - byteIn(); - c <<= 7; - ct -= 7; - a = 0x80000000; -} - -void JArithmeticDecoder::restart(int dataLenA) { - int oldDataLen; - - oldDataLen = dataLen; - dataLen = dataLenA; - if (oldDataLen == -1) { - buf1 = readByte(); - } else if (oldDataLen <= -2) { - buf0 = readByte(); - buf1 = readByte(); - } -} - -void JArithmeticDecoder::cleanup() { - if (limitStream) { - while (dataLen > 0) { - buf0 = buf1; - buf1 = readByte(); - } - } -} - -int JArithmeticDecoder::decodeBit(Guint context, - JArithmeticDecoderStats *stats) { - int bit; - Guint qe; - int iCX, mpsCX; - - iCX = stats->cxTab[context] >> 1; - mpsCX = stats->cxTab[context] & 1; - qe = qeTab[iCX]; - a -= qe; - if (c < a) { - if (a & 0x80000000) { - bit = mpsCX; - } else { - // MPS_EXCHANGE - if (a < qe) { - bit = 1 - mpsCX; - if (switchTab[iCX]) { - stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX); - } else { - stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX; - } - } else { - bit = mpsCX; - stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX; - } - // RENORMD - do { - if (ct == 0) { - byteIn(); - } - a <<= 1; - c <<= 1; - --ct; - } while (!(a & 0x80000000)); - } - } else { - c -= a; - // LPS_EXCHANGE - if (a < qe) { - bit = mpsCX; - stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX; - } else { - bit = 1 - mpsCX; - if (switchTab[iCX]) { - stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX); - } else { - stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX; - } - } - a = qe; - // RENORMD - do { - if (ct == 0) { - byteIn(); - } - a <<= 1; - c <<= 1; - --ct; - } while (!(a & 0x80000000)); - } - return bit; -} - -int JArithmeticDecoder::decodeByte(Guint context, - JArithmeticDecoderStats *stats) { - int byte; - int i; - - byte = 0; - for (i = 0; i < 8; ++i) { - byte = (byte << 1) | decodeBit(context, stats); - } - return byte; -} - -GBool JArithmeticDecoder::decodeInt(int *x, JArithmeticDecoderStats *stats) { - int s; - Guint v; - int i; - - prev = 1; - s = decodeIntBit(stats); - if (decodeIntBit(stats)) { - if (decodeIntBit(stats)) { - if (decodeIntBit(stats)) { - if (decodeIntBit(stats)) { - if (decodeIntBit(stats)) { - v = 0; - for (i = 0; i < 32; ++i) { - v = (v << 1) | decodeIntBit(stats); - } - v += 4436; - } else { - v = 0; - for (i = 0; i < 12; ++i) { - v = (v << 1) | decodeIntBit(stats); - } - v += 340; - } - } else { - v = 0; - for (i = 0; i < 8; ++i) { - v = (v << 1) | decodeIntBit(stats); - } - v += 84; - } - } else { - v = 0; - for (i = 0; i < 6; ++i) { - v = (v << 1) | decodeIntBit(stats); - } - v += 20; - } - } else { - v = decodeIntBit(stats); - v = (v << 1) | decodeIntBit(stats); - v = (v << 1) | decodeIntBit(stats); - v = (v << 1) | decodeIntBit(stats); - v += 4; - } - } else { - v = decodeIntBit(stats); - v = (v << 1) | decodeIntBit(stats); - } - - if (s) { - if (v == 0) { - return gFalse; - } - *x = -(int)v; - } else { - *x = (int)v; - } - return gTrue; -} - -int JArithmeticDecoder::decodeIntBit(JArithmeticDecoderStats *stats) { - int bit; - - bit = decodeBit(prev, stats); - if (prev < 0x100) { - prev = (prev << 1) | bit; - } else { - prev = (((prev << 1) | bit) & 0x1ff) | 0x100; - } - return bit; -} - -Guint JArithmeticDecoder::decodeIAID(Guint codeLen, - JArithmeticDecoderStats *stats) { - Guint i; - int bit; - - prev = 1; - for (i = 0; i < codeLen; ++i) { - bit = decodeBit(prev, stats); - prev = (prev << 1) | bit; - } - return prev - (1 << codeLen); -} - -void JArithmeticDecoder::byteIn() { - if (buf0 == 0xff) { - if (buf1 > 0x8f) { - ct = 8; - } else { - buf0 = buf1; - buf1 = readByte(); - c = c + 0xfe00 - (buf0 << 9); - ct = 7; - } - } else { - buf0 = buf1; - buf1 = readByte(); - c = c + 0xff00 - (buf0 << 8); - ct = 8; - } -} diff --git a/xpdf/xpdf/JArithmeticDecoder.h b/xpdf/xpdf/JArithmeticDecoder.h deleted file mode 100644 index a40823ddb..000000000 --- a/xpdf/xpdf/JArithmeticDecoder.h +++ /dev/null @@ -1,109 +0,0 @@ -//======================================================================== -// -// JArithmeticDecoder.h -// -// Arithmetic decoder used by the JBIG2 and JPEG2000 decoders. -// -// Copyright 2002-2004 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef JARITHMETICDECODER_H -#define JARITHMETICDECODER_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -class Stream; - -//------------------------------------------------------------------------ -// JArithmeticDecoderStats -//------------------------------------------------------------------------ - -class JArithmeticDecoderStats { -public: - - JArithmeticDecoderStats(int contextSizeA); - ~JArithmeticDecoderStats(); - JArithmeticDecoderStats *copy(); - void reset(); - int getContextSize() { return contextSize; } - void copyFrom(JArithmeticDecoderStats *stats); - void setEntry(Guint cx, int i, int mps); - -private: - - Guchar *cxTab; // cxTab[cx] = (i[cx] << 1) + mps[cx] - int contextSize; - - friend class JArithmeticDecoder; -}; - -//------------------------------------------------------------------------ -// JArithmeticDecoder -//------------------------------------------------------------------------ - -class JArithmeticDecoder { -public: - - JArithmeticDecoder(); - ~JArithmeticDecoder(); - - void setStream(Stream *strA) - { str = strA; dataLen = 0; limitStream = gFalse; } - void setStream(Stream *strA, int dataLenA) - { str = strA; dataLen = dataLenA; limitStream = gTrue; } - - // Start decoding on a new stream. This fills the byte buffers and - // runs INITDEC. - void start(); - - // Restart decoding on an interrupted stream. This refills the - // buffers if needed, but does not run INITDEC. (This is used in - // JPEG 2000 streams when codeblock data is split across multiple - // packets/layers.) - void restart(int dataLenA); - - // Read any leftover data in the stream. - void cleanup(); - - // Decode one bit. - int decodeBit(Guint context, JArithmeticDecoderStats *stats); - - // Decode eight bits. - int decodeByte(Guint context, JArithmeticDecoderStats *stats); - - // Returns false for OOB, otherwise sets * and returns true. - GBool decodeInt(int *x, JArithmeticDecoderStats *stats); - - Guint decodeIAID(Guint codeLen, - JArithmeticDecoderStats *stats); - -private: - - Guint readByte(); - int decodeIntBit(JArithmeticDecoderStats *stats); - void byteIn(); - - static Guint qeTab[47]; - static int nmpsTab[47]; - static int nlpsTab[47]; - static int switchTab[47]; - - Guint buf0, buf1; - Guint c, a; - int ct; - - Guint prev; // for the integer decoder - - Stream *str; - int dataLen; - GBool limitStream; -}; - -#endif diff --git a/xpdf/xpdf/JBIG2Stream.cc b/xpdf/xpdf/JBIG2Stream.cc deleted file mode 100644 index 9354d69a3..000000000 --- a/xpdf/xpdf/JBIG2Stream.cc +++ /dev/null @@ -1,3411 +0,0 @@ -//======================================================================== -// -// JBIG2Stream.cc -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "GList.h" -#include "Error.h" -#include "JArithmeticDecoder.h" -#include "JBIG2Stream.h" - -//~ share these tables -#include "Stream-CCITT.h" - -//------------------------------------------------------------------------ - -static int contextSize[4] = { 16, 13, 10, 10 }; -static int refContextSize[2] = { 13, 10 }; - -//------------------------------------------------------------------------ -// JBIG2HuffmanTable -//------------------------------------------------------------------------ - -#define jbig2HuffmanLOW 0xfffffffd -#define jbig2HuffmanOOB 0xfffffffe -#define jbig2HuffmanEOT 0xffffffff - -struct JBIG2HuffmanTable { - int val; - Guint prefixLen; - Guint rangeLen; // can also be LOW, OOB, or EOT - Guint prefix; -}; - -JBIG2HuffmanTable huffTableA[] = { - { 0, 1, 4, 0x000 }, - { 16, 2, 8, 0x002 }, - { 272, 3, 16, 0x006 }, - { 65808, 3, 32, 0x007 }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableB[] = { - { 0, 1, 0, 0x000 }, - { 1, 2, 0, 0x002 }, - { 2, 3, 0, 0x006 }, - { 3, 4, 3, 0x00e }, - { 11, 5, 6, 0x01e }, - { 75, 6, 32, 0x03e }, - { 0, 6, jbig2HuffmanOOB, 0x03f }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableC[] = { - { 0, 1, 0, 0x000 }, - { 1, 2, 0, 0x002 }, - { 2, 3, 0, 0x006 }, - { 3, 4, 3, 0x00e }, - { 11, 5, 6, 0x01e }, - { 0, 6, jbig2HuffmanOOB, 0x03e }, - { 75, 7, 32, 0x0fe }, - { -256, 8, 8, 0x0fe }, - { -257, 8, jbig2HuffmanLOW, 0x0ff }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableD[] = { - { 1, 1, 0, 0x000 }, - { 2, 2, 0, 0x002 }, - { 3, 3, 0, 0x006 }, - { 4, 4, 3, 0x00e }, - { 12, 5, 6, 0x01e }, - { 76, 5, 32, 0x01f }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableE[] = { - { 1, 1, 0, 0x000 }, - { 2, 2, 0, 0x002 }, - { 3, 3, 0, 0x006 }, - { 4, 4, 3, 0x00e }, - { 12, 5, 6, 0x01e }, - { 76, 6, 32, 0x03e }, - { -255, 7, 8, 0x07e }, - { -256, 7, jbig2HuffmanLOW, 0x07f }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableF[] = { - { 0, 2, 7, 0x000 }, - { 128, 3, 7, 0x002 }, - { 256, 3, 8, 0x003 }, - { -1024, 4, 9, 0x008 }, - { -512, 4, 8, 0x009 }, - { -256, 4, 7, 0x00a }, - { -32, 4, 5, 0x00b }, - { 512, 4, 9, 0x00c }, - { 1024, 4, 10, 0x00d }, - { -2048, 5, 10, 0x01c }, - { -128, 5, 6, 0x01d }, - { -64, 5, 5, 0x01e }, - { -2049, 6, jbig2HuffmanLOW, 0x03e }, - { 2048, 6, 32, 0x03f }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableG[] = { - { -512, 3, 8, 0x000 }, - { 256, 3, 8, 0x001 }, - { 512, 3, 9, 0x002 }, - { 1024, 3, 10, 0x003 }, - { -1024, 4, 9, 0x008 }, - { -256, 4, 7, 0x009 }, - { -32, 4, 5, 0x00a }, - { 0, 4, 5, 0x00b }, - { 128, 4, 7, 0x00c }, - { -128, 5, 6, 0x01a }, - { -64, 5, 5, 0x01b }, - { 32, 5, 5, 0x01c }, - { 64, 5, 6, 0x01d }, - { -1025, 5, jbig2HuffmanLOW, 0x01e }, - { 2048, 5, 32, 0x01f }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableH[] = { - { 0, 2, 1, 0x000 }, - { 0, 2, jbig2HuffmanOOB, 0x001 }, - { 4, 3, 4, 0x004 }, - { -1, 4, 0, 0x00a }, - { 22, 4, 4, 0x00b }, - { 38, 4, 5, 0x00c }, - { 2, 5, 0, 0x01a }, - { 70, 5, 6, 0x01b }, - { 134, 5, 7, 0x01c }, - { 3, 6, 0, 0x03a }, - { 20, 6, 1, 0x03b }, - { 262, 6, 7, 0x03c }, - { 646, 6, 10, 0x03d }, - { -2, 7, 0, 0x07c }, - { 390, 7, 8, 0x07d }, - { -15, 8, 3, 0x0fc }, - { -5, 8, 1, 0x0fd }, - { -7, 9, 1, 0x1fc }, - { -3, 9, 0, 0x1fd }, - { -16, 9, jbig2HuffmanLOW, 0x1fe }, - { 1670, 9, 32, 0x1ff }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableI[] = { - { 0, 2, jbig2HuffmanOOB, 0x000 }, - { -1, 3, 1, 0x002 }, - { 1, 3, 1, 0x003 }, - { 7, 3, 5, 0x004 }, - { -3, 4, 1, 0x00a }, - { 43, 4, 5, 0x00b }, - { 75, 4, 6, 0x00c }, - { 3, 5, 1, 0x01a }, - { 139, 5, 7, 0x01b }, - { 267, 5, 8, 0x01c }, - { 5, 6, 1, 0x03a }, - { 39, 6, 2, 0x03b }, - { 523, 6, 8, 0x03c }, - { 1291, 6, 11, 0x03d }, - { -5, 7, 1, 0x07c }, - { 779, 7, 9, 0x07d }, - { -31, 8, 4, 0x0fc }, - { -11, 8, 2, 0x0fd }, - { -15, 9, 2, 0x1fc }, - { -7, 9, 1, 0x1fd }, - { -32, 9, jbig2HuffmanLOW, 0x1fe }, - { 3339, 9, 32, 0x1ff }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableJ[] = { - { -2, 2, 2, 0x000 }, - { 6, 2, 6, 0x001 }, - { 0, 2, jbig2HuffmanOOB, 0x002 }, - { -3, 5, 0, 0x018 }, - { 2, 5, 0, 0x019 }, - { 70, 5, 5, 0x01a }, - { 3, 6, 0, 0x036 }, - { 102, 6, 5, 0x037 }, - { 134, 6, 6, 0x038 }, - { 198, 6, 7, 0x039 }, - { 326, 6, 8, 0x03a }, - { 582, 6, 9, 0x03b }, - { 1094, 6, 10, 0x03c }, - { -21, 7, 4, 0x07a }, - { -4, 7, 0, 0x07b }, - { 4, 7, 0, 0x07c }, - { 2118, 7, 11, 0x07d }, - { -5, 8, 0, 0x0fc }, - { 5, 8, 0, 0x0fd }, - { -22, 8, jbig2HuffmanLOW, 0x0fe }, - { 4166, 8, 32, 0x0ff }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableK[] = { - { 1, 1, 0, 0x000 }, - { 2, 2, 1, 0x002 }, - { 4, 4, 0, 0x00c }, - { 5, 4, 1, 0x00d }, - { 7, 5, 1, 0x01c }, - { 9, 5, 2, 0x01d }, - { 13, 6, 2, 0x03c }, - { 17, 7, 2, 0x07a }, - { 21, 7, 3, 0x07b }, - { 29, 7, 4, 0x07c }, - { 45, 7, 5, 0x07d }, - { 77, 7, 6, 0x07e }, - { 141, 7, 32, 0x07f }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableL[] = { - { 1, 1, 0, 0x000 }, - { 2, 2, 0, 0x002 }, - { 3, 3, 1, 0x006 }, - { 5, 5, 0, 0x01c }, - { 6, 5, 1, 0x01d }, - { 8, 6, 1, 0x03c }, - { 10, 7, 0, 0x07a }, - { 11, 7, 1, 0x07b }, - { 13, 7, 2, 0x07c }, - { 17, 7, 3, 0x07d }, - { 25, 7, 4, 0x07e }, - { 41, 8, 5, 0x0fe }, - { 73, 8, 32, 0x0ff }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableM[] = { - { 1, 1, 0, 0x000 }, - { 2, 3, 0, 0x004 }, - { 7, 3, 3, 0x005 }, - { 3, 4, 0, 0x00c }, - { 5, 4, 1, 0x00d }, - { 4, 5, 0, 0x01c }, - { 15, 6, 1, 0x03a }, - { 17, 6, 2, 0x03b }, - { 21, 6, 3, 0x03c }, - { 29, 6, 4, 0x03d }, - { 45, 6, 5, 0x03e }, - { 77, 7, 6, 0x07e }, - { 141, 7, 32, 0x07f }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableN[] = { - { 0, 1, 0, 0x000 }, - { -2, 3, 0, 0x004 }, - { -1, 3, 0, 0x005 }, - { 1, 3, 0, 0x006 }, - { 2, 3, 0, 0x007 }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -JBIG2HuffmanTable huffTableO[] = { - { 0, 1, 0, 0x000 }, - { -1, 3, 0, 0x004 }, - { 1, 3, 0, 0x005 }, - { -2, 4, 0, 0x00c }, - { 2, 4, 0, 0x00d }, - { -4, 5, 1, 0x01c }, - { 3, 5, 1, 0x01d }, - { -8, 6, 2, 0x03c }, - { 5, 6, 2, 0x03d }, - { -24, 7, 4, 0x07c }, - { 9, 7, 4, 0x07d }, - { -25, 7, jbig2HuffmanLOW, 0x07e }, - { 25, 7, 32, 0x07f }, - { 0, 0, jbig2HuffmanEOT, 0 } -}; - -//------------------------------------------------------------------------ -// JBIG2HuffmanDecoder -//------------------------------------------------------------------------ - -class JBIG2HuffmanDecoder { -public: - - JBIG2HuffmanDecoder(); - ~JBIG2HuffmanDecoder(); - void setStream(Stream *strA) { str = strA; } - - void reset(); - - // Returns false for OOB, otherwise sets * and returns true. - GBool decodeInt(int *x, JBIG2HuffmanTable *table); - - Guint readBits(Guint n); - Guint readBit(); - - // Sort the table by prefix length and assign prefix values. - void buildTable(JBIG2HuffmanTable *table, Guint len); - -private: - - Stream *str; - Guint buf; - Guint bufLen; -}; - -JBIG2HuffmanDecoder::JBIG2HuffmanDecoder() { - str = NULL; - reset(); -} - -JBIG2HuffmanDecoder::~JBIG2HuffmanDecoder() { -} - -void JBIG2HuffmanDecoder::reset() { - buf = 0; - bufLen = 0; -} - -//~ optimize this -GBool JBIG2HuffmanDecoder::decodeInt(int *x, JBIG2HuffmanTable *table) { - Guint i, len, prefix; - - i = 0; - len = 0; - prefix = 0; - while (table[i].rangeLen != jbig2HuffmanEOT) { - while (len < table[i].prefixLen) { - prefix = (prefix << 1) | readBit(); - ++len; - } - if (prefix == table[i].prefix) { - if (table[i].rangeLen == jbig2HuffmanOOB) { - return gFalse; - } - if (table[i].rangeLen == jbig2HuffmanLOW) { - *x = table[i].val - readBits(32); - } else if (table[i].rangeLen > 0) { - *x = table[i].val + readBits(table[i].rangeLen); - } else { - *x = table[i].val; - } - return gTrue; - } - ++i; - } - return gFalse; -} - -Guint JBIG2HuffmanDecoder::readBits(Guint n) { - Guint x, mask, nLeft; - - mask = (n == 32) ? 0xffffffff : ((1 << n) - 1); - if (bufLen >= n) { - x = (buf >> (bufLen - n)) & mask; - bufLen -= n; - } else { - x = buf & ((1 << bufLen) - 1); - nLeft = n - bufLen; - bufLen = 0; - while (nLeft >= 8) { - x = (x << 8) | (str->getChar() & 0xff); - nLeft -= 8; - } - if (nLeft > 0) { - buf = str->getChar(); - bufLen = 8 - nLeft; - x = (x << nLeft) | ((buf >> bufLen) & ((1 << nLeft) - 1)); - } - } - return x; -} - -Guint JBIG2HuffmanDecoder::readBit() { - if (bufLen == 0) { - buf = str->getChar(); - bufLen = 8; - } - --bufLen; - return (buf >> bufLen) & 1; -} - -void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) { - Guint i, j, k, prefix; - JBIG2HuffmanTable tab; - - // stable selection sort: - // - entries with prefixLen > 0, in ascending prefixLen order - // - entry with prefixLen = 0, rangeLen = EOT - // - all other entries with prefixLen = 0 - // (on entry, table[len] has prefixLen = 0, rangeLen = EOT) - for (i = 0; i < len; ++i) { - for (j = i; j < len && table[j].prefixLen == 0; ++j) ; - if (j == len) { - break; - } - for (k = j + 1; k < len; ++k) { - if (table[k].prefixLen > 0 && - table[k].prefixLen < table[j].prefixLen) { - j = k; - } - } - if (j != i) { - tab = table[j]; - for (k = j; k > i; --k) { - table[k] = table[k - 1]; - } - table[i] = tab; - } - } - table[i] = table[len]; - - // assign prefixes - i = 0; - prefix = 0; - table[i++].prefix = prefix++; - for (; table[i].rangeLen != jbig2HuffmanEOT; ++i) { - prefix <<= table[i].prefixLen - table[i-1].prefixLen; - table[i].prefix = prefix++; - } -} - -//------------------------------------------------------------------------ -// JBIG2MMRDecoder -//------------------------------------------------------------------------ - -class JBIG2MMRDecoder { -public: - - JBIG2MMRDecoder(); - ~JBIG2MMRDecoder(); - void setStream(Stream *strA) { str = strA; } - void reset(); - int get2DCode(); - int getBlackCode(); - int getWhiteCode(); - Guint get24Bits(); - void skipTo(Guint length); - -private: - - Stream *str; - Guint buf; - Guint bufLen; - Guint nBytesRead; -}; - -JBIG2MMRDecoder::JBIG2MMRDecoder() { - str = NULL; - reset(); -} - -JBIG2MMRDecoder::~JBIG2MMRDecoder() { -} - -void JBIG2MMRDecoder::reset() { - buf = 0; - bufLen = 0; - nBytesRead = 0; -} - -int JBIG2MMRDecoder::get2DCode() { - CCITTCode *p; - - if (bufLen == 0) { - buf = str->getChar() & 0xff; - bufLen = 8; - ++nBytesRead; - p = &twoDimTab1[(buf >> 1) & 0x7f]; - } else if (bufLen == 8) { - p = &twoDimTab1[(buf >> 1) & 0x7f]; - } else { - p = &twoDimTab1[(buf << (7 - bufLen)) & 0x7f]; - if (p->bits < 0 || p->bits > (int)bufLen) { - buf = (buf << 8) | (str->getChar() & 0xff); - bufLen += 8; - ++nBytesRead; - p = &twoDimTab1[(buf >> (bufLen - 7)) & 0x7f]; - } - } - if (p->bits < 0) { - error(str->getPos(), "Bad two dim code in JBIG2 MMR stream"); - return 0; - } - bufLen -= p->bits; - return p->n; -} - -int JBIG2MMRDecoder::getWhiteCode() { - CCITTCode *p; - Guint code; - - if (bufLen == 0) { - buf = str->getChar() & 0xff; - bufLen = 8; - ++nBytesRead; - } - while (1) { - if (bufLen >= 7 && ((buf >> (bufLen - 7)) & 0x7f) == 0) { - if (bufLen <= 12) { - code = buf << (12 - bufLen); - } else { - code = buf >> (bufLen - 12); - } - p = &whiteTab1[code & 0x1f]; - } else { - if (bufLen <= 9) { - code = buf << (9 - bufLen); - } else { - code = buf >> (bufLen - 9); - } - p = &whiteTab2[code & 0x1ff]; - } - if (p->bits > 0 && p->bits <= (int)bufLen) { - bufLen -= p->bits; - return p->n; - } - if (bufLen >= 12) { - break; - } - buf = (buf << 8) | (str->getChar() & 0xff); - bufLen += 8; - ++nBytesRead; - } - error(str->getPos(), "Bad white code in JBIG2 MMR stream"); - // eat a bit and return a positive number so that the caller doesn't - // go into an infinite loop - --bufLen; - return 1; -} - -int JBIG2MMRDecoder::getBlackCode() { - CCITTCode *p; - Guint code; - - if (bufLen == 0) { - buf = str->getChar() & 0xff; - bufLen = 8; - ++nBytesRead; - } - while (1) { - if (bufLen >= 6 && ((buf >> (bufLen - 6)) & 0x3f) == 0) { - if (bufLen <= 13) { - code = buf << (13 - bufLen); - } else { - code = buf >> (bufLen - 13); - } - p = &blackTab1[code & 0x7f]; - } else if (bufLen >= 4 && ((buf >> (bufLen - 4)) & 0x0f) == 0) { - if (bufLen <= 12) { - code = buf << (12 - bufLen); - } else { - code = buf >> (bufLen - 12); - } - p = &blackTab2[(code & 0xff) - 64]; - } else { - if (bufLen <= 6) { - code = buf << (6 - bufLen); - } else { - code = buf >> (bufLen - 6); - } - p = &blackTab3[code & 0x3f]; - } - if (p->bits > 0 && p->bits <= (int)bufLen) { - bufLen -= p->bits; - return p->n; - } - if (bufLen >= 13) { - break; - } - buf = (buf << 8) | (str->getChar() & 0xff); - bufLen += 8; - ++nBytesRead; - } - error(str->getPos(), "Bad black code in JBIG2 MMR stream"); - // eat a bit and return a positive number so that the caller doesn't - // go into an infinite loop - --bufLen; - return 1; -} - -Guint JBIG2MMRDecoder::get24Bits() { - while (bufLen < 24) { - buf = (buf << 8) | (str->getChar() & 0xff); - bufLen += 8; - ++nBytesRead; - } - return (buf >> (bufLen - 24)) & 0xffffff; -} - -void JBIG2MMRDecoder::skipTo(Guint length) { - while (nBytesRead < length) { - str->getChar(); - ++nBytesRead; - } -} - -//------------------------------------------------------------------------ -// JBIG2Segment -//------------------------------------------------------------------------ - -enum JBIG2SegmentType { - jbig2SegBitmap, - jbig2SegSymbolDict, - jbig2SegPatternDict, - jbig2SegCodeTable -}; - -class JBIG2Segment { -public: - - JBIG2Segment(Guint segNumA) { segNum = segNumA; } - virtual ~JBIG2Segment() {} - void setSegNum(Guint segNumA) { segNum = segNumA; } - Guint getSegNum() { return segNum; } - virtual JBIG2SegmentType getType() = 0; - -private: - - Guint segNum; -}; - -//------------------------------------------------------------------------ -// JBIG2Bitmap -//------------------------------------------------------------------------ - -struct JBIG2BitmapPtr { - Guchar *p; - int shift; - int x; -}; - -class JBIG2Bitmap: public JBIG2Segment { -public: - - JBIG2Bitmap(Guint segNumA, int wA, int hA); - virtual ~JBIG2Bitmap(); - virtual JBIG2SegmentType getType() { return jbig2SegBitmap; } - JBIG2Bitmap *copy() { return new JBIG2Bitmap(0, this); } - JBIG2Bitmap *getSlice(Guint x, Guint y, Guint wA, Guint hA); - void expand(int newH, Guint pixel); - void clearToZero(); - void clearToOne(); - int getWidth() { return w; } - int getHeight() { return h; } - int getPixel(int x, int y) - { return (x < 0 || x >= w || y < 0 || y >= h) ? 0 : - (data[y * line + (x >> 3)] >> (7 - (x & 7))) & 1; } - void setPixel(int x, int y) - { data[y * line + (x >> 3)] |= 1 << (7 - (x & 7)); } - void clearPixel(int x, int y) - { data[y * line + (x >> 3)] &= 0x7f7f >> (x & 7); } - void getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr); - int nextPixel(JBIG2BitmapPtr *ptr); - void duplicateRow(int yDest, int ySrc); - void combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp); - Guchar *getDataPtr() { return data; } - int getDataSize() { return h * line; } - -private: - - JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap); - - int w, h, line; - Guchar *data; -}; - -JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): - JBIG2Segment(segNumA) -{ - w = wA; - h = hA; - line = (wA + 7) >> 3; - - if (h < 0 || line <= 0 || h >= (INT_MAX - 1) / line) { - data = NULL; - return; - } - - // need to allocate one extra guard byte for use in combine() - data = (Guchar *)gmalloc(h * line + 1); - data[h * line] = 0; -} - -JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): - JBIG2Segment(segNumA) -{ - w = bitmap->w; - h = bitmap->h; - line = bitmap->line; - - if (h < 0 || line <= 0 || h >= (INT_MAX - 1) / line) { - data = NULL; - return; - } - - // need to allocate one extra guard byte for use in combine() - data = (Guchar *)gmalloc(h * line + 1); - memcpy(data, bitmap->data, h * line); - data[h * line] = 0; -} - -JBIG2Bitmap::~JBIG2Bitmap() { - gfree(data); -} - -//~ optimize this -JBIG2Bitmap *JBIG2Bitmap::getSlice(Guint x, Guint y, Guint wA, Guint hA) { - JBIG2Bitmap *slice; - Guint xx, yy; - - slice = new JBIG2Bitmap(0, wA, hA); - slice->clearToZero(); - for (yy = 0; yy < hA; ++yy) { - for (xx = 0; xx < wA; ++xx) { - if (getPixel(x + xx, y + yy)) { - slice->setPixel(xx, yy); - } - } - } - return slice; -} - -void JBIG2Bitmap::expand(int newH, Guint pixel) { - if (newH <= h || line <= 0 || newH >= (INT_MAX - 1) / line) { - return; - } - // need to allocate one extra guard byte for use in combine() - data = (Guchar *)grealloc(data, newH * line + 1); - if (pixel) { - memset(data + h * line, 0xff, (newH - h) * line); - } else { - memset(data + h * line, 0x00, (newH - h) * line); - } - h = newH; - data[h * line] = 0; -} - -void JBIG2Bitmap::clearToZero() { - memset(data, 0, h * line); -} - -void JBIG2Bitmap::clearToOne() { - memset(data, 0xff, h * line); -} - -inline void JBIG2Bitmap::getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr) { - if (y < 0 || y >= h || x >= w) { - ptr->p = NULL; - } else if (x < 0) { - ptr->p = &data[y * line]; - ptr->shift = 7; - ptr->x = x; - } else { - ptr->p = &data[y * line + (x >> 3)]; - ptr->shift = 7 - (x & 7); - ptr->x = x; - } -} - -inline int JBIG2Bitmap::nextPixel(JBIG2BitmapPtr *ptr) { - int pix; - - if (!ptr->p) { - pix = 0; - } else if (ptr->x < 0) { - ++ptr->x; - pix = 0; - } else { - pix = (*ptr->p >> ptr->shift) & 1; - if (++ptr->x == w) { - ptr->p = NULL; - } else if (ptr->shift == 0) { - ++ptr->p; - ptr->shift = 7; - } else { - --ptr->shift; - } - } - return pix; -} - -void JBIG2Bitmap::duplicateRow(int yDest, int ySrc) { - memcpy(data + yDest * line, data + ySrc * line, line); -} - -void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y, - Guint combOp) { - int x0, x1, y0, y1, xx, yy; - Guchar *srcPtr, *destPtr; - Guint src0, src1, src, dest, s1, s2, m1, m2, m3; - GBool oneByte; - - if (y < 0) { - y0 = -y; - } else { - y0 = 0; - } - if (y + bitmap->h > h) { - y1 = h - y; - } else { - y1 = bitmap->h; - } - if (y0 >= y1) { - return; - } - - if (x >= 0) { - x0 = x & ~7; - } else { - x0 = 0; - } - x1 = x + bitmap->w; - if (x1 > w) { - x1 = w; - } - if (x0 >= x1) { - return; - } - - s1 = x & 7; - s2 = 8 - s1; - m1 = 0xff >> (x1 & 7); - m2 = 0xff << (((x1 & 7) == 0) ? 0 : 8 - (x1 & 7)); - m3 = (0xff >> s1) & m2; - - oneByte = x0 == ((x1 - 1) & ~7); - - for (yy = y0; yy < y1; ++yy) { - - // one byte per line -- need to mask both left and right side - if (oneByte) { - if (x >= 0) { - destPtr = data + (y + yy) * line + (x >> 3); - srcPtr = bitmap->data + yy * bitmap->line; - dest = *destPtr; - src1 = *srcPtr; - switch (combOp) { - case 0: // or - dest |= (src1 >> s1) & m2; - break; - case 1: // and - dest &= ((0xff00 | src1) >> s1) | m1; - break; - case 2: // xor - dest ^= (src1 >> s1) & m2; - break; - case 3: // xnor - dest ^= ((src1 ^ 0xff) >> s1) & m2; - break; - case 4: // replace - dest = (dest & ~m3) | ((src1 >> s1) & m3); - break; - } - *destPtr = dest; - } else { - destPtr = data + (y + yy) * line; - srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3); - dest = *destPtr; - src1 = *srcPtr; - switch (combOp) { - case 0: // or - dest |= src1 & m2; - break; - case 1: // and - dest &= src1 | m1; - break; - case 2: // xor - dest ^= src1 & m2; - break; - case 3: // xnor - dest ^= (src1 ^ 0xff) & m2; - break; - case 4: // replace - dest = (src1 & m2) | (dest & m1); - break; - } - *destPtr = dest; - } - - // multiple bytes per line -- need to mask left side of left-most - // byte and right side of right-most byte - } else { - - // left-most byte - if (x >= 0) { - destPtr = data + (y + yy) * line + (x >> 3); - srcPtr = bitmap->data + yy * bitmap->line; - src1 = *srcPtr++; - dest = *destPtr; - switch (combOp) { - case 0: // or - dest |= src1 >> s1; - break; - case 1: // and - dest &= (0xff00 | src1) >> s1; - break; - case 2: // xor - dest ^= src1 >> s1; - break; - case 3: // xnor - dest ^= (src1 ^ 0xff) >> s1; - break; - case 4: // replace - dest = (dest & (0xff << s2)) | (src1 >> s1); - break; - } - *destPtr++ = dest; - xx = x0 + 8; - } else { - destPtr = data + (y + yy) * line; - srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3); - src1 = *srcPtr++; - xx = x0; - } - - // middle bytes - for (; xx < x1 - 8; xx += 8) { - dest = *destPtr; - src0 = src1; - src1 = *srcPtr++; - src = (((src0 << 8) | src1) >> s1) & 0xff; - switch (combOp) { - case 0: // or - dest |= src; - break; - case 1: // and - dest &= src; - break; - case 2: // xor - dest ^= src; - break; - case 3: // xnor - dest ^= src ^ 0xff; - break; - case 4: // replace - dest = src; - break; - } - *destPtr++ = dest; - } - - // right-most byte - // note: this last byte (src1) may not actually be used, depending - // on the values of s1, m1, and m2 - and in fact, it may be off - // the edge of the source bitmap, which means we need to allocate - // one extra guard byte at the end of each bitmap - dest = *destPtr; - src0 = src1; - src1 = *srcPtr++; - src = (((src0 << 8) | src1) >> s1) & 0xff; - switch (combOp) { - case 0: // or - dest |= src & m2; - break; - case 1: // and - dest &= src | m1; - break; - case 2: // xor - dest ^= src & m2; - break; - case 3: // xnor - dest ^= (src ^ 0xff) & m2; - break; - case 4: // replace - dest = (src & m2) | (dest & m1); - break; - } - *destPtr = dest; - } - } -} - -//------------------------------------------------------------------------ -// JBIG2SymbolDict -//------------------------------------------------------------------------ - -class JBIG2SymbolDict: public JBIG2Segment { -public: - - JBIG2SymbolDict(Guint segNumA, Guint sizeA); - virtual ~JBIG2SymbolDict(); - virtual JBIG2SegmentType getType() { return jbig2SegSymbolDict; } - Guint getSize() { return size; } - void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } - JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } - void setGenericRegionStats(JArithmeticDecoderStats *stats) - { genericRegionStats = stats; } - void setRefinementRegionStats(JArithmeticDecoderStats *stats) - { refinementRegionStats = stats; } - JArithmeticDecoderStats *getGenericRegionStats() - { return genericRegionStats; } - JArithmeticDecoderStats *getRefinementRegionStats() - { return refinementRegionStats; } - -private: - - Guint size; - JBIG2Bitmap **bitmaps; - JArithmeticDecoderStats *genericRegionStats; - JArithmeticDecoderStats *refinementRegionStats; -}; - -JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA): - JBIG2Segment(segNumA) -{ - size = sizeA; - bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); - genericRegionStats = NULL; - refinementRegionStats = NULL; -} - -JBIG2SymbolDict::~JBIG2SymbolDict() { - Guint i; - - for (i = 0; i < size; ++i) { - delete bitmaps[i]; - } - gfree(bitmaps); - if (genericRegionStats) { - delete genericRegionStats; - } - if (refinementRegionStats) { - delete refinementRegionStats; - } -} - -//------------------------------------------------------------------------ -// JBIG2PatternDict -//------------------------------------------------------------------------ - -class JBIG2PatternDict: public JBIG2Segment { -public: - - JBIG2PatternDict(Guint segNumA, Guint sizeA); - virtual ~JBIG2PatternDict(); - virtual JBIG2SegmentType getType() { return jbig2SegPatternDict; } - Guint getSize() { return size; } - void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } - JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } - -private: - - Guint size; - JBIG2Bitmap **bitmaps; -}; - -JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA): - JBIG2Segment(segNumA) -{ - size = sizeA; - bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); -} - -JBIG2PatternDict::~JBIG2PatternDict() { - Guint i; - - for (i = 0; i < size; ++i) { - delete bitmaps[i]; - } - gfree(bitmaps); -} - -//------------------------------------------------------------------------ -// JBIG2CodeTable -//------------------------------------------------------------------------ - -class JBIG2CodeTable: public JBIG2Segment { -public: - - JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA); - virtual ~JBIG2CodeTable(); - virtual JBIG2SegmentType getType() { return jbig2SegCodeTable; } - JBIG2HuffmanTable *getHuffTable() { return table; } - -private: - - JBIG2HuffmanTable *table; -}; - -JBIG2CodeTable::JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA): - JBIG2Segment(segNumA) -{ - table = tableA; -} - -JBIG2CodeTable::~JBIG2CodeTable() { - gfree(table); -} - -//------------------------------------------------------------------------ -// JBIG2Stream -//------------------------------------------------------------------------ - -JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStream): - FilterStream(strA) -{ - pageBitmap = NULL; - - arithDecoder = new JArithmeticDecoder(); - genericRegionStats = new JArithmeticDecoderStats(1 << 1); - refinementRegionStats = new JArithmeticDecoderStats(1 << 1); - iadhStats = new JArithmeticDecoderStats(1 << 9); - iadwStats = new JArithmeticDecoderStats(1 << 9); - iaexStats = new JArithmeticDecoderStats(1 << 9); - iaaiStats = new JArithmeticDecoderStats(1 << 9); - iadtStats = new JArithmeticDecoderStats(1 << 9); - iaitStats = new JArithmeticDecoderStats(1 << 9); - iafsStats = new JArithmeticDecoderStats(1 << 9); - iadsStats = new JArithmeticDecoderStats(1 << 9); - iardxStats = new JArithmeticDecoderStats(1 << 9); - iardyStats = new JArithmeticDecoderStats(1 << 9); - iardwStats = new JArithmeticDecoderStats(1 << 9); - iardhStats = new JArithmeticDecoderStats(1 << 9); - iariStats = new JArithmeticDecoderStats(1 << 9); - iaidStats = new JArithmeticDecoderStats(1 << 1); - huffDecoder = new JBIG2HuffmanDecoder(); - mmrDecoder = new JBIG2MMRDecoder(); - - segments = globalSegments = new GList(); - if (globalsStream->isStream()) { - curStr = globalsStream->getStream(); - curStr->reset(); - arithDecoder->setStream(curStr); - huffDecoder->setStream(curStr); - mmrDecoder->setStream(curStr); - readSegments(); - } - - segments = NULL; - curStr = NULL; - dataPtr = dataEnd = NULL; -} - -JBIG2Stream::~JBIG2Stream() { - delete arithDecoder; - delete genericRegionStats; - delete refinementRegionStats; - delete iadhStats; - delete iadwStats; - delete iaexStats; - delete iaaiStats; - delete iadtStats; - delete iaitStats; - delete iafsStats; - delete iadsStats; - delete iardxStats; - delete iardyStats; - delete iardwStats; - delete iardhStats; - delete iariStats; - delete iaidStats; - delete huffDecoder; - delete mmrDecoder; - if (pageBitmap) { - delete pageBitmap; - } - if (segments) { - deleteGList(segments, JBIG2Segment); - } - if (globalSegments) { - deleteGList(globalSegments, JBIG2Segment); - } - delete str; -} - -void JBIG2Stream::reset() { - if (pageBitmap) { - delete pageBitmap; - pageBitmap = NULL; - } - if (segments) { - deleteGList(segments, JBIG2Segment); - } - segments = new GList(); - - curStr = str; - curStr->reset(); - arithDecoder->setStream(curStr); - huffDecoder->setStream(curStr); - mmrDecoder->setStream(curStr); - readSegments(); - - if (pageBitmap) { - dataPtr = pageBitmap->getDataPtr(); - dataEnd = dataPtr + pageBitmap->getDataSize(); - } else { - dataPtr = NULL; - } -} - -int JBIG2Stream::getChar() { - if (dataPtr && dataPtr < dataEnd) { - return (*dataPtr++ ^ 0xff) & 0xff; - } - return EOF; -} - -int JBIG2Stream::lookChar() { - if (dataPtr && dataPtr < dataEnd) { - return (*dataPtr ^ 0xff) & 0xff; - } - return EOF; -} - -GString *JBIG2Stream::getPSFilter(int /*psLevel*/, const char */*indent*/) { - return NULL; -} - -GBool JBIG2Stream::isBinary(GBool /*last*/) { - return str->isBinary(gTrue); -} - -void JBIG2Stream::readSegments() { - Guint segNum, segFlags, segType, page, segLength; - Guint refFlags, nRefSegs; - Guint *refSegs; - int c1, c2, c3; - Guint i; - - while (readULong(&segNum)) { - - // segment header flags - if (!readUByte(&segFlags)) { - goto eofError1; - } - segType = segFlags & 0x3f; - - // referred-to segment count and retention flags - if (!readUByte(&refFlags)) { - goto eofError1; - } - nRefSegs = refFlags >> 5; - if (nRefSegs == 7) { - if ((c1 = curStr->getChar()) == EOF || - (c2 = curStr->getChar()) == EOF || - (c3 = curStr->getChar()) == EOF) { - goto eofError1; - } - refFlags = (refFlags << 24) | (c1 << 16) | (c2 << 8) | c3; - nRefSegs = refFlags & 0x1fffffff; - for (i = 0; i < (nRefSegs + 9) >> 3; ++i) { - c1 = curStr->getChar(); - } - } - - // referred-to segment numbers - refSegs = (Guint *)gmallocn(nRefSegs, sizeof(Guint)); - if (segNum <= 256) { - for (i = 0; i < nRefSegs; ++i) { - if (!readUByte(&refSegs[i])) { - goto eofError2; - } - } - } else if (segNum <= 65536) { - for (i = 0; i < nRefSegs; ++i) { - if (!readUWord(&refSegs[i])) { - goto eofError2; - } - } - } else { - for (i = 0; i < nRefSegs; ++i) { - if (!readULong(&refSegs[i])) { - goto eofError2; - } - } - } - - // segment page association - if (segFlags & 0x40) { - if (!readULong(&page)) { - goto eofError2; - } - } else { - if (!readUByte(&page)) { - goto eofError2; - } - } - - // segment data length - if (!readULong(&segLength)) { - goto eofError2; - } - - // read the segment data - switch (segType) { - case 0: - if (!readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs)) { - goto syntaxError; - } - break; - case 4: - readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs); - break; - case 6: - readTextRegionSeg(segNum, gTrue, gFalse, segLength, refSegs, nRefSegs); - break; - case 7: - readTextRegionSeg(segNum, gTrue, gTrue, segLength, refSegs, nRefSegs); - break; - case 16: - readPatternDictSeg(segNum, segLength); - break; - case 20: - readHalftoneRegionSeg(segNum, gFalse, gFalse, segLength, - refSegs, nRefSegs); - break; - case 22: - readHalftoneRegionSeg(segNum, gTrue, gFalse, segLength, - refSegs, nRefSegs); - break; - case 23: - readHalftoneRegionSeg(segNum, gTrue, gTrue, segLength, - refSegs, nRefSegs); - break; - case 36: - readGenericRegionSeg(segNum, gFalse, gFalse, segLength); - break; - case 38: - readGenericRegionSeg(segNum, gTrue, gFalse, segLength); - break; - case 39: - readGenericRegionSeg(segNum, gTrue, gTrue, segLength); - break; - case 40: - readGenericRefinementRegionSeg(segNum, gFalse, gFalse, segLength, - refSegs, nRefSegs); - break; - case 42: - readGenericRefinementRegionSeg(segNum, gTrue, gFalse, segLength, - refSegs, nRefSegs); - break; - case 43: - readGenericRefinementRegionSeg(segNum, gTrue, gTrue, segLength, - refSegs, nRefSegs); - break; - case 48: - readPageInfoSeg(segLength); - break; - case 50: - readEndOfStripeSeg(segLength); - break; - case 52: - readProfilesSeg(segLength); - break; - case 53: - readCodeTableSeg(segNum, segLength); - break; - case 62: - readExtensionSeg(segLength); - break; - default: - error(getPos(), "Unknown segment type in JBIG2 stream"); - for (i = 0; i < segLength; ++i) { - if ((c1 = curStr->getChar()) == EOF) { - goto eofError2; - } - } - break; - } - - gfree(refSegs); - } - - return; - - syntaxError: - gfree(refSegs); - return; - - eofError2: - gfree(refSegs); - eofError1: - error(getPos(), "Unexpected EOF in JBIG2 stream"); -} - -GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint /*length*/, - Guint *refSegs, Guint nRefSegs) { - JBIG2SymbolDict *symbolDict; - JBIG2HuffmanTable *huffDHTable, *huffDWTable; - JBIG2HuffmanTable *huffBMSizeTable, *huffAggInstTable; - JBIG2Segment *seg; - GList *codeTables; - JBIG2SymbolDict *inputSymbolDict; - Guint flags, sdTemplate, sdrTemplate, huff, refAgg; - Guint huffDH, huffDW, huffBMSize, huffAggInst; - Guint contextUsed, contextRetained; - int sdATX[4], sdATY[4], sdrATX[2], sdrATY[2]; - Guint numExSyms, numNewSyms, numInputSyms, symCodeLen; - JBIG2Bitmap **bitmaps; - JBIG2Bitmap *collBitmap, *refBitmap; - Guint *symWidths; - Guint symHeight, symWidth, totalWidth, x, symID; - int dh, dw, refAggNum, refDX, refDY, bmSize; - GBool ex; - int run, cnt; - Guint i, j, k; - Guchar *p; - - // symbol dictionary flags - if (!readUWord(&flags)) { - goto eofError; - } - sdTemplate = (flags >> 10) & 3; - sdrTemplate = (flags >> 12) & 1; - huff = flags & 1; - refAgg = (flags >> 1) & 1; - huffDH = (flags >> 2) & 3; - huffDW = (flags >> 4) & 3; - huffBMSize = (flags >> 6) & 1; - huffAggInst = (flags >> 7) & 1; - contextUsed = (flags >> 8) & 1; - contextRetained = (flags >> 9) & 1; - - // symbol dictionary AT flags - if (!huff) { - if (sdTemplate == 0) { - if (!readByte(&sdATX[0]) || - !readByte(&sdATY[0]) || - !readByte(&sdATX[1]) || - !readByte(&sdATY[1]) || - !readByte(&sdATX[2]) || - !readByte(&sdATY[2]) || - !readByte(&sdATX[3]) || - !readByte(&sdATY[3])) { - goto eofError; - } - } else { - if (!readByte(&sdATX[0]) || - !readByte(&sdATY[0])) { - goto eofError; - } - } - } - - // symbol dictionary refinement AT flags - if (refAgg && !sdrTemplate) { - if (!readByte(&sdrATX[0]) || - !readByte(&sdrATY[0]) || - !readByte(&sdrATX[1]) || - !readByte(&sdrATY[1])) { - goto eofError; - } - } - - // SDNUMEXSYMS and SDNUMNEWSYMS - if (!readULong(&numExSyms) || !readULong(&numNewSyms)) { - goto eofError; - } - - // get referenced segments: input symbol dictionaries and code tables - codeTables = new GList(); - numInputSyms = 0; - for (i = 0; i < nRefSegs; ++i) { - seg = findSegment(refSegs[i]); - if (seg->getType() == jbig2SegSymbolDict) { - numInputSyms += ((JBIG2SymbolDict *)seg)->getSize(); - } else if (seg->getType() == jbig2SegCodeTable) { - codeTables->append(seg); - } - } - - // compute symbol code length - symCodeLen = 0; - i = 1; - while (i < numInputSyms + numNewSyms) { - ++symCodeLen; - i <<= 1; - } - - // get the input symbol bitmaps - bitmaps = (JBIG2Bitmap **)gmallocn(numInputSyms + numNewSyms, - sizeof(JBIG2Bitmap *)); - for (i = 0; i < numInputSyms + numNewSyms; ++i) { - bitmaps[i] = NULL; - } - k = 0; - inputSymbolDict = NULL; - for (i = 0; i < nRefSegs; ++i) { - seg = findSegment(refSegs[i]); - if (seg->getType() == jbig2SegSymbolDict) { - inputSymbolDict = (JBIG2SymbolDict *)seg; - for (j = 0; j < inputSymbolDict->getSize(); ++j) { - bitmaps[k++] = inputSymbolDict->getBitmap(j); - } - } - } - - // get the Huffman tables - huffDHTable = huffDWTable = NULL; // make gcc happy - huffBMSizeTable = huffAggInstTable = NULL; // make gcc happy - i = 0; - if (huff) { - if (huffDH == 0) { - huffDHTable = huffTableD; - } else if (huffDH == 1) { - huffDHTable = huffTableE; - } else { - huffDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - if (huffDW == 0) { - huffDWTable = huffTableB; - } else if (huffDW == 1) { - huffDWTable = huffTableC; - } else { - huffDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - if (huffBMSize == 0) { - huffBMSizeTable = huffTableA; - } else { - huffBMSizeTable = - ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - if (huffAggInst == 0) { - huffAggInstTable = huffTableA; - } else { - huffAggInstTable = - ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - } - delete codeTables; - - // set up the Huffman decoder - if (huff) { - huffDecoder->reset(); - - // set up the arithmetic decoder - } else { - if (contextUsed && inputSymbolDict) { - resetGenericStats(sdTemplate, inputSymbolDict->getGenericRegionStats()); - } else { - resetGenericStats(sdTemplate, NULL); - } - resetIntStats(symCodeLen); - arithDecoder->start(); - } - - // set up the arithmetic decoder for refinement/aggregation - if (refAgg) { - if (contextUsed && inputSymbolDict) { - resetRefinementStats(sdrTemplate, - inputSymbolDict->getRefinementRegionStats()); - } else { - resetRefinementStats(sdrTemplate, NULL); - } - } - - // allocate symbol widths storage - symWidths = NULL; - if (huff && !refAgg) { - symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint)); - } - - symHeight = 0; - i = 0; - while (i < numNewSyms) { - - // read the height class delta height - if (huff) { - huffDecoder->decodeInt(&dh, huffDHTable); - } else { - arithDecoder->decodeInt(&dh, iadhStats); - } - if (dh < 0 && (Guint)-dh >= symHeight) { - error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); - goto syntaxError; - } - symHeight += dh; - symWidth = 0; - totalWidth = 0; - j = i; - - // read the symbols in this height class - while (1) { - - // read the delta width - if (huff) { - if (!huffDecoder->decodeInt(&dw, huffDWTable)) { - break; - } - } else { - if (!arithDecoder->decodeInt(&dw, iadwStats)) { - break; - } - } - if (dw < 0 && (Guint)-dw >= symWidth) { - error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); - goto syntaxError; - } - symWidth += dw; - - // using a collective bitmap, so don't read a bitmap here - if (huff && !refAgg) { - symWidths[i] = symWidth; - totalWidth += symWidth; - - // refinement/aggregate coding - } else if (refAgg) { - if (huff) { - if (!huffDecoder->decodeInt(&refAggNum, huffAggInstTable)) { - break; - } - } else { - if (!arithDecoder->decodeInt(&refAggNum, iaaiStats)) { - break; - } - } -#if 0 //~ This special case was added about a year before the final draft - //~ of the JBIG2 spec was released. I have encountered some old - //~ JBIG2 images that predate it. - if (0) { -#else - if (refAggNum == 1) { -#endif - if (huff) { - symID = huffDecoder->readBits(symCodeLen); - huffDecoder->decodeInt(&refDX, huffTableO); - huffDecoder->decodeInt(&refDY, huffTableO); - huffDecoder->decodeInt(&bmSize, huffTableA); - huffDecoder->reset(); - arithDecoder->start(); - } else { - symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); - arithDecoder->decodeInt(&refDX, iardxStats); - arithDecoder->decodeInt(&refDY, iardyStats); - } - refBitmap = bitmaps[symID]; - bitmaps[numInputSyms + i] = - readGenericRefinementRegion(symWidth, symHeight, - sdrTemplate, gFalse, - refBitmap, refDX, refDY, - sdrATX, sdrATY); - //~ do we need to use the bmSize value here (in Huffman mode)? - } else { - bitmaps[numInputSyms + i] = - readTextRegion(huff, gTrue, symWidth, symHeight, - refAggNum, 0, numInputSyms + i, NULL, - symCodeLen, bitmaps, 0, 0, 0, 1, 0, - huffTableF, huffTableH, huffTableK, huffTableO, - huffTableO, huffTableO, huffTableO, huffTableA, - sdrTemplate, sdrATX, sdrATY); - } - - // non-ref/agg coding - } else { - bitmaps[numInputSyms + i] = - readGenericBitmap(gFalse, symWidth, symHeight, - sdTemplate, gFalse, gFalse, NULL, - sdATX, sdATY, 0); - } - - ++i; - } - - // read the collective bitmap - if (huff && !refAgg) { - huffDecoder->decodeInt(&bmSize, huffBMSizeTable); - huffDecoder->reset(); - if (bmSize == 0) { - collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight); - bmSize = symHeight * ((totalWidth + 7) >> 3); - p = collBitmap->getDataPtr(); - for (k = 0; k < (Guint)bmSize; ++k) { - *p++ = curStr->getChar(); - } - } else { - collBitmap = readGenericBitmap(gTrue, totalWidth, symHeight, - 0, gFalse, gFalse, NULL, NULL, NULL, - bmSize); - } - x = 0; - for (; j < i; ++j) { - bitmaps[numInputSyms + j] = - collBitmap->getSlice(x, 0, symWidths[j], symHeight); - x += symWidths[j]; - } - delete collBitmap; - } - } - - // create the symbol dict object - symbolDict = new JBIG2SymbolDict(segNum, numExSyms); - - // exported symbol list - i = j = 0; - ex = gFalse; - while (i < numInputSyms + numNewSyms) { - if (huff) { - huffDecoder->decodeInt(&run, huffTableA); - } else { - arithDecoder->decodeInt(&run, iaexStats); - } - if (ex) { - for (cnt = 0; cnt < run; ++cnt) { - symbolDict->setBitmap(j++, bitmaps[i++]->copy()); - } - } else { - i += run; - } - ex = !ex; - } - - for (i = 0; i < numNewSyms; ++i) { - delete bitmaps[numInputSyms + i]; - } - gfree(bitmaps); - if (symWidths) { - gfree(symWidths); - } - - // save the arithmetic decoder stats - if (!huff && contextRetained) { - symbolDict->setGenericRegionStats(genericRegionStats->copy()); - if (refAgg) { - symbolDict->setRefinementRegionStats(refinementRegionStats->copy()); - } - } - - // store the new symbol dict - segments->append(symbolDict); - - return gTrue; - - syntaxError: - for (i = 0; i < numNewSyms; ++i) { - if (bitmaps[numInputSyms + i]) { - delete bitmaps[numInputSyms + i]; - } - } - gfree(bitmaps); - if (symWidths) { - gfree(symWidths); - } - return gFalse; - - eofError: - error(getPos(), "Unexpected EOF in JBIG2 stream"); - return gFalse; -} - -void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, - GBool /*lossless*/, Guint /*length*/, - Guint *refSegs, Guint nRefSegs) { - JBIG2Bitmap *bitmap; - JBIG2HuffmanTable runLengthTab[36]; - JBIG2HuffmanTable *symCodeTab; - JBIG2HuffmanTable *huffFSTable, *huffDSTable, *huffDTTable; - JBIG2HuffmanTable *huffRDWTable, *huffRDHTable; - JBIG2HuffmanTable *huffRDXTable, *huffRDYTable, *huffRSizeTable; - JBIG2Segment *seg; - GList *codeTables; - JBIG2SymbolDict *symbolDict; - JBIG2Bitmap **syms; - Guint w, h, x, y, segInfoFlags, extCombOp; - Guint flags, huff, refine, logStrips, refCorner, transposed; - Guint combOp, defPixel, templ; - int sOffset; - Guint huffFlags, huffFS, huffDS, huffDT; - Guint huffRDW, huffRDH, huffRDX, huffRDY, huffRSize; - Guint numInstances, numSyms, symCodeLen; - int atx[2], aty[2]; - Guint i, k, kk; - int j; - - // region segment info field - if (!readULong(&w) || !readULong(&h) || - !readULong(&x) || !readULong(&y) || - !readUByte(&segInfoFlags)) { - goto eofError; - } - extCombOp = segInfoFlags & 7; - - // rest of the text region header - if (!readUWord(&flags)) { - goto eofError; - } - huff = flags & 1; - refine = (flags >> 1) & 1; - logStrips = (flags >> 2) & 3; - refCorner = (flags >> 4) & 3; - transposed = (flags >> 6) & 1; - combOp = (flags >> 7) & 3; - defPixel = (flags >> 9) & 1; - sOffset = (flags >> 10) & 0x1f; - if (sOffset & 0x10) { - sOffset |= -1 - 0x0f; - } - templ = (flags >> 15) & 1; - huffFS = huffDS = huffDT = 0; // make gcc happy - huffRDW = huffRDH = huffRDX = huffRDY = huffRSize = 0; // make gcc happy - if (huff) { - if (!readUWord(&huffFlags)) { - goto eofError; - } - huffFS = huffFlags & 3; - huffDS = (huffFlags >> 2) & 3; - huffDT = (huffFlags >> 4) & 3; - huffRDW = (huffFlags >> 6) & 3; - huffRDH = (huffFlags >> 8) & 3; - huffRDX = (huffFlags >> 10) & 3; - huffRDY = (huffFlags >> 12) & 3; - huffRSize = (huffFlags >> 14) & 1; - } - if (refine && templ == 0) { - if (!readByte(&atx[0]) || !readByte(&aty[0]) || - !readByte(&atx[1]) || !readByte(&aty[1])) { - goto eofError; - } - } - if (!readULong(&numInstances)) { - goto eofError; - } - - // get symbol dictionaries and tables - codeTables = new GList(); - numSyms = 0; - for (i = 0; i < nRefSegs; ++i) { - if ((seg = findSegment(refSegs[i]))) { - if (seg->getType() == jbig2SegSymbolDict) { - numSyms += ((JBIG2SymbolDict *)seg)->getSize(); - } else if (seg->getType() == jbig2SegCodeTable) { - codeTables->append(seg); - } - } else { - error(getPos(), "Invalid segment reference in JBIG2 text region"); - } - } - symCodeLen = 0; - i = 1; - while (i < numSyms) { - ++symCodeLen; - i <<= 1; - } - - // get the symbol bitmaps - syms = (JBIG2Bitmap **)gmallocn(numSyms, sizeof(JBIG2Bitmap *)); - kk = 0; - for (i = 0; i < nRefSegs; ++i) { - if ((seg = findSegment(refSegs[i]))) { - if (seg->getType() == jbig2SegSymbolDict) { - symbolDict = (JBIG2SymbolDict *)seg; - for (k = 0; k < symbolDict->getSize(); ++k) { - syms[kk++] = symbolDict->getBitmap(k); - } - } - } - } - - // get the Huffman tables - huffFSTable = huffDSTable = huffDTTable = NULL; // make gcc happy - huffRDWTable = huffRDHTable = NULL; // make gcc happy - huffRDXTable = huffRDYTable = huffRSizeTable = NULL; // make gcc happy - i = 0; - if (huff) { - if (huffFS == 0) { - huffFSTable = huffTableF; - } else if (huffFS == 1) { - huffFSTable = huffTableG; - } else { - huffFSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - if (huffDS == 0) { - huffDSTable = huffTableH; - } else if (huffDS == 1) { - huffDSTable = huffTableI; - } else if (huffDS == 2) { - huffDSTable = huffTableJ; - } else { - huffDSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - if (huffDT == 0) { - huffDTTable = huffTableK; - } else if (huffDT == 1) { - huffDTTable = huffTableL; - } else if (huffDT == 2) { - huffDTTable = huffTableM; - } else { - huffDTTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - if (huffRDW == 0) { - huffRDWTable = huffTableN; - } else if (huffRDW == 1) { - huffRDWTable = huffTableO; - } else { - huffRDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - if (huffRDH == 0) { - huffRDHTable = huffTableN; - } else if (huffRDH == 1) { - huffRDHTable = huffTableO; - } else { - huffRDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - if (huffRDX == 0) { - huffRDXTable = huffTableN; - } else if (huffRDX == 1) { - huffRDXTable = huffTableO; - } else { - huffRDXTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - if (huffRDY == 0) { - huffRDYTable = huffTableN; - } else if (huffRDY == 1) { - huffRDYTable = huffTableO; - } else { - huffRDYTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - if (huffRSize == 0) { - huffRSizeTable = huffTableA; - } else { - huffRSizeTable = - ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); - } - } - delete codeTables; - - // symbol ID Huffman decoding table - if (huff) { - huffDecoder->reset(); - for (i = 0; i < 32; ++i) { - runLengthTab[i].val = i; - runLengthTab[i].prefixLen = huffDecoder->readBits(4); - runLengthTab[i].rangeLen = 0; - } - runLengthTab[32].val = 0x103; - runLengthTab[32].prefixLen = huffDecoder->readBits(4); - runLengthTab[32].rangeLen = 2; - runLengthTab[33].val = 0x203; - runLengthTab[33].prefixLen = huffDecoder->readBits(4); - runLengthTab[33].rangeLen = 3; - runLengthTab[34].val = 0x20b; - runLengthTab[34].prefixLen = huffDecoder->readBits(4); - runLengthTab[34].rangeLen = 7; - runLengthTab[35].prefixLen = 0; - runLengthTab[35].rangeLen = jbig2HuffmanEOT; - huffDecoder->buildTable(runLengthTab, 35); - symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1, - sizeof(JBIG2HuffmanTable)); - for (i = 0; i < numSyms; ++i) { - symCodeTab[i].val = i; - symCodeTab[i].rangeLen = 0; - } - i = 0; - while (i < numSyms) { - huffDecoder->decodeInt(&j, runLengthTab); - if (j > 0x200) { - for (j -= 0x200; j && i < numSyms; --j) { - symCodeTab[i++].prefixLen = 0; - } - } else if (j > 0x100) { - for (j -= 0x100; j && i < numSyms; --j) { - symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen; - ++i; - } - } else { - symCodeTab[i++].prefixLen = j; - } - } - symCodeTab[numSyms].prefixLen = 0; - symCodeTab[numSyms].rangeLen = jbig2HuffmanEOT; - huffDecoder->buildTable(symCodeTab, numSyms); - huffDecoder->reset(); - - // set up the arithmetic decoder - } else { - symCodeTab = NULL; - resetIntStats(symCodeLen); - arithDecoder->start(); - } - if (refine) { - resetRefinementStats(templ, NULL); - } - - bitmap = readTextRegion(huff, refine, w, h, numInstances, - logStrips, numSyms, symCodeTab, symCodeLen, syms, - defPixel, combOp, transposed, refCorner, sOffset, - huffFSTable, huffDSTable, huffDTTable, - huffRDWTable, huffRDHTable, - huffRDXTable, huffRDYTable, huffRSizeTable, - templ, atx, aty); - - gfree(syms); - - // combine the region bitmap into the page bitmap - if (imm) { - if (pageH == 0xffffffff && y + h > curPageH) { - pageBitmap->expand(y + h, pageDefPixel); - } - pageBitmap->combine(bitmap, x, y, extCombOp); - delete bitmap; - - // store the region bitmap - } else { - bitmap->setSegNum(segNum); - segments->append(bitmap); - } - - // clean up the Huffman decoder - if (huff) { - gfree(symCodeTab); - } - - return; - - eofError: - error(getPos(), "Unexpected EOF in JBIG2 stream"); -} - -JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, - int w, int h, - Guint numInstances, - Guint logStrips, - int numSyms, - JBIG2HuffmanTable *symCodeTab, - Guint symCodeLen, - JBIG2Bitmap **syms, - Guint defPixel, Guint combOp, - Guint transposed, Guint refCorner, - int sOffset, - JBIG2HuffmanTable *huffFSTable, - JBIG2HuffmanTable *huffDSTable, - JBIG2HuffmanTable *huffDTTable, - JBIG2HuffmanTable *huffRDWTable, - JBIG2HuffmanTable *huffRDHTable, - JBIG2HuffmanTable *huffRDXTable, - JBIG2HuffmanTable *huffRDYTable, - JBIG2HuffmanTable *huffRSizeTable, - Guint templ, - int *atx, int *aty) { - JBIG2Bitmap *bitmap; - JBIG2Bitmap *symbolBitmap; - Guint strips; - int t, dt, tt, s, ds, sFirst, j; - int rdw, rdh, rdx, rdy, ri, refDX, refDY, bmSize; - Guint symID, inst, bw, bh; - - strips = 1 << logStrips; - - // allocate the bitmap - bitmap = new JBIG2Bitmap(0, w, h); - if (defPixel) { - bitmap->clearToOne(); - } else { - bitmap->clearToZero(); - } - - // decode initial T value - if (huff) { - huffDecoder->decodeInt(&t, huffDTTable); - } else { - arithDecoder->decodeInt(&t, iadtStats); - } - t *= -(int)strips; - - inst = 0; - sFirst = 0; - while (inst < numInstances) { - - // decode delta-T - if (huff) { - huffDecoder->decodeInt(&dt, huffDTTable); - } else { - arithDecoder->decodeInt(&dt, iadtStats); - } - t += dt * strips; - - // first S value - if (huff) { - huffDecoder->decodeInt(&ds, huffFSTable); - } else { - arithDecoder->decodeInt(&ds, iafsStats); - } - sFirst += ds; - s = sFirst; - - // read the instances - while (1) { - - // T value - if (strips == 1) { - dt = 0; - } else if (huff) { - dt = huffDecoder->readBits(logStrips); - } else { - arithDecoder->decodeInt(&dt, iaitStats); - } - tt = t + dt; - - // symbol ID - if (huff) { - if (symCodeTab) { - huffDecoder->decodeInt(&j, symCodeTab); - symID = (Guint)j; - } else { - symID = huffDecoder->readBits(symCodeLen); - } - } else { - symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); - } - - if (symID >= (Guint)numSyms) { - error(getPos(), "Invalid symbol number in JBIG2 text region"); - } else { - - // get the symbol bitmap - symbolBitmap = NULL; - if (refine) { - if (huff) { - ri = (int)huffDecoder->readBit(); - } else { - arithDecoder->decodeInt(&ri, iariStats); - } - } else { - ri = 0; - } - if (ri) { - if (huff) { - huffDecoder->decodeInt(&rdw, huffRDWTable); - huffDecoder->decodeInt(&rdh, huffRDHTable); - huffDecoder->decodeInt(&rdx, huffRDXTable); - huffDecoder->decodeInt(&rdy, huffRDYTable); - huffDecoder->decodeInt(&bmSize, huffRSizeTable); - huffDecoder->reset(); - arithDecoder->start(); - } else { - arithDecoder->decodeInt(&rdw, iardwStats); - arithDecoder->decodeInt(&rdh, iardhStats); - arithDecoder->decodeInt(&rdx, iardxStats); - arithDecoder->decodeInt(&rdy, iardyStats); - } - refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx; - refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy; - - symbolBitmap = - readGenericRefinementRegion(rdw + syms[symID]->getWidth(), - rdh + syms[symID]->getHeight(), - templ, gFalse, syms[symID], - refDX, refDY, atx, aty); - //~ do we need to use the bmSize value here (in Huffman mode)? - } else { - symbolBitmap = syms[symID]; - } - - // combine the symbol bitmap into the region bitmap - //~ something is wrong here - refCorner shouldn't degenerate into - //~ two cases - bw = symbolBitmap->getWidth() - 1; - bh = symbolBitmap->getHeight() - 1; - if (transposed) { - switch (refCorner) { - case 0: // bottom left - bitmap->combine(symbolBitmap, tt, s, combOp); - break; - case 1: // top left - bitmap->combine(symbolBitmap, tt, s, combOp); - break; - case 2: // bottom right - bitmap->combine(symbolBitmap, tt - bw, s, combOp); - break; - case 3: // top right - bitmap->combine(symbolBitmap, tt - bw, s, combOp); - break; - } - s += bh; - } else { - switch (refCorner) { - case 0: // bottom left - bitmap->combine(symbolBitmap, s, tt - bh, combOp); - break; - case 1: // top left - bitmap->combine(symbolBitmap, s, tt, combOp); - break; - case 2: // bottom right - bitmap->combine(symbolBitmap, s, tt - bh, combOp); - break; - case 3: // top right - bitmap->combine(symbolBitmap, s, tt, combOp); - break; - } - s += bw; - } - if (ri) { - delete symbolBitmap; - } - } - - // next instance - ++inst; - - // next S value - if (huff) { - if (!huffDecoder->decodeInt(&ds, huffDSTable)) { - break; - } - } else { - if (!arithDecoder->decodeInt(&ds, iadsStats)) { - break; - } - } - s += sOffset + ds; - } - } - - return bitmap; -} - -void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) { - JBIG2PatternDict *patternDict; - JBIG2Bitmap *bitmap; - Guint flags, patternW, patternH, grayMax, templ, mmr; - int atx[4], aty[4]; - Guint i, x; - - // halftone dictionary flags, pattern width and height, max gray value - if (!readUByte(&flags) || - !readUByte(&patternW) || - !readUByte(&patternH) || - !readULong(&grayMax)) { - goto eofError; - } - templ = (flags >> 1) & 3; - mmr = flags & 1; - - // set up the arithmetic decoder - if (!mmr) { - resetGenericStats(templ, NULL); - arithDecoder->start(); - } - - // read the bitmap - atx[0] = -(int)patternW; aty[0] = 0; - atx[1] = -3; aty[1] = -1; - atx[2] = 2; aty[2] = -2; - atx[3] = -2; aty[3] = -2; - bitmap = readGenericBitmap(mmr, (grayMax + 1) * patternW, patternH, - templ, gFalse, gFalse, NULL, - atx, aty, length - 7); - - // create the pattern dict object - patternDict = new JBIG2PatternDict(segNum, grayMax + 1); - - // split up the bitmap - x = 0; - for (i = 0; i <= grayMax; ++i) { - patternDict->setBitmap(i, bitmap->getSlice(x, 0, patternW, patternH)); - x += patternW; - } - - // free memory - delete bitmap; - - // store the new pattern dict - segments->append(patternDict); - - return; - - eofError: - error(getPos(), "Unexpected EOF in JBIG2 stream"); -} - -void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, - GBool /*lossless*/, Guint /*length*/, - Guint *refSegs, Guint nRefSegs) { - JBIG2Bitmap *bitmap; - JBIG2Segment *seg; - JBIG2PatternDict *patternDict; - JBIG2Bitmap *skipBitmap; - Guint *grayImg; - JBIG2Bitmap *grayBitmap; - JBIG2Bitmap *patternBitmap; - Guint w, h, x, y, segInfoFlags, extCombOp; - Guint flags, mmr, templ, enableSkip, combOp; - Guint gridW, gridH, stepX, stepY, patW, patH; - int atx[4], aty[4]; - int gridX, gridY, xx, yy, bit, j; - Guint bpp, m, n, i; - - // region segment info field - if (!readULong(&w) || !readULong(&h) || - !readULong(&x) || !readULong(&y) || - !readUByte(&segInfoFlags)) { - goto eofError; - } - extCombOp = segInfoFlags & 7; - - // rest of the halftone region header - if (!readUByte(&flags)) { - goto eofError; - } - mmr = flags & 1; - templ = (flags >> 1) & 3; - enableSkip = (flags >> 3) & 1; - combOp = (flags >> 4) & 7; - if (!readULong(&gridW) || !readULong(&gridH) || - !readLong(&gridX) || !readLong(&gridY) || - !readUWord(&stepX) || !readUWord(&stepY)) { - goto eofError; - } - - // get pattern dictionary - if (nRefSegs != 1) { - error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); - return; - } - seg = findSegment(refSegs[0]); - if (seg->getType() != jbig2SegPatternDict) { - error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); - return; - } - if (gridH == 0 || gridW >= INT_MAX / gridH) { - error(getPos(), "Bad size in JBIG2 halftone segment"); - return; - } - if (w == 0 || h >= INT_MAX / w) { - error(getPos(), "Bad size in JBIG2 bitmap segment"); - return; - } - - patternDict = (JBIG2PatternDict *)seg; - bpp = 0; - i = 1; - while (i < patternDict->getSize()) { - ++bpp; - i <<= 1; - } - patW = patternDict->getBitmap(0)->getWidth(); - patH = patternDict->getBitmap(0)->getHeight(); - - // set up the arithmetic decoder - if (!mmr) { - resetGenericStats(templ, NULL); - arithDecoder->start(); - } - - // allocate the bitmap - bitmap = new JBIG2Bitmap(segNum, w, h); - if (flags & 0x80) { // HDEFPIXEL - bitmap->clearToOne(); - } else { - bitmap->clearToZero(); - } - - // compute the skip bitmap - skipBitmap = NULL; - if (enableSkip) { - skipBitmap = new JBIG2Bitmap(0, gridW, gridH); - skipBitmap->clearToZero(); - for (m = 0; m < gridH; ++m) { - xx = gridX + m * stepY; - yy = gridY + m * stepX; - for (n = 0; n < gridW; ++n) { - if (((xx + (int)patW) >> 8) <= 0 || (xx >> 8) >= (int)w || - ((yy + (int)patH) >> 8) <= 0 || (yy >> 8) >= (int)h) { - skipBitmap->setPixel(n, m); - } - } - } - } - - // read the gray-scale image - grayImg = (Guint *)gmallocn(gridW * gridH, sizeof(Guint)); - memset(grayImg, 0, gridW * gridH * sizeof(Guint)); - atx[0] = templ <= 1 ? 3 : 2; aty[0] = -1; - atx[1] = -3; aty[1] = -1; - atx[2] = 2; aty[2] = -2; - atx[3] = -2; aty[3] = -2; - for (j = bpp - 1; j >= 0; --j) { - grayBitmap = readGenericBitmap(mmr, gridW, gridH, templ, gFalse, - enableSkip, skipBitmap, atx, aty, -1); - i = 0; - for (m = 0; m < gridH; ++m) { - for (n = 0; n < gridW; ++n) { - bit = grayBitmap->getPixel(n, m) ^ (grayImg[i] & 1); - grayImg[i] = (grayImg[i] << 1) | bit; - ++i; - } - } - delete grayBitmap; - } - - // decode the image - i = 0; - for (m = 0; m < gridH; ++m) { - xx = gridX + m * stepY; - yy = gridY + m * stepX; - for (n = 0; n < gridW; ++n) { - if (!(enableSkip && skipBitmap->getPixel(n, m))) { - patternBitmap = patternDict->getBitmap(grayImg[i]); - bitmap->combine(patternBitmap, xx >> 8, yy >> 8, combOp); - } - xx += stepX; - yy -= stepY; - ++i; - } - } - - gfree(grayImg); - - // combine the region bitmap into the page bitmap - if (imm) { - if (pageH == 0xffffffff && y + h > curPageH) { - pageBitmap->expand(y + h, pageDefPixel); - } - pageBitmap->combine(bitmap, x, y, extCombOp); - delete bitmap; - - // store the region bitmap - } else { - segments->append(bitmap); - } - - return; - - eofError: - error(getPos(), "Unexpected EOF in JBIG2 stream"); -} - -void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm, - GBool /*lossless*/, Guint length) { - JBIG2Bitmap *bitmap; - Guint w, h, x, y, segInfoFlags, extCombOp; - Guint flags, mmr, templ, tpgdOn; - int atx[4], aty[4]; - - // region segment info field - if (!readULong(&w) || !readULong(&h) || - !readULong(&x) || !readULong(&y) || - !readUByte(&segInfoFlags)) { - goto eofError; - } - extCombOp = segInfoFlags & 7; - - // rest of the generic region segment header - if (!readUByte(&flags)) { - goto eofError; - } - mmr = flags & 1; - templ = (flags >> 1) & 3; - tpgdOn = (flags >> 3) & 1; - - // AT flags - if (!mmr) { - if (templ == 0) { - if (!readByte(&atx[0]) || - !readByte(&aty[0]) || - !readByte(&atx[1]) || - !readByte(&aty[1]) || - !readByte(&atx[2]) || - !readByte(&aty[2]) || - !readByte(&atx[3]) || - !readByte(&aty[3])) { - goto eofError; - } - } else { - if (!readByte(&atx[0]) || - !readByte(&aty[0])) { - goto eofError; - } - } - } - - // set up the arithmetic decoder - if (!mmr) { - resetGenericStats(templ, NULL); - arithDecoder->start(); - } - - // read the bitmap - bitmap = readGenericBitmap(mmr, w, h, templ, tpgdOn, gFalse, - NULL, atx, aty, mmr ? 0 : length - 18); - - // combine the region bitmap into the page bitmap - if (imm) { - if (pageH == 0xffffffff && y + h > curPageH) { - pageBitmap->expand(y + h, pageDefPixel); - } - pageBitmap->combine(bitmap, x, y, extCombOp); - delete bitmap; - - // store the region bitmap - } else { - bitmap->setSegNum(segNum); - segments->append(bitmap); - } - - return; - - eofError: - error(getPos(), "Unexpected EOF in JBIG2 stream"); -} - -JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, - int templ, GBool tpgdOn, - GBool useSkip, JBIG2Bitmap *skip, - int *atx, int *aty, - int mmrDataLength) { - JBIG2Bitmap *bitmap; - GBool ltp; - Guint ltpCX, cx, cx0, cx1, cx2; - JBIG2BitmapPtr cxPtr0, cxPtr1; - JBIG2BitmapPtr atPtr0, atPtr1, atPtr2, atPtr3; - int *refLine, *codingLine; - int code1, code2, code3; - int x, y, a0, pix, i, refI, codingI; - - bitmap = new JBIG2Bitmap(0, w, h); - bitmap->clearToZero(); - - //----- MMR decode - - if (mmr) { - - mmrDecoder->reset(); - refLine = (int *)gmallocn(w + 2, sizeof(int)); - codingLine = (int *)gmallocn(w + 2, sizeof(int)); - codingLine[0] = codingLine[1] = w; - - for (y = 0; y < h; ++y) { - - // copy coding line to ref line - for (i = 0; codingLine[i] < w; ++i) { - refLine[i] = codingLine[i]; - } - refLine[i] = refLine[i + 1] = w; - - // decode a line - refI = 0; // b1 = refLine[refI] - codingI = 0; // a1 = codingLine[codingI] - a0 = 0; - do { - code1 = mmrDecoder->get2DCode(); - switch (code1) { - case twoDimPass: - if (refLine[refI] < w) { - a0 = refLine[refI + 1]; - refI += 2; - } - break; - case twoDimHoriz: - if (codingI & 1) { - code1 = 0; - do { - code1 += code3 = mmrDecoder->getBlackCode(); - } while (code3 >= 64); - code2 = 0; - do { - code2 += code3 = mmrDecoder->getWhiteCode(); - } while (code3 >= 64); - } else { - code1 = 0; - do { - code1 += code3 = mmrDecoder->getWhiteCode(); - } while (code3 >= 64); - code2 = 0; - do { - code2 += code3 = mmrDecoder->getBlackCode(); - } while (code3 >= 64); - } - if (code1 > 0 || code2 > 0) { - a0 = codingLine[codingI++] = a0 + code1; - a0 = codingLine[codingI++] = a0 + code2; - while (refLine[refI] <= a0 && refLine[refI] < w) { - refI += 2; - } - } - break; - case twoDimVert0: - a0 = codingLine[codingI++] = refLine[refI]; - if (refLine[refI] < w) { - ++refI; - } - break; - case twoDimVertR1: - a0 = codingLine[codingI++] = refLine[refI] + 1; - if (refLine[refI] < w) { - ++refI; - while (refLine[refI] <= a0 && refLine[refI] < w) { - refI += 2; - } - } - break; - case twoDimVertR2: - a0 = codingLine[codingI++] = refLine[refI] + 2; - if (refLine[refI] < w) { - ++refI; - while (refLine[refI] <= a0 && refLine[refI] < w) { - refI += 2; - } - } - break; - case twoDimVertR3: - a0 = codingLine[codingI++] = refLine[refI] + 3; - if (refLine[refI] < w) { - ++refI; - while (refLine[refI] <= a0 && refLine[refI] < w) { - refI += 2; - } - } - break; - case twoDimVertL1: - a0 = codingLine[codingI++] = refLine[refI] - 1; - if (refI > 0) { - --refI; - } else { - ++refI; - } - while (refLine[refI] <= a0 && refLine[refI] < w) { - refI += 2; - } - break; - case twoDimVertL2: - a0 = codingLine[codingI++] = refLine[refI] - 2; - if (refI > 0) { - --refI; - } else { - ++refI; - } - while (refLine[refI] <= a0 && refLine[refI] < w) { - refI += 2; - } - break; - case twoDimVertL3: - a0 = codingLine[codingI++] = refLine[refI] - 3; - if (refI > 0) { - --refI; - } else { - ++refI; - } - while (refLine[refI] <= a0 && refLine[refI] < w) { - refI += 2; - } - break; - default: - error(getPos(), "Illegal code in JBIG2 MMR bitmap data"); - break; - } - } while (a0 < w); - codingLine[codingI++] = w; - - // convert the run lengths to a bitmap line - i = 0; - while (codingLine[i] < w) { - for (x = codingLine[i]; x < codingLine[i+1]; ++x) { - bitmap->setPixel(x, y); - } - i += 2; - } - } - - if (mmrDataLength >= 0) { - mmrDecoder->skipTo(mmrDataLength); - } else { - if (mmrDecoder->get24Bits() != 0x001001) { - error(getPos(), "Missing EOFB in JBIG2 MMR bitmap data"); - } - } - - gfree(refLine); - gfree(codingLine); - - //----- arithmetic decode - - } else { - // set up the typical row context - ltpCX = 0; // make gcc happy - if (tpgdOn) { - switch (templ) { - case 0: - ltpCX = 0x3953; // 001 11001 0101 0011 - break; - case 1: - ltpCX = 0x079a; // 0011 11001 101 0 - break; - case 2: - ltpCX = 0x0e3; // 001 1100 01 1 - break; - case 3: - ltpCX = 0x18a; // 01100 0101 1 - break; - } - } - - ltp = 0; - cx = cx0 = cx1 = cx2 = 0; // make gcc happy - for (y = 0; y < h; ++y) { - - // check for a "typical" (duplicate) row - if (tpgdOn) { - if (arithDecoder->decodeBit(ltpCX, genericRegionStats)) { - ltp = !ltp; - } - if (ltp) { - bitmap->duplicateRow(y, y-1); - continue; - } - } - - switch (templ) { - case 0: - - // set up the context - bitmap->getPixelPtr(0, y-2, &cxPtr0); - cx0 = bitmap->nextPixel(&cxPtr0); - cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); - bitmap->getPixelPtr(0, y-1, &cxPtr1); - cx1 = bitmap->nextPixel(&cxPtr1); - cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); - cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); - cx2 = 0; - bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); - bitmap->getPixelPtr(atx[1], y + aty[1], &atPtr1); - bitmap->getPixelPtr(atx[2], y + aty[2], &atPtr2); - bitmap->getPixelPtr(atx[3], y + aty[3], &atPtr3); - - // decode the row - for (x = 0; x < w; ++x) { - - // build the context - cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) | - (bitmap->nextPixel(&atPtr0) << 3) | - (bitmap->nextPixel(&atPtr1) << 2) | - (bitmap->nextPixel(&atPtr2) << 1) | - bitmap->nextPixel(&atPtr3); - - // check for a skipped pixel - if (useSkip && skip->getPixel(x, y)) { - pix = 0; - - // decode the pixel - } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { - bitmap->setPixel(x, y); - } - - // update the context - cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07; - cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; - cx2 = ((cx2 << 1) | pix) & 0x0f; - } - break; - - case 1: - - // set up the context - bitmap->getPixelPtr(0, y-2, &cxPtr0); - cx0 = bitmap->nextPixel(&cxPtr0); - cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); - cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); - bitmap->getPixelPtr(0, y-1, &cxPtr1); - cx1 = bitmap->nextPixel(&cxPtr1); - cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); - cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); - cx2 = 0; - bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); - - // decode the row - for (x = 0; x < w; ++x) { - - // build the context - cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) | - bitmap->nextPixel(&atPtr0); - - // check for a skipped pixel - if (useSkip && skip->getPixel(x, y)) { - pix = 0; - - // decode the pixel - } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { - bitmap->setPixel(x, y); - } - - // update the context - cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x0f; - cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; - cx2 = ((cx2 << 1) | pix) & 0x07; - } - break; - - case 2: - - // set up the context - bitmap->getPixelPtr(0, y-2, &cxPtr0); - cx0 = bitmap->nextPixel(&cxPtr0); - cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); - bitmap->getPixelPtr(0, y-1, &cxPtr1); - cx1 = bitmap->nextPixel(&cxPtr1); - cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); - cx2 = 0; - bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); - - // decode the row - for (x = 0; x < w; ++x) { - - // build the context - cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) | - bitmap->nextPixel(&atPtr0); - - // check for a skipped pixel - if (useSkip && skip->getPixel(x, y)) { - pix = 0; - - // decode the pixel - } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { - bitmap->setPixel(x, y); - } - - // update the context - cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07; - cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x0f; - cx2 = ((cx2 << 1) | pix) & 0x03; - } - break; - - case 3: - - // set up the context - bitmap->getPixelPtr(0, y-1, &cxPtr1); - cx1 = bitmap->nextPixel(&cxPtr1); - cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); - cx2 = 0; - bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); - - // decode the row - for (x = 0; x < w; ++x) { - - // build the context - cx = (cx1 << 5) | (cx2 << 1) | - bitmap->nextPixel(&atPtr0); - - // check for a skipped pixel - if (useSkip && skip->getPixel(x, y)) { - pix = 0; - - // decode the pixel - } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { - bitmap->setPixel(x, y); - } - - // update the context - cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; - cx2 = ((cx2 << 1) | pix) & 0x0f; - } - break; - } - } - } - - return bitmap; -} - -void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm, - GBool /*lossless*/, Guint /*length*/, - Guint *refSegs, - Guint nRefSegs) { - JBIG2Bitmap *bitmap, *refBitmap; - Guint w, h, x, y, segInfoFlags, extCombOp; - Guint flags, templ, tpgrOn; - int atx[2], aty[2]; - JBIG2Segment *seg; - - // region segment info field - if (!readULong(&w) || !readULong(&h) || - !readULong(&x) || !readULong(&y) || - !readUByte(&segInfoFlags)) { - goto eofError; - } - extCombOp = segInfoFlags & 7; - - // rest of the generic refinement region segment header - if (!readUByte(&flags)) { - goto eofError; - } - templ = flags & 1; - tpgrOn = (flags >> 1) & 1; - - // AT flags - if (!templ) { - if (!readByte(&atx[0]) || !readByte(&aty[0]) || - !readByte(&atx[1]) || !readByte(&aty[1])) { - goto eofError; - } - } - - // resize the page bitmap if needed - if (nRefSegs == 0 || imm) { - if (pageH == 0xffffffff && y + h > curPageH) { - pageBitmap->expand(y + h, pageDefPixel); - } - } - - // get referenced bitmap - if (nRefSegs > 1) { - error(getPos(), "Bad reference in JBIG2 generic refinement segment"); - return; - } - if (nRefSegs == 1) { - seg = findSegment(refSegs[0]); - if (seg->getType() != jbig2SegBitmap) { - error(getPos(), "Bad bitmap reference in JBIG2 generic refinement segment"); - return; - } - refBitmap = (JBIG2Bitmap *)seg; - } else { - refBitmap = pageBitmap->getSlice(x, y, w, h); - } - - // set up the arithmetic decoder - resetRefinementStats(templ, NULL); - arithDecoder->start(); - - // read - bitmap = readGenericRefinementRegion(w, h, templ, tpgrOn, - refBitmap, 0, 0, atx, aty); - - // combine the region bitmap into the page bitmap - if (imm) { - pageBitmap->combine(bitmap, x, y, extCombOp); - delete bitmap; - - // store the region bitmap - } else { - bitmap->setSegNum(segNum); - segments->append(bitmap); - } - - // delete the referenced bitmap - if (nRefSegs == 1) { - discardSegment(refSegs[0]); - } else { - delete refBitmap; - } - - return; - - eofError: - error(getPos(), "Unexpected EOF in JBIG2 stream"); -} - -JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h, - int templ, GBool tpgrOn, - JBIG2Bitmap *refBitmap, - int refDX, int refDY, - int *atx, int *aty) { - JBIG2Bitmap *bitmap; - GBool ltp; - Guint ltpCX, cx, cx0, cx2, cx3, cx4, tpgrCX0, tpgrCX1, tpgrCX2; - JBIG2BitmapPtr cxPtr0, cxPtr1, cxPtr2, cxPtr3, cxPtr4, cxPtr5, cxPtr6; - JBIG2BitmapPtr tpgrCXPtr0, tpgrCXPtr1, tpgrCXPtr2; - int x, y, pix; - - if (w < 0 || h <= 0 || w >= INT_MAX / h) - return NULL; - - bitmap = new JBIG2Bitmap(0, w, h); - bitmap->clearToZero(); - - // set up the typical row context - if (templ) { - ltpCX = 0x008; - } else { - ltpCX = 0x0010; - } - - ltp = 0; - for (y = 0; y < h; ++y) { - - if (templ) { - - // set up the context - bitmap->getPixelPtr(0, y-1, &cxPtr0); - cx0 = bitmap->nextPixel(&cxPtr0); - bitmap->getPixelPtr(-1, y, &cxPtr1); - refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2); - refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3); - cx3 = refBitmap->nextPixel(&cxPtr3); - cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3); - refBitmap->getPixelPtr(-refDX, y+1-refDY, &cxPtr4); - cx4 = refBitmap->nextPixel(&cxPtr4); - - // set up the typical prediction context - tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy - if (tpgrOn) { - refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0); - tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0); - tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); - tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); - refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1); - tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1); - tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); - tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); - refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2); - tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2); - tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); - tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); - } - - for (x = 0; x < w; ++x) { - - // update the context - cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 7; - cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7; - cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 3; - - if (tpgrOn) { - // update the typical predictor context - tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7; - tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7; - tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7; - - // check for a "typical" pixel - if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) { - ltp = !ltp; - } - if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) { - bitmap->clearPixel(x, y); - continue; - } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) { - bitmap->setPixel(x, y); - continue; - } - } - - // build the context - cx = (cx0 << 7) | (bitmap->nextPixel(&cxPtr1) << 6) | - (refBitmap->nextPixel(&cxPtr2) << 5) | - (cx3 << 2) | cx4; - - // decode the pixel - if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) { - bitmap->setPixel(x, y); - } - } - - } else { - - // set up the context - bitmap->getPixelPtr(0, y-1, &cxPtr0); - cx0 = bitmap->nextPixel(&cxPtr0); - bitmap->getPixelPtr(-1, y, &cxPtr1); - refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2); - cx2 = refBitmap->nextPixel(&cxPtr2); - refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3); - cx3 = refBitmap->nextPixel(&cxPtr3); - cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3); - refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &cxPtr4); - cx4 = refBitmap->nextPixel(&cxPtr4); - cx4 = (cx4 << 1) | refBitmap->nextPixel(&cxPtr4); - bitmap->getPixelPtr(atx[0], y+aty[0], &cxPtr5); - refBitmap->getPixelPtr(atx[1]-refDX, y+aty[1]-refDY, &cxPtr6); - - // set up the typical prediction context - tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy - if (tpgrOn) { - refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0); - tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0); - tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); - tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); - refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1); - tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1); - tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); - tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); - refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2); - tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2); - tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); - tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); - } - - for (x = 0; x < w; ++x) { - - // update the context - cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 3; - cx2 = ((cx2 << 1) | refBitmap->nextPixel(&cxPtr2)) & 3; - cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7; - cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 7; - - if (tpgrOn) { - // update the typical predictor context - tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7; - tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7; - tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7; - - // check for a "typical" pixel - if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) { - ltp = !ltp; - } - if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) { - bitmap->clearPixel(x, y); - continue; - } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) { - bitmap->setPixel(x, y); - continue; - } - } - - // build the context - cx = (cx0 << 11) | (bitmap->nextPixel(&cxPtr1) << 10) | - (cx2 << 8) | (cx3 << 5) | (cx4 << 2) | - (bitmap->nextPixel(&cxPtr5) << 1) | - refBitmap->nextPixel(&cxPtr6); - - // decode the pixel - if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) { - bitmap->setPixel(x, y); - } - } - } - } - - return bitmap; -} - -void JBIG2Stream::readPageInfoSeg(Guint /*length*/) { - Guint xRes, yRes, flags, striping; - - if (!readULong(&pageW) || !readULong(&pageH) || - !readULong(&xRes) || !readULong(&yRes) || - !readUByte(&flags) || !readUWord(&striping)) { - goto eofError; - } - pageDefPixel = (flags >> 2) & 1; - defCombOp = (flags >> 3) & 3; - - // allocate the page bitmap - if (pageH == 0xffffffff) { - curPageH = striping & 0x7fff; - } else { - curPageH = pageH; - } - pageBitmap = new JBIG2Bitmap(0, pageW, curPageH); - - // default pixel value - if (pageDefPixel) { - pageBitmap->clearToOne(); - } else { - pageBitmap->clearToZero(); - } - - return; - - eofError: - error(getPos(), "Unexpected EOF in JBIG2 stream"); -} - -void JBIG2Stream::readEndOfStripeSeg(Guint length) { - Guint i; - - // skip the segment - for (i = 0; i < length; ++i) { - curStr->getChar(); - } -} - -void JBIG2Stream::readProfilesSeg(Guint length) { - Guint i; - - // skip the segment - for (i = 0; i < length; ++i) { - curStr->getChar(); - } -} - -void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint /*length*/) { - JBIG2HuffmanTable *huffTab; - Guint flags, oob, prefixBits, rangeBits; - int lowVal, highVal, val; - Guint huffTabSize, i; - - if (!readUByte(&flags) || !readLong(&lowVal) || !readLong(&highVal)) { - goto eofError; - } - oob = flags & 1; - prefixBits = ((flags >> 1) & 7) + 1; - rangeBits = ((flags >> 4) & 7) + 1; - - huffDecoder->reset(); - huffTabSize = 8; - huffTab = (JBIG2HuffmanTable *) - gmallocn(huffTabSize, sizeof(JBIG2HuffmanTable)); - i = 0; - val = lowVal; - while (val < highVal) { - if (i == huffTabSize) { - huffTabSize *= 2; - huffTab = (JBIG2HuffmanTable *) - greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); - } - huffTab[i].val = val; - huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); - huffTab[i].rangeLen = huffDecoder->readBits(rangeBits); - val += 1 << huffTab[i].rangeLen; - ++i; - } - if (i + oob + 3 > huffTabSize) { - huffTabSize = i + oob + 3; - huffTab = (JBIG2HuffmanTable *) - greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); - } - huffTab[i].val = lowVal - 1; - huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); - huffTab[i].rangeLen = jbig2HuffmanLOW; - ++i; - huffTab[i].val = highVal; - huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); - huffTab[i].rangeLen = 32; - ++i; - if (oob) { - huffTab[i].val = 0; - huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); - huffTab[i].rangeLen = jbig2HuffmanOOB; - ++i; - } - huffTab[i].val = 0; - huffTab[i].prefixLen = 0; - huffTab[i].rangeLen = jbig2HuffmanEOT; - huffDecoder->buildTable(huffTab, i); - - // create and store the new table segment - segments->append(new JBIG2CodeTable(segNum, huffTab)); - - return; - - eofError: - error(getPos(), "Unexpected EOF in JBIG2 stream"); -} - -void JBIG2Stream::readExtensionSeg(Guint length) { - Guint i; - - // skip the segment - for (i = 0; i < length; ++i) { - curStr->getChar(); - } -} - -JBIG2Segment *JBIG2Stream::findSegment(Guint segNum) { - JBIG2Segment *seg; - int i; - - for (i = 0; i < globalSegments->getLength(); ++i) { - seg = (JBIG2Segment *)globalSegments->get(i); - if (seg->getSegNum() == segNum) { - return seg; - } - } - for (i = 0; i < segments->getLength(); ++i) { - seg = (JBIG2Segment *)segments->get(i); - if (seg->getSegNum() == segNum) { - return seg; - } - } - return NULL; -} - -void JBIG2Stream::discardSegment(Guint segNum) { - JBIG2Segment *seg; - int i; - - for (i = 0; i < globalSegments->getLength(); ++i) { - seg = (JBIG2Segment *)globalSegments->get(i); - if (seg->getSegNum() == segNum) { - globalSegments->del(i); - return; - } - } - for (i = 0; i < segments->getLength(); ++i) { - seg = (JBIG2Segment *)segments->get(i); - if (seg->getSegNum() == segNum) { - segments->del(i); - return; - } - } -} - -void JBIG2Stream::resetGenericStats(Guint templ, - JArithmeticDecoderStats *prevStats) { - int size; - - size = contextSize[templ]; - if (prevStats && prevStats->getContextSize() == size) { - if (genericRegionStats->getContextSize() == size) { - genericRegionStats->copyFrom(prevStats); - } else { - delete genericRegionStats; - genericRegionStats = prevStats->copy(); - } - } else { - if (genericRegionStats->getContextSize() == size) { - genericRegionStats->reset(); - } else { - delete genericRegionStats; - genericRegionStats = new JArithmeticDecoderStats(1 << size); - } - } -} - -void JBIG2Stream::resetRefinementStats(Guint templ, - JArithmeticDecoderStats *prevStats) { - int size; - - size = refContextSize[templ]; - if (prevStats && prevStats->getContextSize() == size) { - if (refinementRegionStats->getContextSize() == size) { - refinementRegionStats->copyFrom(prevStats); - } else { - delete refinementRegionStats; - refinementRegionStats = prevStats->copy(); - } - } else { - if (refinementRegionStats->getContextSize() == size) { - refinementRegionStats->reset(); - } else { - delete refinementRegionStats; - refinementRegionStats = new JArithmeticDecoderStats(1 << size); - } - } -} - -void JBIG2Stream::resetIntStats(int symCodeLen) { - iadhStats->reset(); - iadwStats->reset(); - iaexStats->reset(); - iaaiStats->reset(); - iadtStats->reset(); - iaitStats->reset(); - iafsStats->reset(); - iadsStats->reset(); - iardxStats->reset(); - iardyStats->reset(); - iardwStats->reset(); - iardhStats->reset(); - iariStats->reset(); - if (iaidStats->getContextSize() == symCodeLen + 1) { - iaidStats->reset(); - } else { - delete iaidStats; - iaidStats = new JArithmeticDecoderStats(1 << (symCodeLen + 1)); - } -} - -GBool JBIG2Stream::readUByte(Guint *x) { - int c0; - - if ((c0 = curStr->getChar()) == EOF) { - return gFalse; - } - *x = (Guint)c0; - return gTrue; -} - -GBool JBIG2Stream::readByte(int *x) { - int c0; - - if ((c0 = curStr->getChar()) == EOF) { - return gFalse; - } - *x = c0; - if (c0 & 0x80) { - *x |= -1 - 0xff; - } - return gTrue; -} - -GBool JBIG2Stream::readUWord(Guint *x) { - int c0, c1; - - if ((c0 = curStr->getChar()) == EOF || - (c1 = curStr->getChar()) == EOF) { - return gFalse; - } - *x = (Guint)((c0 << 8) | c1); - return gTrue; -} - -GBool JBIG2Stream::readULong(Guint *x) { - int c0, c1, c2, c3; - - if ((c0 = curStr->getChar()) == EOF || - (c1 = curStr->getChar()) == EOF || - (c2 = curStr->getChar()) == EOF || - (c3 = curStr->getChar()) == EOF) { - return gFalse; - } - *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); - return gTrue; -} - -GBool JBIG2Stream::readLong(int *x) { - int c0, c1, c2, c3; - - if ((c0 = curStr->getChar()) == EOF || - (c1 = curStr->getChar()) == EOF || - (c2 = curStr->getChar()) == EOF || - (c3 = curStr->getChar()) == EOF) { - return gFalse; - } - *x = ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); - if (c0 & 0x80) { - *x |= -1 - (int)0xffffffff; - } - return gTrue; -} diff --git a/xpdf/xpdf/JBIG2Stream.h b/xpdf/xpdf/JBIG2Stream.h deleted file mode 100644 index d7a538b8f..000000000 --- a/xpdf/xpdf/JBIG2Stream.h +++ /dev/null @@ -1,143 +0,0 @@ -//======================================================================== -// -// JBIG2Stream.h -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef JBIG2STREAM_H -#define JBIG2STREAM_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "Object.h" -#include "Stream.h" - -class GList; -class JBIG2Segment; -class JBIG2Bitmap; -class JArithmeticDecoder; -class JArithmeticDecoderStats; -class JBIG2HuffmanDecoder; -struct JBIG2HuffmanTable; -class JBIG2MMRDecoder; - -//------------------------------------------------------------------------ - -class JBIG2Stream: public FilterStream { -public: - - JBIG2Stream(Stream *strA, Object *globalsStream); - virtual ~JBIG2Stream(); - virtual StreamKind getKind() { return strJBIG2; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - void readSegments(); - GBool readSymbolDictSeg(Guint segNum, Guint length, - Guint *refSegs, Guint nRefSegs); - void readTextRegionSeg(Guint segNum, GBool imm, - GBool lossless, Guint length, - Guint *refSegs, Guint nRefSegs); - JBIG2Bitmap *readTextRegion(GBool huff, GBool refine, - int w, int h, - Guint numInstances, - Guint logStrips, - int numSyms, - JBIG2HuffmanTable *symCodeTab, - Guint symCodeLen, - JBIG2Bitmap **syms, - Guint defPixel, Guint combOp, - Guint transposed, Guint refCorner, - int sOffset, - JBIG2HuffmanTable *huffFSTable, - JBIG2HuffmanTable *huffDSTable, - JBIG2HuffmanTable *huffDTTable, - JBIG2HuffmanTable *huffRDWTable, - JBIG2HuffmanTable *huffRDHTable, - JBIG2HuffmanTable *huffRDXTable, - JBIG2HuffmanTable *huffRDYTable, - JBIG2HuffmanTable *huffRSizeTable, - Guint templ, - int *atx, int *aty); - void readPatternDictSeg(Guint segNum, Guint length); - void readHalftoneRegionSeg(Guint segNum, GBool imm, - GBool lossless, Guint length, - Guint *refSegs, Guint nRefSegs); - void readGenericRegionSeg(Guint segNum, GBool imm, - GBool lossless, Guint length); - JBIG2Bitmap *readGenericBitmap(GBool mmr, int w, int h, - int templ, GBool tpgdOn, - GBool useSkip, JBIG2Bitmap *skip, - int *atx, int *aty, - int mmrDataLength); - void readGenericRefinementRegionSeg(Guint segNum, GBool imm, - GBool lossless, Guint length, - Guint *refSegs, - Guint nRefSegs); - JBIG2Bitmap *readGenericRefinementRegion(int w, int h, - int templ, GBool tpgrOn, - JBIG2Bitmap *refBitmap, - int refDX, int refDY, - int *atx, int *aty); - void readPageInfoSeg(Guint length); - void readEndOfStripeSeg(Guint length); - void readProfilesSeg(Guint length); - void readCodeTableSeg(Guint segNum, Guint length); - void readExtensionSeg(Guint length); - JBIG2Segment *findSegment(Guint segNum); - void discardSegment(Guint segNum); - void resetGenericStats(Guint templ, - JArithmeticDecoderStats *prevStats); - void resetRefinementStats(Guint templ, - JArithmeticDecoderStats *prevStats); - void resetIntStats(int symCodeLen); - GBool readUByte(Guint *x); - GBool readByte(int *x); - GBool readUWord(Guint *x); - GBool readULong(Guint *x); - GBool readLong(int *x); - - Guint pageW, pageH, curPageH; - Guint pageDefPixel; - JBIG2Bitmap *pageBitmap; - Guint defCombOp; - GList *segments; // [JBIG2Segment] - GList *globalSegments; // [JBIG2Segment] - Stream *curStr; - Guchar *dataPtr; - Guchar *dataEnd; - - JArithmeticDecoder *arithDecoder; - JArithmeticDecoderStats *genericRegionStats; - JArithmeticDecoderStats *refinementRegionStats; - JArithmeticDecoderStats *iadhStats; - JArithmeticDecoderStats *iadwStats; - JArithmeticDecoderStats *iaexStats; - JArithmeticDecoderStats *iaaiStats; - JArithmeticDecoderStats *iadtStats; - JArithmeticDecoderStats *iaitStats; - JArithmeticDecoderStats *iafsStats; - JArithmeticDecoderStats *iadsStats; - JArithmeticDecoderStats *iardxStats; - JArithmeticDecoderStats *iardyStats; - JArithmeticDecoderStats *iardwStats; - JArithmeticDecoderStats *iardhStats; - JArithmeticDecoderStats *iariStats; - JArithmeticDecoderStats *iaidStats; - JBIG2HuffmanDecoder *huffDecoder; - JBIG2MMRDecoder *mmrDecoder; -}; - -#endif diff --git a/xpdf/xpdf/JPXStream.cc b/xpdf/xpdf/JPXStream.cc deleted file mode 100644 index f8dda64c9..000000000 --- a/xpdf/xpdf/JPXStream.cc +++ /dev/null @@ -1,2954 +0,0 @@ -//======================================================================== -// -// JPXStream.cc -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "gmem.h" -#include "Error.h" -#include "JArithmeticDecoder.h" -#include "JPXStream.h" - -//~ to do: -// - precincts -// - ROI -// - progression order changes -// - packed packet headers -// - support for palettes, channel maps, etc. -// - make sure all needed JP2/JPX subboxes are parsed (readBoxes) -// - can we assume that QCC segments must come after the QCD segment? -// - skip EPH markers (readTilePartData) -// - handle tilePartToEOC in readTilePartData -// - deal with multiple codeword segments (readTilePartData, -// readCodeBlockData) -// - progression orders 2, 3, and 4 -// - in coefficient decoding (readCodeBlockData): -// - termination pattern: terminate after every coding pass -// - error resilience segmentation symbol -// - selective arithmetic coding bypass -// - vertically causal context formation -// - coeffs longer than 31 bits (should just ignore the extra bits?) -// - handle boxes larger than 2^32 bytes -// - the fixed-point arithmetic won't handle 16-bit pixels - -//------------------------------------------------------------------------ - -// number of contexts for the arithmetic decoder -#define jpxNContexts 19 - -#define jpxContextSigProp 0 // 0 - 8: significance prop and cleanup -#define jpxContextSign 9 // 9 - 13: sign -#define jpxContextMagRef 14 // 14 -16: magnitude refinement -#define jpxContextRunLength 17 // cleanup: run length -#define jpxContextUniform 18 // cleanup: first signif coeff - -//------------------------------------------------------------------------ - -#define jpxPassSigProp 0 -#define jpxPassMagRef 1 -#define jpxPassCleanup 2 - -//------------------------------------------------------------------------ - -// arithmetic decoder context for the significance propagation and -// cleanup passes: -// [horiz][vert][diag][subband] -// where subband = 0 for HL -// = 1 for LH and LL -// = 2 for HH -static Guint sigPropContext[3][3][5][3] = { - {{{ 0, 0, 0 }, // horiz=0, vert=0, diag=0 - { 1, 1, 3 }, // horiz=0, vert=0, diag=1 - { 2, 2, 6 }, // horiz=0, vert=0, diag=2 - { 2, 2, 8 }, // horiz=0, vert=0, diag=3 - { 2, 2, 8 }}, // horiz=0, vert=0, diag=4 - {{ 5, 3, 1 }, // horiz=0, vert=1, diag=0 - { 6, 3, 4 }, // horiz=0, vert=1, diag=1 - { 6, 3, 7 }, // horiz=0, vert=1, diag=2 - { 6, 3, 8 }, // horiz=0, vert=1, diag=3 - { 6, 3, 8 }}, // horiz=0, vert=1, diag=4 - {{ 8, 4, 2 }, // horiz=0, vert=2, diag=0 - { 8, 4, 5 }, // horiz=0, vert=2, diag=1 - { 8, 4, 7 }, // horiz=0, vert=2, diag=2 - { 8, 4, 8 }, // horiz=0, vert=2, diag=3 - { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4 - {{{ 3, 5, 1 }, // horiz=1, vert=0, diag=0 - { 3, 6, 4 }, // horiz=1, vert=0, diag=1 - { 3, 6, 7 }, // horiz=1, vert=0, diag=2 - { 3, 6, 8 }, // horiz=1, vert=0, diag=3 - { 3, 6, 8 }}, // horiz=1, vert=0, diag=4 - {{ 7, 7, 2 }, // horiz=1, vert=1, diag=0 - { 7, 7, 5 }, // horiz=1, vert=1, diag=1 - { 7, 7, 7 }, // horiz=1, vert=1, diag=2 - { 7, 7, 8 }, // horiz=1, vert=1, diag=3 - { 7, 7, 8 }}, // horiz=1, vert=1, diag=4 - {{ 8, 7, 2 }, // horiz=1, vert=2, diag=0 - { 8, 7, 5 }, // horiz=1, vert=2, diag=1 - { 8, 7, 7 }, // horiz=1, vert=2, diag=2 - { 8, 7, 8 }, // horiz=1, vert=2, diag=3 - { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4 - {{{ 4, 8, 2 }, // horiz=2, vert=0, diag=0 - { 4, 8, 5 }, // horiz=2, vert=0, diag=1 - { 4, 8, 7 }, // horiz=2, vert=0, diag=2 - { 4, 8, 8 }, // horiz=2, vert=0, diag=3 - { 4, 8, 8 }}, // horiz=2, vert=0, diag=4 - {{ 7, 8, 2 }, // horiz=2, vert=1, diag=0 - { 7, 8, 5 }, // horiz=2, vert=1, diag=1 - { 7, 8, 7 }, // horiz=2, vert=1, diag=2 - { 7, 8, 8 }, // horiz=2, vert=1, diag=3 - { 7, 8, 8 }}, // horiz=2, vert=1, diag=4 - {{ 8, 8, 2 }, // horiz=2, vert=2, diag=0 - { 8, 8, 5 }, // horiz=2, vert=2, diag=1 - { 8, 8, 7 }, // horiz=2, vert=2, diag=2 - { 8, 8, 8 }, // horiz=2, vert=2, diag=3 - { 8, 8, 8 }}} // horiz=2, vert=2, diag=4 -}; - -// arithmetic decoder context and xor bit for the sign bit in the -// significance propagation pass: -// [horiz][vert][k] -// where horiz/vert are offset by 2 (i.e., range is -2 .. 2) -// and k = 0 for the context -// = 1 for the xor bit -static Guint signContext[5][5][2] = { - {{ 13, 1 }, // horiz=-2, vert=-2 - { 13, 1 }, // horiz=-2, vert=-1 - { 12, 1 }, // horiz=-2, vert= 0 - { 11, 1 }, // horiz=-2, vert=+1 - { 11, 1 }}, // horiz=-2, vert=+2 - {{ 13, 1 }, // horiz=-1, vert=-2 - { 13, 1 }, // horiz=-1, vert=-1 - { 12, 1 }, // horiz=-1, vert= 0 - { 11, 1 }, // horiz=-1, vert=+1 - { 11, 1 }}, // horiz=-1, vert=+2 - {{ 10, 1 }, // horiz= 0, vert=-2 - { 10, 1 }, // horiz= 0, vert=-1 - { 9, 0 }, // horiz= 0, vert= 0 - { 10, 0 }, // horiz= 0, vert=+1 - { 10, 0 }}, // horiz= 0, vert=+2 - {{ 11, 0 }, // horiz=+1, vert=-2 - { 11, 0 }, // horiz=+1, vert=-1 - { 12, 0 }, // horiz=+1, vert= 0 - { 13, 0 }, // horiz=+1, vert=+1 - { 13, 0 }}, // horiz=+1, vert=+2 - {{ 11, 0 }, // horiz=+2, vert=-2 - { 11, 0 }, // horiz=+2, vert=-1 - { 12, 0 }, // horiz=+2, vert= 0 - { 13, 0 }, // horiz=+2, vert=+1 - { 13, 0 }}, // horiz=+2, vert=+2 -}; - -//------------------------------------------------------------------------ - -// constants used in the IDWT -#define idwtAlpha -1.586134342059924 -#define idwtBeta -0.052980118572961 -#define idwtGamma 0.882911075530934 -#define idwtDelta 0.443506852043971 -#define idwtKappa 1.230174104914001 -#define idwtIKappa (1.0 / idwtKappa) - -// number of bits to the right of the decimal point for the fixed -// point arithmetic used in the IDWT -#define fracBits 16 - -//------------------------------------------------------------------------ - -// floor(x / y) -#define jpxFloorDiv(x, y) ((x) / (y)) - -// floor(x / 2^y) -#define jpxFloorDivPow2(x, y) ((x) >> (y)) - -// ceil(x / y) -#define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y)) - -// ceil(x / 2^y) -#define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y)) - -//------------------------------------------------------------------------ - -JPXStream::JPXStream(Stream *strA): - FilterStream(strA) -{ - nComps = 0; - bpc = NULL; - width = height = 0; - haveCS = gFalse; - havePalette = gFalse; - haveCompMap = gFalse; - haveChannelDefn = gFalse; - - img.tiles = NULL; - bitBuf = 0; - bitBufLen = 0; - bitBufSkip = gFalse; - byteCount = 0; -} - -JPXStream::~JPXStream() { - JPXTile *tile; - JPXTileComp *tileComp; - JPXResLevel *resLevel; - JPXPrecinct *precinct; - JPXSubband *subband; - JPXCodeBlock *cb; - Guint comp, i, k, r, pre, sb; - - gfree(bpc); - if (havePalette) { - gfree(palette.bpc); - gfree(palette.c); - } - if (haveCompMap) { - gfree(compMap.comp); - gfree(compMap.type); - gfree(compMap.pComp); - } - if (haveChannelDefn) { - gfree(channelDefn.idx); - gfree(channelDefn.type); - gfree(channelDefn.assoc); - } - - if (img.tiles) { - for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { - tile = &img.tiles[i]; - if (tile->tileComps) { - for (comp = 0; comp < img.nComps; ++comp) { - tileComp = &tile->tileComps[comp]; - gfree(tileComp->quantSteps); - gfree(tileComp->data); - gfree(tileComp->buf); - if (tileComp->resLevels) { - for (r = 0; r <= tileComp->nDecompLevels; ++r) { - resLevel = &tileComp->resLevels[r]; - if (resLevel->precincts) { - for (pre = 0; pre < 1; ++pre) { - precinct = &resLevel->precincts[pre]; - if (precinct->subbands) { - for (sb = 0; sb < (r == 0 ? 1 : 3); ++sb) { - subband = &precinct->subbands[sb]; - gfree(subband->inclusion); - gfree(subband->zeroBitPlane); - if (subband->cbs) { - for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) { - cb = &subband->cbs[k]; - gfree(cb->coeffs); - if (cb->arithDecoder) { - delete cb->arithDecoder; - } - if (cb->stats) { - delete cb->stats; - } - } - gfree(subband->cbs); - } - } - gfree(precinct->subbands); - } - } - gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts); - } - } - gfree(img.tiles[i].tileComps[comp].resLevels); - } - } - gfree(img.tiles[i].tileComps); - } - } - gfree(img.tiles); - } - delete str; -} - -void JPXStream::reset() { - str->reset(); - if (readBoxes()) { - curY = img.yOffset; - } else { - // readBoxes reported an error, so we go immediately to EOF - curY = img.ySize; - } - curX = img.xOffset; - curComp = 0; - readBufLen = 0; -} - -int JPXStream::getChar() { - int c; - - if (readBufLen < 8) { - fillReadBuf(); - } - if (readBufLen == 8) { - c = readBuf & 0xff; - readBufLen = 0; - } else if (readBufLen > 8) { - c = (readBuf >> (readBufLen - 8)) & 0xff; - readBufLen -= 8; - } else if (readBufLen == 0) { - c = EOF; - } else { - c = (readBuf << (8 - readBufLen)) & 0xff; - readBufLen = 0; - } - return c; -} - -int JPXStream::lookChar() { - int c; - - if (readBufLen < 8) { - fillReadBuf(); - } - if (readBufLen == 8) { - c = readBuf & 0xff; - } else if (readBufLen > 8) { - c = (readBuf >> (readBufLen - 8)) & 0xff; - } else if (readBufLen == 0) { - c = EOF; - } else { - c = (readBuf << (8 - readBufLen)) & 0xff; - } - return c; -} - -void JPXStream::fillReadBuf() { - JPXTileComp *tileComp; - Guint tileIdx, tx, ty; - int pix, pixBits; - - do { - if (curY >= img.ySize) { - return; - } - tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles - + (curX - img.xTileOffset) / img.xTileSize; -#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid - tileComp = &img.tiles[tileIdx].tileComps[curComp]; -#else - tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp]; -#endif - tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep); - ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep); - pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx]; - pixBits = tileComp->prec; -#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid - if (++curComp == img.nComps) { -#else - if (havePalette) { - if (pix >= 0 && pix < palette.nEntries) { - pix = palette.c[pix * palette.nComps + curComp]; - } else { - pix = - pixBits = palette.bpc[curComp]; - } - if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) { -#endif - curComp = 0; - if (++curX == img.xSize) { - curX = img.xOffset; - ++curY; - } - } - if (pixBits == 8) { - readBuf = (readBuf << 8) | (pix & 0xff); - } else { - readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1)); - } - readBufLen += pixBits; - } while (readBufLen < 8); -} - -GString *JPXStream::getPSFilter(int /*psLevel*/, const char */*indent*/) { - return NULL; -} - -GBool JPXStream::isBinary(GBool /*last*/) { - return str->isBinary(gTrue); -} - -void JPXStream::getImageParams(int *bitsPerComponent, - StreamColorSpaceMode *csMode) { - Guint boxType, boxLen, dataLen, csEnum; - Guint bpc1, dummy, i; - int csMeth, csPrec, csPrec1, dummy2; - StreamColorSpaceMode csMode1; - GBool haveBPC, haveCSMode; - - csPrec = 0; // make gcc happy - haveBPC = haveCSMode = gFalse; - str->reset(); - if (str->lookChar() == 0xff) { - getImageParams2(bitsPerComponent, csMode); - } else { - while (readBoxHdr(&boxType, &boxLen, &dataLen)) { - if (boxType == 0x6a703268) { // JP2 header - // skip the superbox - } else if (boxType == 0x69686472) { // image header - if (readULong(&dummy) && - readULong(&dummy) && - readUWord(&dummy) && - readUByte(&bpc1) && - readUByte(&dummy) && - readUByte(&dummy) && - readUByte(&dummy)) { - *bitsPerComponent = bpc1 + 1; - haveBPC = gTrue; - } - } else if (boxType == 0x636F6C72) { // color specification - if (readByte(&csMeth) && - readByte(&csPrec1) && - readByte(&dummy2)) { - if (csMeth == 1) { - if (readULong(&csEnum)) { - csMode1 = streamCSNone; - if (csEnum == jpxCSBiLevel || - csEnum == jpxCSGrayscale) { - csMode1 = streamCSDeviceGray; - } else if (csEnum == jpxCSCMYK) { - csMode1 = streamCSDeviceCMYK; - } else if (csEnum == jpxCSsRGB || - csEnum == jpxCSCISesRGB || - csEnum == jpxCSROMMRGB) { - csMode1 = streamCSDeviceRGB; - } - if (csMode1 != streamCSNone && - (!haveCSMode || csPrec1 > csPrec)) { - *csMode = csMode1; - csPrec = csPrec1; - haveCSMode = gTrue; - } - for (i = 0; i < dataLen - 7; ++i) { - str->getChar(); - } - } - } else { - for (i = 0; i < dataLen - 3; ++i) { - str->getChar(); - } - } - } - } else if (boxType == 0x6A703263) { // codestream - if (!(haveBPC && haveCSMode)) { - getImageParams2(bitsPerComponent, csMode); - } - break; - } else { - for (i = 0; i < dataLen; ++i) { - str->getChar(); - } - } - } - } - str->close(); -} - -// Get image parameters from the codestream. -void JPXStream::getImageParams2(int *bitsPerComponent, - StreamColorSpaceMode *csMode) { - int segType; - Guint segLen, nComps1, bpc1, dummy, i; - - while (readMarkerHdr(&segType, &segLen)) { - if (segType == 0x51) { // SIZ - image and tile size - if (readUWord(&dummy) && - readULong(&dummy) && - readULong(&dummy) && - readULong(&dummy) && - readULong(&dummy) && - readULong(&dummy) && - readULong(&dummy) && - readULong(&dummy) && - readULong(&dummy) && - readUWord(&nComps1) && - readUByte(&bpc1)) { - *bitsPerComponent = (bpc1 & 0x7f) + 1; - // if there's no color space info, take a guess - if (nComps1 == 1) { - *csMode = streamCSDeviceGray; - } else if (nComps1 == 3) { - *csMode = streamCSDeviceRGB; - } else if (nComps1 == 4) { - *csMode = streamCSDeviceCMYK; - } - } - break; - } else { - if (segLen > 2) { - for (i = 0; i < segLen - 2; ++i) { - str->getChar(); - } - } - } - } -} - -GBool JPXStream::readBoxes() { - Guint boxType, boxLen, dataLen; - Guint bpc1, compression, unknownColorspace, ipr; - Guint i, j; - - haveImgHdr = gFalse; - - // check for a naked JPEG 2000 codestream (without the JP2/JPX - // wrapper) -- this appears to be a violation of the PDF spec, but - // Acrobat allows it - if (str->lookChar() == 0xff) { - error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper"); - readCodestream(0); - nComps = img.nComps; - bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); - for (i = 0; i < nComps; ++i) { - bpc[i] = img.tiles[0].tileComps[i].prec; - } - width = img.xSize - img.xOffset; - height = img.ySize - img.yOffset; - return gTrue; - } - - while (readBoxHdr(&boxType, &boxLen, &dataLen)) { - switch (boxType) { - case 0x6a703268: // JP2 header - // this is a grouping box ('superbox') which has no real - // contents and doesn't appear to be used consistently, i.e., - // some things which should be subboxes of the JP2 header box - // show up outside of it - so we simply ignore the JP2 header - // box - break; - case 0x69686472: // image header - if (!readULong(&height) || - !readULong(&width) || - !readUWord(&nComps) || - !readUByte(&bpc1) || - !readUByte(&compression) || - !readUByte(&unknownColorspace) || - !readUByte(&ipr)) { - error(getPos(), "Unexpected EOF in JPX stream"); - return gFalse; - } - if (compression != 7) { - error(getPos(), "Unknown compression type in JPX stream"); - return gFalse; - } - bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); - for (i = 0; i < nComps; ++i) { - bpc[i] = bpc1; - } - haveImgHdr = gTrue; - break; - case 0x62706363: // bits per component - if (!haveImgHdr) { - error(getPos(), "Found bits per component box before image header box in JPX stream"); - return gFalse; - } - if (dataLen != nComps) { - error(getPos(), "Invalid bits per component box in JPX stream"); - return gFalse; - } - for (i = 0; i < nComps; ++i) { - if (!readUByte(&bpc[i])) { - error(getPos(), "Unexpected EOF in JPX stream"); - return gFalse; - } - } - break; - case 0x636F6C72: // color specification - if (!readColorSpecBox(dataLen)) { - return gFalse; - } - break; - case 0x70636c72: // palette - if (!readUWord(&palette.nEntries) || - !readUByte(&palette.nComps)) { - error(getPos(), "Unexpected EOF in JPX stream"); - return gFalse; - } - palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint)); - palette.c = - (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int)); - for (i = 0; i < palette.nComps; ++i) { - if (!readUByte(&palette.bpc[i])) { - error(getPos(), "Unexpected EOF in JPX stream"); - return gFalse; - } - ++palette.bpc[i]; - } - for (i = 0; i < palette.nEntries; ++i) { - for (j = 0; j < palette.nComps; ++j) { - if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3, - (palette.bpc[j] & 0x80) ? gTrue : gFalse, - &palette.c[i * palette.nComps + j])) { - error(getPos(), "Unexpected EOF in JPX stream"); - return gFalse; - } - } - } - havePalette = gTrue; - break; - case 0x636d6170: // component mapping - compMap.nChannels = dataLen / 4; - compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); - compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); - compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); - for (i = 0; i < compMap.nChannels; ++i) { - if (!readUWord(&compMap.comp[i]) || - !readUByte(&compMap.type[i]) || - !readUByte(&compMap.pComp[i])) { - error(getPos(), "Unexpected EOF in JPX stream"); - return gFalse; - } - } - haveCompMap = gTrue; - break; - case 0x63646566: // channel definition - if (!readUWord(&channelDefn.nChannels)) { - error(getPos(), "Unexpected EOF in JPX stream"); - return gFalse; - } - channelDefn.idx = - (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); - channelDefn.type = - (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); - channelDefn.assoc = - (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); - for (i = 0; i < channelDefn.nChannels; ++i) { - if (!readUWord(&channelDefn.idx[i]) || - !readUWord(&channelDefn.type[i]) || - !readUWord(&channelDefn.assoc[i])) { - error(getPos(), "Unexpected EOF in JPX stream"); - return gFalse; - } - } - haveChannelDefn = gTrue; - break; - case 0x6A703263: // contiguous codestream - if (!bpc) { - error(getPos(), "JPX stream is missing the image header box"); - } - if (!haveCS) { - error(getPos(), "JPX stream has no supported color spec"); - } - if (!readCodestream(dataLen)) { - return gFalse; - } - break; - default: - for (i = 0; i < dataLen; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Unexpected EOF in JPX stream"); - return gFalse; - } - } - break; - } - } - return gTrue; -} - -GBool JPXStream::readColorSpecBox(Guint dataLen) { - JPXColorSpec newCS; - Guint csApprox, csEnum; - Guint i; - GBool ok; - - ok = gFalse; - if (!readUByte(&newCS.meth) || - !readByte(&newCS.prec) || - !readUByte(&csApprox)) { - goto err; - } - switch (newCS.meth) { - case 1: // enumerated colorspace - if (!readULong(&csEnum)) { - goto err; - } - newCS.enumerated.type = (JPXColorSpaceType)csEnum; - switch (newCS.enumerated.type) { - case jpxCSBiLevel: - ok = gTrue; - break; - case jpxCSYCbCr1: - ok = gTrue; - break; - case jpxCSYCbCr2: - ok = gTrue; - break; - case jpxCSYCBCr3: - ok = gTrue; - break; - case jpxCSPhotoYCC: - ok = gTrue; - break; - case jpxCSCMY: - ok = gTrue; - break; - case jpxCSCMYK: - ok = gTrue; - break; - case jpxCSYCCK: - ok = gTrue; - break; - case jpxCSCIELab: - if (dataLen == 7 + 7*4) { - if (!readULong(&newCS.enumerated.cieLab.rl) || - !readULong(&newCS.enumerated.cieLab.ol) || - !readULong(&newCS.enumerated.cieLab.ra) || - !readULong(&newCS.enumerated.cieLab.oa) || - !readULong(&newCS.enumerated.cieLab.rb) || - !readULong(&newCS.enumerated.cieLab.ob) || - !readULong(&newCS.enumerated.cieLab.il)) { - goto err; - } - } else if (dataLen == 7) { - //~ this assumes the 8-bit case - newCS.enumerated.cieLab.rl = 100; - newCS.enumerated.cieLab.ol = 0; - newCS.enumerated.cieLab.ra = 255; - newCS.enumerated.cieLab.oa = 128; - newCS.enumerated.cieLab.rb = 255; - newCS.enumerated.cieLab.ob = 96; - newCS.enumerated.cieLab.il = 0x00443530; - } else { - goto err; - } - ok = gTrue; - break; - case jpxCSsRGB: - ok = gTrue; - break; - case jpxCSGrayscale: - ok = gTrue; - break; - case jpxCSBiLevel2: - ok = gTrue; - break; - case jpxCSCIEJab: - // not allowed in PDF - goto err; - case jpxCSCISesRGB: - ok = gTrue; - break; - case jpxCSROMMRGB: - ok = gTrue; - break; - case jpxCSsRGBYCbCr: - ok = gTrue; - break; - case jpxCSYPbPr1125: - ok = gTrue; - break; - case jpxCSYPbPr1250: - ok = gTrue; - break; - default: - goto err; - } - break; - case 2: // restricted ICC profile - case 3: // any ICC profile (JPX) - case 4: // vendor color (JPX) - for (i = 0; i < dataLen - 3; ++i) { - if (str->getChar() == EOF) { - goto err; - } - } - break; - } - - if (ok && (!haveCS || newCS.prec > cs.prec)) { - cs = newCS; - haveCS = gTrue; - } - - return gTrue; - - err: - error(getPos(), "Error in JPX color spec"); - return gFalse; -} - -GBool JPXStream::readCodestream(Guint /*len*/) { - JPXTile *tile; - JPXTileComp *tileComp; - int segType; - GBool haveSIZ, haveCOD, haveQCD, haveSOT; - Guint precinctSize, style; - Guint segLen, capabilities, nTiles, comp, i, j, r; - - //----- main header - haveSIZ = haveCOD = haveQCD = haveSOT = gFalse; - do { - if (!readMarkerHdr(&segType, &segLen)) { - error(getPos(), "Error in JPX codestream"); - return gFalse; - } - switch (segType) { - case 0x4f: // SOC - start of codestream - // marker only - break; - case 0x51: // SIZ - image and tile size - if (!readUWord(&capabilities) || - !readULong(&img.xSize) || - !readULong(&img.ySize) || - !readULong(&img.xOffset) || - !readULong(&img.yOffset) || - !readULong(&img.xTileSize) || - !readULong(&img.yTileSize) || - !readULong(&img.xTileOffset) || - !readULong(&img.yTileOffset) || - !readUWord(&img.nComps)) { - error(getPos(), "Error in JPX SIZ marker segment"); - return gFalse; - } - if (haveImgHdr && img.nComps != nComps) { - error(getPos(), "Different number of components in JPX SIZ marker segment"); - return gFalse; - } - img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1) - / img.xTileSize; - img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1) - / img.yTileSize; - nTiles = img.nXTiles * img.nYTiles; - // check for overflow before allocating memory - if (img.nXTiles <= 0 || img.nYTiles <= 0 || img.nXTiles >= INT_MAX / img.nYTiles) { - error(getPos(), "Bad tile count in JPX SIZ marker segment"); - return gFalse; - } - img.tiles = (JPXTile *)gmallocn(nTiles, sizeof(JPXTile)); - for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { - img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps, - sizeof(JPXTileComp)); - for (comp = 0; comp < img.nComps; ++comp) { - img.tiles[i].tileComps[comp].quantSteps = NULL; - img.tiles[i].tileComps[comp].data = NULL; - img.tiles[i].tileComps[comp].buf = NULL; - img.tiles[i].tileComps[comp].resLevels = NULL; - } - } - for (comp = 0; comp < img.nComps; ++comp) { - if (!readUByte(&img.tiles[0].tileComps[comp].prec) || - !readUByte(&img.tiles[0].tileComps[comp].hSep) || - !readUByte(&img.tiles[0].tileComps[comp].vSep)) { - error(getPos(), "Error in JPX SIZ marker segment"); - return gFalse; - } - img.tiles[0].tileComps[comp].sgned = - (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse; - img.tiles[0].tileComps[comp].prec = - (img.tiles[0].tileComps[comp].prec & 0x7f) + 1; - for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { - img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp]; - } - } - haveSIZ = gTrue; - break; - case 0x52: // COD - coding style default - if (!readUByte(&img.tiles[0].tileComps[0].style) || - !readUByte(&img.tiles[0].progOrder) || - !readUWord(&img.tiles[0].nLayers) || - !readUByte(&img.tiles[0].multiComp) || - !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) || - !readUByte(&img.tiles[0].tileComps[0].codeBlockW) || - !readUByte(&img.tiles[0].tileComps[0].codeBlockH) || - !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) || - !readUByte(&img.tiles[0].tileComps[0].transform)) { - error(getPos(), "Error in JPX COD marker segment"); - return gFalse; - } - img.tiles[0].tileComps[0].codeBlockW += 2; - img.tiles[0].tileComps[0].codeBlockH += 2; - for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { - if (i != 0) { - img.tiles[i].progOrder = img.tiles[0].progOrder; - img.tiles[i].nLayers = img.tiles[0].nLayers; - img.tiles[i].multiComp = img.tiles[0].multiComp; - } - for (comp = 0; comp < img.nComps; ++comp) { - if (!(i == 0 && comp == 0)) { - img.tiles[i].tileComps[comp].style = - img.tiles[0].tileComps[0].style; - img.tiles[i].tileComps[comp].nDecompLevels = - img.tiles[0].tileComps[0].nDecompLevels; - img.tiles[i].tileComps[comp].codeBlockW = - img.tiles[0].tileComps[0].codeBlockW; - img.tiles[i].tileComps[comp].codeBlockH = - img.tiles[0].tileComps[0].codeBlockH; - img.tiles[i].tileComps[comp].codeBlockStyle = - img.tiles[0].tileComps[0].codeBlockStyle; - img.tiles[i].tileComps[comp].transform = - img.tiles[0].tileComps[0].transform; - } - img.tiles[i].tileComps[comp].resLevels = - (JPXResLevel *)gmallocn( - (img.tiles[i].tileComps[comp].nDecompLevels + 1), - sizeof(JPXResLevel)); - for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { - img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; - } - } - } - for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) { - if (img.tiles[0].tileComps[0].style & 0x01) { - if (!readUByte(&precinctSize)) { - error(getPos(), "Error in JPX COD marker segment"); - return gFalse; - } - img.tiles[0].tileComps[0].resLevels[r].precinctWidth = - precinctSize & 0x0f; - img.tiles[0].tileComps[0].resLevels[r].precinctHeight = - (precinctSize >> 4) & 0x0f; - } else { - img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15; - img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15; - } - } - for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { - for (comp = 0; comp < img.nComps; ++comp) { - if (!(i == 0 && comp == 0)) { - for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { - img.tiles[i].tileComps[comp].resLevels[r].precinctWidth = - img.tiles[0].tileComps[0].resLevels[r].precinctWidth; - img.tiles[i].tileComps[comp].resLevels[r].precinctHeight = - img.tiles[0].tileComps[0].resLevels[r].precinctHeight; - } - } - } - } - haveCOD = gTrue; - break; - case 0x53: // COC - coding style component - if (!haveCOD) { - error(getPos(), "JPX COC marker segment before COD segment"); - return gFalse; - } - if ((img.nComps > 256 && !readUWord(&comp)) || - (img.nComps <= 256 && !readUByte(&comp)) || - comp >= img.nComps || - !readUByte(&style) || - !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) || - !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) || - !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) || - !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) || - !readUByte(&img.tiles[0].tileComps[comp].transform)) { - error(getPos(), "Error in JPX COC marker segment"); - return gFalse; - } - img.tiles[0].tileComps[comp].style = - (img.tiles[0].tileComps[comp].style & ~1) | (style & 1); - img.tiles[0].tileComps[comp].codeBlockW += 2; - img.tiles[0].tileComps[comp].codeBlockH += 2; - for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { - if (i != 0) { - img.tiles[i].tileComps[comp].style = - img.tiles[0].tileComps[comp].style; - img.tiles[i].tileComps[comp].nDecompLevels = - img.tiles[0].tileComps[comp].nDecompLevels; - img.tiles[i].tileComps[comp].codeBlockW = - img.tiles[0].tileComps[comp].codeBlockW; - img.tiles[i].tileComps[comp].codeBlockH = - img.tiles[0].tileComps[comp].codeBlockH; - img.tiles[i].tileComps[comp].codeBlockStyle = - img.tiles[0].tileComps[comp].codeBlockStyle; - img.tiles[i].tileComps[comp].transform = - img.tiles[0].tileComps[comp].transform; - } - img.tiles[i].tileComps[comp].resLevels = - (JPXResLevel *)greallocn( - img.tiles[i].tileComps[comp].resLevels, - (img.tiles[i].tileComps[comp].nDecompLevels + 1), - sizeof(JPXResLevel)); - for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { - img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; - } - } - for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) { - if (img.tiles[0].tileComps[comp].style & 0x01) { - if (!readUByte(&precinctSize)) { - error(getPos(), "Error in JPX COD marker segment"); - return gFalse; - } - img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = - precinctSize & 0x0f; - img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = - (precinctSize >> 4) & 0x0f; - } else { - img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15; - img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15; - } - } - for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { - for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { - img.tiles[i].tileComps[comp].resLevels[r].precinctWidth = - img.tiles[0].tileComps[comp].resLevels[r].precinctWidth; - img.tiles[i].tileComps[comp].resLevels[r].precinctHeight = - img.tiles[0].tileComps[comp].resLevels[r].precinctHeight; - } - } - break; - case 0x5c: // QCD - quantization default - if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) { - img.tiles[0].tileComps[0].nQuantSteps = segLen - 3; - img.tiles[0].tileComps[0].quantSteps = - (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, - img.tiles[0].tileComps[0].nQuantSteps, - sizeof(Guint)); - for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { - if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - } - } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) { - img.tiles[0].tileComps[0].nQuantSteps = 1; - img.tiles[0].tileComps[0].quantSteps = - (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, - img.tiles[0].tileComps[0].nQuantSteps, - sizeof(Guint)); - if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) { - img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2; - img.tiles[0].tileComps[0].quantSteps = - (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, - img.tiles[0].tileComps[0].nQuantSteps, - sizeof(Guint)); - for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { - if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - } - } else { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { - for (comp = 0; comp < img.nComps; ++comp) { - if (!(i == 0 && comp == 0)) { - img.tiles[i].tileComps[comp].quantStyle = - img.tiles[0].tileComps[0].quantStyle; - img.tiles[i].tileComps[comp].nQuantSteps = - img.tiles[0].tileComps[0].nQuantSteps; - img.tiles[i].tileComps[comp].quantSteps = - (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, - img.tiles[0].tileComps[0].nQuantSteps, - sizeof(Guint)); - for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) { - img.tiles[i].tileComps[comp].quantSteps[j] = - img.tiles[0].tileComps[0].quantSteps[j]; - } - } - } - } - haveQCD = gTrue; - break; - case 0x5d: // QCC - quantization component - if (!haveQCD) { - error(getPos(), "JPX QCC marker segment before QCD segment"); - return gFalse; - } - if ((img.nComps > 256 && !readUWord(&comp)) || - (img.nComps <= 256 && !readUByte(&comp)) || - comp >= img.nComps || - !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) { - error(getPos(), "Error in JPX QCC marker segment"); - return gFalse; - } - if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) { - img.tiles[0].tileComps[comp].nQuantSteps = - segLen - (img.nComps > 256 ? 5 : 4); - img.tiles[0].tileComps[comp].quantSteps = - (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, - img.tiles[0].tileComps[comp].nQuantSteps, - sizeof(Guint)); - for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { - if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) { - error(getPos(), "Error in JPX QCC marker segment"); - return gFalse; - } - } - } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) { - img.tiles[0].tileComps[comp].nQuantSteps = 1; - img.tiles[0].tileComps[comp].quantSteps = - (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, - img.tiles[0].tileComps[comp].nQuantSteps, - sizeof(Guint)); - if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) { - error(getPos(), "Error in JPX QCC marker segment"); - return gFalse; - } - } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) { - img.tiles[0].tileComps[comp].nQuantSteps = - (segLen - (img.nComps > 256 ? 5 : 4)) / 2; - img.tiles[0].tileComps[comp].quantSteps = - (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, - img.tiles[0].tileComps[comp].nQuantSteps, - sizeof(Guint)); - for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { - if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - } - } else { - error(getPos(), "Error in JPX QCC marker segment"); - return gFalse; - } - for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { - img.tiles[i].tileComps[comp].quantStyle = - img.tiles[0].tileComps[comp].quantStyle; - img.tiles[i].tileComps[comp].nQuantSteps = - img.tiles[0].tileComps[comp].nQuantSteps; - img.tiles[i].tileComps[comp].quantSteps = - (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, - img.tiles[0].tileComps[comp].nQuantSteps, - sizeof(Guint)); - for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) { - img.tiles[i].tileComps[comp].quantSteps[j] = - img.tiles[0].tileComps[comp].quantSteps[j]; - } - } - break; - case 0x5e: // RGN - region of interest -#if 1 //~ ROI is unimplemented - fprintf(stderr, "RGN\n"); - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX PPM marker segment"); - return gFalse; - } - } -#else - if ((img.nComps > 256 && !readUWord(&comp)) || - (img.nComps <= 256 && !readUByte(&comp)) || - comp >= img.nComps || - !readUByte(&compInfo[comp].defROI.style) || - !readUByte(&compInfo[comp].defROI.shift)) { - error(getPos(), "Error in JPX RGN marker segment"); - return gFalse; - } -#endif - break; - case 0x5f: // POC - progression order change -#if 1 //~ progression order changes are unimplemented - fprintf(stderr, "POC\n"); - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX PPM marker segment"); - return gFalse; - } - } -#else - nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); - progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder)); - for (i = 0; i < nProgs; ++i) { - if (!readUByte(&progs[i].startRes) || - !(img.nComps > 256 && readUWord(&progs[i].startComp)) || - !(img.nComps <= 256 && readUByte(&progs[i].startComp)) || - !readUWord(&progs[i].endLayer) || - !readUByte(&progs[i].endRes) || - !(img.nComps > 256 && readUWord(&progs[i].endComp)) || - !(img.nComps <= 256 && readUByte(&progs[i].endComp)) || - !readUByte(&progs[i].progOrder)) { - error(getPos(), "Error in JPX POC marker segment"); - return gFalse; - } - } -#endif - break; - case 0x60: // PPM - packed packet headers, main header -#if 1 //~ packed packet headers are unimplemented - fprintf(stderr, "PPM\n"); - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX PPM marker segment"); - return gFalse; - } - } -#endif - break; - case 0x55: // TLM - tile-part lengths - // skipped - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX TLM marker segment"); - return gFalse; - } - } - break; - case 0x57: // PLM - packet length, main header - // skipped - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX PLM marker segment"); - return gFalse; - } - } - break; - case 0x63: // CRG - component registration - // skipped - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX CRG marker segment"); - return gFalse; - } - } - break; - case 0x64: // COM - comment - // skipped - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX COM marker segment"); - return gFalse; - } - } - break; - case 0x90: // SOT - start of tile - haveSOT = gTrue; - break; - default: - error(getPos(), "Unknown marker segment %02x in JPX stream", segType); - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - break; - } - } - break; - } - } while (!haveSOT); - - if (!haveSIZ) { - error(getPos(), "Missing SIZ marker segment in JPX stream"); - return gFalse; - } - if (!haveCOD) { - error(getPos(), "Missing COD marker segment in JPX stream"); - return gFalse; - } - if (!haveQCD) { - error(getPos(), "Missing QCD marker segment in JPX stream"); - return gFalse; - } - - //----- read the tile-parts - while (1) { - if (!readTilePart()) { - return gFalse; - } - if (!readMarkerHdr(&segType, &segLen)) { - error(getPos(), "Error in JPX codestream"); - return gFalse; - } - if (segType != 0x90) { // SOT - start of tile - break; - } - } - - if (segType != 0xd9) { // EOC - end of codestream - error(getPos(), "Missing EOC marker in JPX codestream"); - return gFalse; - } - - //----- finish decoding the image - for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { - tile = &img.tiles[i]; - for (comp = 0; comp < img.nComps; ++comp) { - tileComp = &tile->tileComps[comp]; - inverseTransform(tileComp); - } - if (!inverseMultiCompAndDC(tile)) { - return gFalse; - } - } - - //~ can free memory below tileComps here, and also tileComp.buf - - return gTrue; -} - -GBool JPXStream::readTilePart() { - JPXTile *tile; - JPXTileComp *tileComp; - JPXResLevel *resLevel; - JPXPrecinct *precinct; - JPXSubband *subband; - JPXCodeBlock *cb; - GBool haveSOD; - Guint tileIdx, tilePartLen, tilePartIdx, nTileParts; - GBool tilePartToEOC; - Guint precinctSize, style; - Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen; - Guint i, j, k, cbX, cbY, r, pre, sb, cbi; - int segType, level; - - // process the SOT marker segment - if (!readUWord(&tileIdx) || - !readULong(&tilePartLen) || - !readUByte(&tilePartIdx) || - !readUByte(&nTileParts)) { - error(getPos(), "Error in JPX SOT marker segment"); - return gFalse; - } - - if (tileIdx >= img.nXTiles * img.nYTiles) { - error(getPos(), "Weird tile index in JPX stream"); - return gFalse; - } - - tilePartToEOC = tilePartLen == 0; - tilePartLen -= 12; // subtract size of SOT segment - - haveSOD = gFalse; - do { - if (!readMarkerHdr(&segType, &segLen)) { - error(getPos(), "Error in JPX tile-part codestream"); - return gFalse; - } - tilePartLen -= 2 + segLen; - switch (segType) { - case 0x52: // COD - coding style default - if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) || - !readUByte(&img.tiles[tileIdx].progOrder) || - !readUWord(&img.tiles[tileIdx].nLayers) || - !readUByte(&img.tiles[tileIdx].multiComp) || - !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) || - !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) || - !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) || - !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) || - !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) { - error(getPos(), "Error in JPX COD marker segment"); - return gFalse; - } - img.tiles[tileIdx].tileComps[0].codeBlockW += 2; - img.tiles[tileIdx].tileComps[0].codeBlockH += 2; - for (comp = 0; comp < img.nComps; ++comp) { - if (comp != 0) { - img.tiles[tileIdx].tileComps[comp].style = - img.tiles[tileIdx].tileComps[0].style; - img.tiles[tileIdx].tileComps[comp].nDecompLevels = - img.tiles[tileIdx].tileComps[0].nDecompLevels; - img.tiles[tileIdx].tileComps[comp].codeBlockW = - img.tiles[tileIdx].tileComps[0].codeBlockW; - img.tiles[tileIdx].tileComps[comp].codeBlockH = - img.tiles[tileIdx].tileComps[0].codeBlockH; - img.tiles[tileIdx].tileComps[comp].codeBlockStyle = - img.tiles[tileIdx].tileComps[0].codeBlockStyle; - img.tiles[tileIdx].tileComps[comp].transform = - img.tiles[tileIdx].tileComps[0].transform; - } - img.tiles[tileIdx].tileComps[comp].resLevels = - (JPXResLevel *)greallocn( - img.tiles[tileIdx].tileComps[comp].resLevels, - (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), - sizeof(JPXResLevel)); - for (r = 0; - r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; - ++r) { - img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; - } - } - for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) { - if (img.tiles[tileIdx].tileComps[0].style & 0x01) { - if (!readUByte(&precinctSize)) { - error(getPos(), "Error in JPX COD marker segment"); - return gFalse; - } - img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = - precinctSize & 0x0f; - img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = - (precinctSize >> 4) & 0x0f; - } else { - img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15; - img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15; - } - } - for (comp = 1; comp < img.nComps; ++comp) { - for (r = 0; - r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; - ++r) { - img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = - img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth; - img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = - img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight; - } - } - break; - case 0x53: // COC - coding style component - if ((img.nComps > 256 && !readUWord(&comp)) || - (img.nComps <= 256 && !readUByte(&comp)) || - comp >= img.nComps || - !readUByte(&style) || - !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) || - !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) || - !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) || - !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) || - !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) { - error(getPos(), "Error in JPX COC marker segment"); - return gFalse; - } - img.tiles[tileIdx].tileComps[comp].style = - (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1); - img.tiles[tileIdx].tileComps[comp].codeBlockW += 2; - img.tiles[tileIdx].tileComps[comp].codeBlockH += 2; - img.tiles[tileIdx].tileComps[comp].resLevels = - (JPXResLevel *)greallocn( - img.tiles[tileIdx].tileComps[comp].resLevels, - (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), - sizeof(JPXResLevel)); - for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { - img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; - } - for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { - if (img.tiles[tileIdx].tileComps[comp].style & 0x01) { - if (!readUByte(&precinctSize)) { - error(getPos(), "Error in JPX COD marker segment"); - return gFalse; - } - img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = - precinctSize & 0x0f; - img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = - (precinctSize >> 4) & 0x0f; - } else { - img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15; - img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15; - } - } - break; - case 0x5c: // QCD - quantization default - if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) { - img.tiles[tileIdx].tileComps[0].nQuantSteps = - segLen - 3; - img.tiles[tileIdx].tileComps[0].quantSteps = - (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, - img.tiles[tileIdx].tileComps[0].nQuantSteps, - sizeof(Guint)); - for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { - if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - } - } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) { - img.tiles[tileIdx].tileComps[0].nQuantSteps = 1; - img.tiles[tileIdx].tileComps[0].quantSteps = - (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, - img.tiles[tileIdx].tileComps[0].nQuantSteps, - sizeof(Guint)); - if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) { - img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2; - img.tiles[tileIdx].tileComps[0].quantSteps = - (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, - img.tiles[tileIdx].tileComps[0].nQuantSteps, - sizeof(Guint)); - for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { - if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - } - } else { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - for (comp = 1; comp < img.nComps; ++comp) { - img.tiles[tileIdx].tileComps[comp].quantStyle = - img.tiles[tileIdx].tileComps[0].quantStyle; - img.tiles[tileIdx].tileComps[comp].nQuantSteps = - img.tiles[tileIdx].tileComps[0].nQuantSteps; - img.tiles[tileIdx].tileComps[comp].quantSteps = - (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, - img.tiles[tileIdx].tileComps[0].nQuantSteps, - sizeof(Guint)); - for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) { - img.tiles[tileIdx].tileComps[comp].quantSteps[j] = - img.tiles[tileIdx].tileComps[0].quantSteps[j]; - } - } - break; - case 0x5d: // QCC - quantization component - if ((img.nComps > 256 && !readUWord(&comp)) || - (img.nComps <= 256 && !readUByte(&comp)) || - comp >= img.nComps || - !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) { - error(getPos(), "Error in JPX QCC marker segment"); - return gFalse; - } - if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) { - img.tiles[tileIdx].tileComps[comp].nQuantSteps = - segLen - (img.nComps > 256 ? 5 : 4); - img.tiles[tileIdx].tileComps[comp].quantSteps = - (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, - img.tiles[tileIdx].tileComps[comp].nQuantSteps, - sizeof(Guint)); - for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { - if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { - error(getPos(), "Error in JPX QCC marker segment"); - return gFalse; - } - } - } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) - == 0x01) { - img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1; - img.tiles[tileIdx].tileComps[comp].quantSteps = - (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, - img.tiles[tileIdx].tileComps[comp].nQuantSteps, - sizeof(Guint)); - if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) { - error(getPos(), "Error in JPX QCC marker segment"); - return gFalse; - } - } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) - == 0x02) { - img.tiles[tileIdx].tileComps[comp].nQuantSteps = - (segLen - (img.nComps > 256 ? 5 : 4)) / 2; - img.tiles[tileIdx].tileComps[comp].quantSteps = - (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, - img.tiles[tileIdx].tileComps[comp].nQuantSteps, - sizeof(Guint)); - for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { - if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { - error(getPos(), "Error in JPX QCD marker segment"); - return gFalse; - } - } - } else { - error(getPos(), "Error in JPX QCC marker segment"); - return gFalse; - } - break; - case 0x5e: // RGN - region of interest -#if 1 //~ ROI is unimplemented - fprintf(stderr, "RGN\n"); - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX PPM marker segment"); - return gFalse; - } - } -#else - if ((img.nComps > 256 && !readUWord(&comp)) || - (img.nComps <= 256 && !readUByte(&comp)) || - comp >= img.nComps || - !readUByte(&compInfo[comp].roi.style) || - !readUByte(&compInfo[comp].roi.shift)) { - error(getPos(), "Error in JPX RGN marker segment"); - return gFalse; - } -#endif - break; - case 0x5f: // POC - progression order change -#if 1 //~ progression order changes are unimplemented - fprintf(stderr, "POC\n"); - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX PPM marker segment"); - return gFalse; - } - } -#else - nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); - tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder)); - for (i = 0; i < nTileProgs; ++i) { - if (!readUByte(&tileProgs[i].startRes) || - !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) || - !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) || - !readUWord(&tileProgs[i].endLayer) || - !readUByte(&tileProgs[i].endRes) || - !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) || - !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) || - !readUByte(&tileProgs[i].progOrder)) { - error(getPos(), "Error in JPX POC marker segment"); - return gFalse; - } - } -#endif - break; - case 0x61: // PPT - packed packet headers, tile-part hdr -#if 1 //~ packed packet headers are unimplemented - fprintf(stderr, "PPT\n"); - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX PPT marker segment"); - return gFalse; - } - } -#endif - case 0x58: // PLT - packet length, tile-part header - // skipped - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX PLT marker segment"); - return gFalse; - } - } - break; - case 0x64: // COM - comment - // skipped - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - error(getPos(), "Error in JPX COM marker segment"); - return gFalse; - } - } - break; - case 0x93: // SOD - start of data - haveSOD = gTrue; - break; - default: - error(getPos(), "Unknown marker segment %02x in JPX tile-part stream", - segType); - for (i = 0; i < segLen - 2; ++i) { - if (str->getChar() == EOF) { - break; - } - } - break; - } - } while (!haveSOD); - - //----- initialize the tile, precincts, and code-blocks - if (tilePartIdx == 0) { - tile = &img.tiles[tileIdx]; - i = tileIdx / img.nXTiles; - j = tileIdx % img.nXTiles; - if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) { - tile->x0 = img.xOffset; - } - if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) { - tile->y0 = img.yOffset; - } - if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) { - tile->x1 = img.xSize; - } - if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) { - tile->y1 = img.ySize; - } - tile->comp = 0; - tile->res = 0; - tile->precinct = 0; - tile->layer = 0; - tile->maxNDecompLevels = 0; - for (comp = 0; comp < img.nComps; ++comp) { - tileComp = &tile->tileComps[comp]; - if (tileComp->nDecompLevels > tile->maxNDecompLevels) { - tile->maxNDecompLevels = tileComp->nDecompLevels; - } - tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep); - tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->hSep); - tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep); - tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep); - tileComp->cbW = 1 << tileComp->codeBlockW; - tileComp->cbH = 1 << tileComp->codeBlockH; - tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) * - (tileComp->y1 - tileComp->y0), - sizeof(int)); - if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { - n = tileComp->x1 - tileComp->x0; - } else { - n = tileComp->y1 - tileComp->y0; - } - tileComp->buf = (int *)gmallocn(n + 8, sizeof(int)); - for (r = 0; r <= tileComp->nDecompLevels; ++r) { - resLevel = &tileComp->resLevels[r]; - k = r == 0 ? tileComp->nDecompLevels - : tileComp->nDecompLevels - r + 1; - resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k); - resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k); - resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k); - resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k); - if (r == 0) { - resLevel->bx0[0] = resLevel->x0; - resLevel->by0[0] = resLevel->y0; - resLevel->bx1[0] = resLevel->x1; - resLevel->by1[0] = resLevel->y1; - } else { - resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k); - resLevel->by0[0] = resLevel->y0; - resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); - resLevel->by1[0] = resLevel->y1; - resLevel->bx0[1] = resLevel->x0; - resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k); - resLevel->bx1[1] = resLevel->x1; - resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); - resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k); - resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k); - resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); - resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); - } - resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct)); - for (pre = 0; pre < 1; ++pre) { - precinct = &resLevel->precincts[pre]; - precinct->x0 = resLevel->x0; - precinct->y0 = resLevel->y0; - precinct->x1 = resLevel->x1; - precinct->y1 = resLevel->y1; - nSBs = r == 0 ? 1 : 3; - precinct->subbands = - (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband)); - for (sb = 0; sb < nSBs; ++sb) { - subband = &precinct->subbands[sb]; - subband->x0 = resLevel->bx0[sb]; - subband->y0 = resLevel->by0[sb]; - subband->x1 = resLevel->bx1[sb]; - subband->y1 = resLevel->by1[sb]; - subband->nXCBs = jpxCeilDivPow2(subband->x1, - tileComp->codeBlockW) - - jpxFloorDivPow2(subband->x0, - tileComp->codeBlockW); - subband->nYCBs = jpxCeilDivPow2(subband->y1, - tileComp->codeBlockH) - - jpxFloorDivPow2(subband->y0, - tileComp->codeBlockH); - n = subband->nXCBs > subband->nYCBs ? subband->nXCBs - : subband->nYCBs; - for (subband->maxTTLevel = 0, --n; - n; - ++subband->maxTTLevel, n >>= 1) ; - n = 0; - for (level = subband->maxTTLevel; level >= 0; --level) { - nx = jpxCeilDivPow2(subband->nXCBs, level); - ny = jpxCeilDivPow2(subband->nYCBs, level); - n += nx * ny; - } - subband->inclusion = - (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); - subband->zeroBitPlane = - (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); - for (k = 0; k < n; ++k) { - subband->inclusion[k].finished = gFalse; - subband->inclusion[k].val = 0; - subband->zeroBitPlane[k].finished = gFalse; - subband->zeroBitPlane[k].val = 0; - } - subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs * - subband->nYCBs, - sizeof(JPXCodeBlock)); - sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW); - sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH); - cb = subband->cbs; - for (cbY = 0; cbY < subband->nYCBs; ++cbY) { - for (cbX = 0; cbX < subband->nXCBs; ++cbX) { - cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW; - cb->x1 = cb->x0 + tileComp->cbW; - if (subband->x0 > cb->x0) { - cb->x0 = subband->x0; - } - if (subband->x1 < cb->x1) { - cb->x1 = subband->x1; - } - cb->y0 = (sby0 + cbY) << tileComp->codeBlockH; - cb->y1 = cb->y0 + tileComp->cbH; - if (subband->y0 > cb->y0) { - cb->y0 = subband->y0; - } - if (subband->y1 < cb->y1) { - cb->y1 = subband->y1; - } - cb->seen = gFalse; - cb->lBlock = 3; - cb->nextPass = jpxPassCleanup; - cb->nZeroBitPlanes = 0; - cb->coeffs = - (JPXCoeff *)gmallocn((1 << (tileComp->codeBlockW - + tileComp->codeBlockH)), - sizeof(JPXCoeff)); - for (cbi = 0; - cbi < (Guint)(1 << (tileComp->codeBlockW - + tileComp->codeBlockH)); - ++cbi) { - cb->coeffs[cbi].flags = 0; - cb->coeffs[cbi].len = 0; - cb->coeffs[cbi].mag = 0; - } - cb->arithDecoder = NULL; - cb->stats = NULL; - ++cb; - } - } - } - } - } - } - } - - return readTilePartData(tileIdx, tilePartLen, tilePartToEOC); -} - -GBool JPXStream::readTilePartData(Guint tileIdx, - Guint tilePartLen, GBool tilePartToEOC) { - JPXTile *tile; - JPXTileComp *tileComp; - JPXResLevel *resLevel; - JPXPrecinct *precinct; - JPXSubband *subband; - JPXCodeBlock *cb; - Guint ttVal; - Guint bits, cbX, cbY, nx, ny, i, j, n, sb; - int level; - - tile = &img.tiles[tileIdx]; - - // read all packets from this tile-part - while (1) { - if (tilePartToEOC) { - //~ peek for an EOC marker - } else if (tilePartLen == 0) { - break; - } - - tileComp = &tile->tileComps[tile->comp]; - resLevel = &tileComp->resLevels[tile->res]; - precinct = &resLevel->precincts[tile->precinct]; - - //----- packet header - - // zero-length flag - if (!readBits(1, &bits)) { - goto err; - } - if (!bits) { - // packet is empty -- clear all code-block inclusion flags - for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) { - subband = &precinct->subbands[sb]; - for (cbY = 0; cbY < subband->nYCBs; ++cbY) { - for (cbX = 0; cbX < subband->nXCBs; ++cbX) { - cb = &subband->cbs[cbY * subband->nXCBs + cbX]; - cb->included = gFalse; - } - } - } - } else { - - for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) { - subband = &precinct->subbands[sb]; - for (cbY = 0; cbY < subband->nYCBs; ++cbY) { - for (cbX = 0; cbX < subband->nXCBs; ++cbX) { - cb = &subband->cbs[cbY * subband->nXCBs + cbX]; - - // skip code-blocks with no coefficients - if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) { - cb->included = gFalse; - continue; - } - - // code-block inclusion - if (cb->seen) { - if (!readBits(1, &cb->included)) { - goto err; - } - } else { - ttVal = 0; - i = 0; - for (level = subband->maxTTLevel; level >= 0; --level) { - nx = jpxCeilDivPow2(subband->nXCBs, level); - ny = jpxCeilDivPow2(subband->nYCBs, level); - j = i + (cbY >> level) * nx + (cbX >> level); - if (!subband->inclusion[j].finished && - !subband->inclusion[j].val) { - subband->inclusion[j].val = ttVal; - } else { - ttVal = subband->inclusion[j].val; - } - while (!subband->inclusion[j].finished && - ttVal <= tile->layer) { - if (!readBits(1, &bits)) { - goto err; - } - if (bits == 1) { - subband->inclusion[j].finished = gTrue; - } else { - ++ttVal; - } - } - subband->inclusion[j].val = ttVal; - if (ttVal > tile->layer) { - break; - } - i += nx * ny; - } - cb->included = level < 0; - } - - if (cb->included) { - - // zero bit-plane count - if (!cb->seen) { - ttVal = 0; - i = 0; - for (level = subband->maxTTLevel; level >= 0; --level) { - nx = jpxCeilDivPow2(subband->nXCBs, level); - ny = jpxCeilDivPow2(subband->nYCBs, level); - j = i + (cbY >> level) * nx + (cbX >> level); - if (!subband->zeroBitPlane[j].finished && - !subband->zeroBitPlane[j].val) { - subband->zeroBitPlane[j].val = ttVal; - } else { - ttVal = subband->zeroBitPlane[j].val; - } - while (!subband->zeroBitPlane[j].finished) { - if (!readBits(1, &bits)) { - goto err; - } - if (bits == 1) { - subband->zeroBitPlane[j].finished = gTrue; - } else { - ++ttVal; - } - } - subband->zeroBitPlane[j].val = ttVal; - i += nx * ny; - } - cb->nZeroBitPlanes = ttVal; - } - - // number of coding passes - if (!readBits(1, &bits)) { - goto err; - } - if (bits == 0) { - cb->nCodingPasses = 1; - } else { - if (!readBits(1, &bits)) { - goto err; - } - if (bits == 0) { - cb->nCodingPasses = 2; - } else { - if (!readBits(2, &bits)) { - goto err; - } - if (bits < 3) { - cb->nCodingPasses = 3 + bits; - } else { - if (!readBits(5, &bits)) { - goto err; - } - if (bits < 31) { - cb->nCodingPasses = 6 + bits; - } else { - if (!readBits(7, &bits)) { - goto err; - } - cb->nCodingPasses = 37 + bits; - } - } - } - } - - // update Lblock - while (1) { - if (!readBits(1, &bits)) { - goto err; - } - if (!bits) { - break; - } - ++cb->lBlock; - } - - // length of compressed data - //~ deal with multiple codeword segments - for (n = cb->lBlock, i = cb->nCodingPasses >> 1; - i; - ++n, i >>= 1) ; - if (!readBits(n, &cb->dataLen)) { - goto err; - } - } - } - } - } - } - tilePartLen -= byteCount; - clearBitBuf(); - - //----- packet data - - for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) { - subband = &precinct->subbands[sb]; - for (cbY = 0; cbY < subband->nYCBs; ++cbY) { - for (cbX = 0; cbX < subband->nXCBs; ++cbX) { - cb = &subband->cbs[cbY * subband->nXCBs + cbX]; - if (cb->included) { - if (!readCodeBlockData(tileComp, resLevel, precinct, subband, - tile->res, sb, cb)) { - return gFalse; - } - tilePartLen -= cb->dataLen; - cb->seen = gTrue; - } - } - } - } - - //----- next packet - - switch (tile->progOrder) { - case 0: // layer, resolution level, component, precinct - if (++tile->comp == img.nComps) { - tile->comp = 0; - if (++tile->res == tile->maxNDecompLevels + 1) { - tile->res = 0; - if (++tile->layer == tile->nLayers) { - tile->layer = 0; - } - } - } - break; - case 1: // resolution level, layer, component, precinct - if (++tile->comp == img.nComps) { - tile->comp = 0; - if (++tile->layer == tile->nLayers) { - tile->layer = 0; - if (++tile->res == tile->maxNDecompLevels + 1) { - tile->res = 0; - } - } - } - break; - case 2: // resolution level, precinct, component, layer - //~ this isn't correct -- see B.12.1.3 - if (++tile->layer == tile->nLayers) { - tile->layer = 0; - if (++tile->comp == img.nComps) { - tile->comp = 0; - if (++tile->res == tile->maxNDecompLevels + 1) { - tile->res = 0; - } - } - } - break; - case 3: // precinct, component, resolution level, layer - //~ this isn't correct -- see B.12.1.4 - if (++tile->layer == tile->nLayers) { - tile->layer = 0; - if (++tile->res == tile->maxNDecompLevels + 1) { - tile->res = 0; - if (++tile->comp == img.nComps) { - tile->comp = 0; - } - } - } - break; - case 4: // component, precinct, resolution level, layer - //~ this isn't correct -- see B.12.1.5 - if (++tile->layer == tile->nLayers) { - tile->layer = 0; - if (++tile->res == tile->maxNDecompLevels + 1) { - tile->res = 0; - if (++tile->comp == img.nComps) { - tile->comp = 0; - } - } - } - break; - } - } - - return gTrue; - - err: - error(getPos(), "Error in JPX stream"); - return gFalse; -} - -GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, - JPXResLevel */*resLevel*/, - JPXPrecinct */*precinct*/, - JPXSubband */*subband*/, - Guint res, Guint sb, - JPXCodeBlock *cb) { - JPXCoeff *coeff0, *coeff1, *coeff; - Guint horiz, vert, diag, all, cx, xorBit; - int horizSign, vertSign; - Guint i, x, y0, y1, y2; - - if (cb->arithDecoder) { - cb->arithDecoder->restart(cb->dataLen); - } else { - cb->arithDecoder = new JArithmeticDecoder(); - cb->arithDecoder->setStream(str, cb->dataLen); - cb->arithDecoder->start(); - cb->stats = new JArithmeticDecoderStats(jpxNContexts); - cb->stats->setEntry(jpxContextSigProp, 4, 0); - cb->stats->setEntry(jpxContextRunLength, 3, 0); - cb->stats->setEntry(jpxContextUniform, 46, 0); - } - - for (i = 0; i < cb->nCodingPasses; ++i) { - switch (cb->nextPass) { - - //----- significance propagation pass - case jpxPassSigProp: - for (y0 = cb->y0, coeff0 = cb->coeffs; - y0 < cb->y1; - y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { - for (x = cb->x0, coeff1 = coeff0; - x < cb->x1; - ++x, ++coeff1) { - for (y1 = 0, coeff = coeff1; - y1 < 4 && y0+y1 < cb->y1; - ++y1, coeff += tileComp->cbW) { - if (!(coeff->flags & jpxCoeffSignificant)) { - horiz = vert = diag = 0; - horizSign = vertSign = 2; - if (x > cb->x0) { - if (coeff[-1].flags & jpxCoeffSignificant) { - ++horiz; - horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; - } - if (y0+y1 > cb->y0) { - diag += (coeff[-(int)tileComp->cbW - 1].flags - >> jpxCoeffSignificantB) & 1; - } - if (y0+y1 < cb->y1 - 1) { - diag += (coeff[tileComp->cbW - 1].flags - >> jpxCoeffSignificantB) & 1; - } - } - if (x < cb->x1 - 1) { - if (coeff[1].flags & jpxCoeffSignificant) { - ++horiz; - horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; - } - if (y0+y1 > cb->y0) { - diag += (coeff[-(int)tileComp->cbW + 1].flags - >> jpxCoeffSignificantB) & 1; - } - if (y0+y1 < cb->y1 - 1) { - diag += (coeff[tileComp->cbW + 1].flags - >> jpxCoeffSignificantB) & 1; - } - } - if (y0+y1 > cb->y0) { - if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) { - ++vert; - vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign) - ? -1 : 1; - } - } - if (y0+y1 < cb->y1 - 1) { - if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) { - ++vert; - vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign) - ? -1 : 1; - } - } - cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; - if (cx != 0) { - if (cb->arithDecoder->decodeBit(cx, cb->stats)) { - coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; - coeff->mag = (coeff->mag << 1) | 1; - cx = signContext[horizSign][vertSign][0]; - xorBit = signContext[horizSign][vertSign][1]; - if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { - coeff->flags |= jpxCoeffSign; - } - } - ++coeff->len; - coeff->flags |= jpxCoeffTouched; - } - } - } - } - } - ++cb->nextPass; - break; - - //----- magnitude refinement pass - case jpxPassMagRef: - for (y0 = cb->y0, coeff0 = cb->coeffs; - y0 < cb->y1; - y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { - for (x = cb->x0, coeff1 = coeff0; - x < cb->x1; - ++x, ++coeff1) { - for (y1 = 0, coeff = coeff1; - y1 < 4 && y0+y1 < cb->y1; - ++y1, coeff += tileComp->cbW) { - if ((coeff->flags & jpxCoeffSignificant) && - !(coeff->flags & jpxCoeffTouched)) { - if (coeff->flags & jpxCoeffFirstMagRef) { - all = 0; - if (x > cb->x0) { - all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1; - if (y0+y1 > cb->y0) { - all += (coeff[-(int)tileComp->cbW - 1].flags - >> jpxCoeffSignificantB) & 1; - } - if (y0+y1 < cb->y1 - 1) { - all += (coeff[tileComp->cbW - 1].flags - >> jpxCoeffSignificantB) & 1; - } - } - if (x < cb->x1 - 1) { - all += (coeff[1].flags >> jpxCoeffSignificantB) & 1; - if (y0+y1 > cb->y0) { - all += (coeff[-(int)tileComp->cbW + 1].flags - >> jpxCoeffSignificantB) & 1; - } - if (y0+y1 < cb->y1 - 1) { - all += (coeff[tileComp->cbW + 1].flags - >> jpxCoeffSignificantB) & 1; - } - } - if (y0+y1 > cb->y0) { - all += (coeff[-(int)tileComp->cbW].flags - >> jpxCoeffSignificantB) & 1; - } - if (y0+y1 < cb->y1 - 1) { - all += (coeff[tileComp->cbW].flags - >> jpxCoeffSignificantB) & 1; - } - cx = all ? 15 : 14; - } else { - cx = 16; - } - coeff->mag = (coeff->mag << 1) | - cb->arithDecoder->decodeBit(cx, cb->stats); - ++coeff->len; - coeff->flags |= jpxCoeffTouched; - coeff->flags &= ~jpxCoeffFirstMagRef; - } - } - } - } - ++cb->nextPass; - break; - - //----- cleanup pass - case jpxPassCleanup: - for (y0 = cb->y0, coeff0 = cb->coeffs; - y0 < cb->y1; - y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { - for (x = cb->x0, coeff1 = coeff0; - x < cb->x1; - ++x, ++coeff1) { - y1 = 0; - if (y0 + 3 < cb->y1 && - !(coeff1->flags & jpxCoeffTouched) && - !(coeff1[tileComp->cbW].flags & jpxCoeffTouched) && - !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) && - !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) && - (x == cb->x0 || y0 == cb->y0 || - !(coeff1[-(int)tileComp->cbW - 1].flags - & jpxCoeffSignificant)) && - (y0 == cb->y0 || - !(coeff1[-(int)tileComp->cbW].flags - & jpxCoeffSignificant)) && - (x == cb->x1 - 1 || y0 == cb->y0 || - !(coeff1[-(int)tileComp->cbW + 1].flags - & jpxCoeffSignificant)) && - (x == cb->x0 || - (!(coeff1[-1].flags & jpxCoeffSignificant) && - !(coeff1[tileComp->cbW - 1].flags - & jpxCoeffSignificant) && - !(coeff1[2 * tileComp->cbW - 1].flags - & jpxCoeffSignificant) && - !(coeff1[3 * tileComp->cbW - 1].flags - & jpxCoeffSignificant))) && - (x == cb->x1 - 1 || - (!(coeff1[1].flags & jpxCoeffSignificant) && - !(coeff1[tileComp->cbW + 1].flags - & jpxCoeffSignificant) && - !(coeff1[2 * tileComp->cbW + 1].flags - & jpxCoeffSignificant) && - !(coeff1[3 * tileComp->cbW + 1].flags - & jpxCoeffSignificant))) && - (x == cb->x0 || y0+4 == cb->y1 || - !(coeff1[4 * tileComp->cbW - 1].flags & jpxCoeffSignificant)) && - (y0+4 == cb->y1 || - !(coeff1[4 * tileComp->cbW].flags & jpxCoeffSignificant)) && - (x == cb->x1 - 1 || y0+4 == cb->y1 || - !(coeff1[4 * tileComp->cbW + 1].flags - & jpxCoeffSignificant))) { - if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) { - y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); - y1 = (y1 << 1) | - cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); - for (y2 = 0, coeff = coeff1; - y2 < y1; - ++y2, coeff += tileComp->cbW) { - ++coeff->len; - } - coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; - coeff->mag = (coeff->mag << 1) | 1; - ++coeff->len; - cx = signContext[2][2][0]; - xorBit = signContext[2][2][1]; - if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { - coeff->flags |= jpxCoeffSign; - } - ++y1; - } else { - for (y1 = 0, coeff = coeff1; - y1 < 4; - ++y1, coeff += tileComp->cbW) { - ++coeff->len; - } - y1 = 4; - } - } - for (coeff = &coeff1[y1 << tileComp->codeBlockW]; - y1 < 4 && y0 + y1 < cb->y1; - ++y1, coeff += tileComp->cbW) { - if (!(coeff->flags & jpxCoeffTouched)) { - horiz = vert = diag = 0; - horizSign = vertSign = 2; - if (x > cb->x0) { - if (coeff[-1].flags & jpxCoeffSignificant) { - ++horiz; - horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; - } - if (y0+y1 > cb->y0) { - diag += (coeff[-(int)tileComp->cbW - 1].flags - >> jpxCoeffSignificantB) & 1; - } - if (y0+y1 < cb->y1 - 1) { - diag += (coeff[tileComp->cbW - 1].flags - >> jpxCoeffSignificantB) & 1; - } - } - if (x < cb->x1 - 1) { - if (coeff[1].flags & jpxCoeffSignificant) { - ++horiz; - horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; - } - if (y0+y1 > cb->y0) { - diag += (coeff[-(int)tileComp->cbW + 1].flags - >> jpxCoeffSignificantB) & 1; - } - if (y0+y1 < cb->y1 - 1) { - diag += (coeff[tileComp->cbW + 1].flags - >> jpxCoeffSignificantB) & 1; - } - } - if (y0+y1 > cb->y0) { - if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) { - ++vert; - vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign) - ? -1 : 1; - } - } - if (y0+y1 < cb->y1 - 1) { - if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) { - ++vert; - vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign) - ? -1 : 1; - } - } - cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; - if (cb->arithDecoder->decodeBit(cx, cb->stats)) { - coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; - coeff->mag = (coeff->mag << 1) | 1; - cx = signContext[horizSign][vertSign][0]; - xorBit = signContext[horizSign][vertSign][1]; - if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { - coeff->flags |= jpxCoeffSign; - } - } - ++coeff->len; - } else { - coeff->flags &= ~jpxCoeffTouched; - } - } - } - } - cb->nextPass = jpxPassSigProp; - break; - } - } - - cb->arithDecoder->cleanup(); - return gTrue; -} - -// Inverse quantization, and wavelet transform (IDWT). This also does -// the initial shift to convert to fixed point format. -void JPXStream::inverseTransform(JPXTileComp *tileComp) { - JPXResLevel *resLevel; - JPXPrecinct *precinct; - JPXSubband *subband; - JPXCodeBlock *cb; - JPXCoeff *coeff0, *coeff; - Guint qStyle, guard, eps, shift; - int shift2; - double mu; - int val; - int *dataPtr; - Guint nx0, ny0, nx1, ny1; - Guint r, cbX, cbY, x, y; - - //----- (NL)LL subband (resolution level 0) - - resLevel = &tileComp->resLevels[0]; - precinct = &resLevel->precincts[0]; - subband = &precinct->subbands[0]; - - // i-quant parameters - qStyle = tileComp->quantStyle & 0x1f; - guard = (tileComp->quantStyle >> 5) & 7; - if (qStyle == 0) { - eps = (tileComp->quantSteps[0] >> 3) & 0x1f; - shift = guard + eps - 1; - mu = 0; // make gcc happy - } else { - shift = guard - 1 + tileComp->prec; - mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0; - } - if (tileComp->transform == 0) { - shift += fracBits; - } - - // copy (NL)LL into the upper-left corner of the data array, doing - // the fixed point adjustment and dequantization along the way - cb = subband->cbs; - for (cbY = 0; cbY < subband->nYCBs; ++cbY) { - for (cbX = 0; cbX < subband->nXCBs; ++cbX) { - for (y = cb->y0, coeff0 = cb->coeffs; - y < cb->y1; - ++y, coeff0 += tileComp->cbW) { - dataPtr = &tileComp->data[(y - subband->y0) - * (tileComp->x1 - tileComp->x0) - + (cb->x0 - subband->x0)]; - for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) { - val = (int)coeff->mag; - if (val != 0) { - shift2 = shift - (cb->nZeroBitPlanes + coeff->len); - if (shift2 > 0) { - val = (val << shift2) + (1 << (shift2 - 1)); - } else { - val >>= -shift2; - } - if (qStyle == 0) { - if (tileComp->transform == 0) { - val &= -1 << fracBits; - } - } else { - val = (int)((double)val * mu); - } - if (coeff->flags & jpxCoeffSign) { - val = -val; - } - } - *dataPtr++ = val; - } - } - ++cb; - } - } - - //----- IDWT for each level - - for (r = 1; r <= tileComp->nDecompLevels; ++r) { - resLevel = &tileComp->resLevels[r]; - - // (n)LL is already in the upper-left corner of the - // tile-component data array -- interleave with (n)HL/LH/HH - // and inverse transform to get (n-1)LL, which will be stored - // in the upper-left corner of the tile-component data array - if (r == tileComp->nDecompLevels) { - nx0 = tileComp->x0; - ny0 = tileComp->y0; - nx1 = tileComp->x1; - ny1 = tileComp->y1; - } else { - nx0 = tileComp->resLevels[r+1].x0; - ny0 = tileComp->resLevels[r+1].y0; - nx1 = tileComp->resLevels[r+1].x1; - ny1 = tileComp->resLevels[r+1].y1; - } - inverseTransformLevel(tileComp, r, resLevel, nx0, ny0, nx1, ny1); - } -} - -// Do one level of the inverse transform: -// - take (n)LL from the tile-component data array -// - take (n)HL/LH/HH from -// - leave the resulting (n-1)LL in the tile-component data array -void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, - Guint r, JPXResLevel *resLevel, - Guint nx0, Guint ny0, - Guint nx1, Guint ny1) { - JPXPrecinct *precinct; - JPXSubband *subband; - JPXCodeBlock *cb; - JPXCoeff *coeff0, *coeff; - Guint qStyle, guard, eps, shift, t; - int shift2; - double mu; - int val; - int *dataPtr; - Guint xo, yo; - Guint x, y, sb, cbX, cbY; - int xx, yy; - - //----- interleave - - // spread out LL - for (yy = resLevel->y1 - 1; yy >= (int)resLevel->y0; --yy) { - for (xx = resLevel->x1 - 1; xx >= (int)resLevel->x0; --xx) { - tileComp->data[(2 * yy - ny0) * (tileComp->x1 - tileComp->x0) - + (2 * xx - nx0)] = - tileComp->data[(yy - resLevel->y0) * (tileComp->x1 - tileComp->x0) - + (xx - resLevel->x0)]; - } - } - - // i-quant parameters - qStyle = tileComp->quantStyle & 0x1f; - guard = (tileComp->quantStyle >> 5) & 7; - - // interleave HL/LH/HH - precinct = &resLevel->precincts[0]; - for (sb = 0; sb < 3; ++sb) { - - // i-quant parameters - if (qStyle == 0) { - eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f; - shift = guard + eps - 1; - mu = 0; // make gcc happy - } else { - shift = guard + tileComp->prec; - if (sb == 2) { - ++shift; - } - t = tileComp->quantSteps[qStyle == 1 ? 0 : (3*r - 2 + sb)]; - mu = (double)(0x800 + (t & 0x7ff)) / 2048.0; - } - if (tileComp->transform == 0) { - shift += fracBits; - } - - // copy the subband coefficients into the data array, doing the - // fixed point adjustment and dequantization along the way - xo = (sb & 1) ? 0 : 1; - yo = (sb > 0) ? 1 : 0; - subband = &precinct->subbands[sb]; - cb = subband->cbs; - for (cbY = 0; cbY < subband->nYCBs; ++cbY) { - for (cbX = 0; cbX < subband->nXCBs; ++cbX) { - for (y = cb->y0, coeff0 = cb->coeffs; - y < cb->y1; - ++y, coeff0 += tileComp->cbW) { - dataPtr = &tileComp->data[(2 * y + yo - ny0) - * (tileComp->x1 - tileComp->x0) - + (2 * cb->x0 + xo - nx0)]; - for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) { - val = (int)coeff->mag; - if (val != 0) { - shift2 = shift - (cb->nZeroBitPlanes + coeff->len); - if (shift2 > 0) { - val = (val << shift2) + (1 << (shift2 - 1)); - } else { - val >>= -shift2; - } - if (qStyle == 0) { - if (tileComp->transform == 0) { - val &= -1 << fracBits; - } - } else { - val = (int)((double)val * mu); - } - if (coeff->flags & jpxCoeffSign) { - val = -val; - } - } - *dataPtr = val; - dataPtr += 2; - } - } - ++cb; - } - } - } - - //----- horizontal (row) transforms - dataPtr = tileComp->data; - for (y = 0; y < ny1 - ny0; ++y) { - inverseTransform1D(tileComp, dataPtr, 1, nx0, nx1); - dataPtr += tileComp->x1 - tileComp->x0; - } - - //----- vertical (column) transforms - dataPtr = tileComp->data; - for (x = 0; x < nx1 - nx0; ++x) { - inverseTransform1D(tileComp, dataPtr, - tileComp->x1 - tileComp->x0, ny0, ny1); - ++dataPtr; - } -} - -void JPXStream::inverseTransform1D(JPXTileComp *tileComp, - int *data, Guint stride, - Guint i0, Guint i1) { - int *buf; - Guint offset, end, i; - - //----- special case for length = 1 - if (i1 - i0 == 1) { - if (i0 & 1) { - *data >>= 1; - } - - } else { - - // choose an offset: this makes even buf[] indexes correspond to - // odd values of i, and vice versa - offset = 3 + (i0 & 1); - end = offset + i1 - i0; - - //----- gather - buf = tileComp->buf; - for (i = 0; i < i1 - i0; ++i) { - buf[offset + i] = data[i * stride]; - } - - //----- extend right - buf[end] = buf[end - 2]; - if (i1 - i0 == 2) { - buf[end+1] = buf[offset + 1]; - buf[end+2] = buf[offset]; - buf[end+3] = buf[offset + 1]; - } else { - buf[end+1] = buf[end - 3]; - if (i1 - i0 == 3) { - buf[end+2] = buf[offset + 1]; - buf[end+3] = buf[offset + 2]; - } else { - buf[end+2] = buf[end - 4]; - if (i1 - i0 == 4) { - buf[end+3] = buf[offset + 1]; - } else { - buf[end+3] = buf[end - 5]; - } - } - } - - //----- extend left - buf[offset - 1] = buf[offset + 1]; - buf[offset - 2] = buf[offset + 2]; - buf[offset - 3] = buf[offset + 3]; - if (offset == 4) { - buf[0] = buf[offset + 4]; - } - - //----- 9-7 irreversible filter - - if (tileComp->transform == 0) { - // step 1 (even) - for (i = 1; i <= end + 2; i += 2) { - buf[i] = (int)(idwtKappa * buf[i]); - } - // step 2 (odd) - for (i = 0; i <= end + 3; i += 2) { - buf[i] = (int)(idwtIKappa * buf[i]); - } - // step 3 (even) - for (i = 1; i <= end + 2; i += 2) { - buf[i] = (int)(buf[i] - idwtDelta * (buf[i-1] + buf[i+1])); - } - // step 4 (odd) - for (i = 2; i <= end + 1; i += 2) { - buf[i] = (int)(buf[i] - idwtGamma * (buf[i-1] + buf[i+1])); - } - // step 5 (even) - for (i = 3; i <= end; i += 2) { - buf[i] = (int)(buf[i] - idwtBeta * (buf[i-1] + buf[i+1])); - } - // step 6 (odd) - for (i = 4; i <= end - 1; i += 2) { - buf[i] = (int)(buf[i] - idwtAlpha * (buf[i-1] + buf[i+1])); - } - - //----- 5-3 reversible filter - - } else { - // step 1 (even) - for (i = 3; i <= end; i += 2) { - buf[i] -= (buf[i-1] + buf[i+1] + 2) >> 2; - } - // step 2 (odd) - for (i = 4; i < end; i += 2) { - buf[i] += (buf[i-1] + buf[i+1]) >> 1; - } - } - - //----- scatter - for (i = 0; i < i1 - i0; ++i) { - data[i * stride] = buf[offset + i]; - } - } -} - -// Inverse multi-component transform and DC level shift. This also -// converts fixed point samples back to integers. -GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { - JPXTileComp *tileComp; - int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal; - int *dataPtr; - Guint j, comp, x, y; - - //----- inverse multi-component transform - - if (tile->multiComp == 1) { - if (img.nComps < 3 || - tile->tileComps[0].hSep != tile->tileComps[1].hSep || - tile->tileComps[0].vSep != tile->tileComps[1].vSep || - tile->tileComps[1].hSep != tile->tileComps[2].hSep || - tile->tileComps[1].vSep != tile->tileComps[2].vSep) { - return gFalse; - } - - // inverse irreversible multiple component transform - if (tile->tileComps[0].transform == 0) { - j = 0; - for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) { - for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) { - d0 = tile->tileComps[0].data[j]; - d1 = tile->tileComps[1].data[j]; - d2 = tile->tileComps[2].data[j]; - tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5); - tile->tileComps[1].data[j] = - (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5); - tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5); - ++j; - } - } - - // inverse reversible multiple component transform - } else { - j = 0; - for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) { - for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) { - d0 = tile->tileComps[0].data[j]; - d1 = tile->tileComps[1].data[j]; - d2 = tile->tileComps[2].data[j]; - tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2); - tile->tileComps[0].data[j] = d2 + t; - tile->tileComps[2].data[j] = d1 + t; - ++j; - } - } - } - } - - //----- DC level shift - for (comp = 0; comp < img.nComps; ++comp) { - tileComp = &tile->tileComps[comp]; - - // signed: clip - if (tileComp->sgned) { - minVal = -(1 << (tileComp->prec - 1)); - maxVal = (1 << (tileComp->prec - 1)) - 1; - dataPtr = tileComp->data; - for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) { - for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) { - coeff = *dataPtr; - if (tileComp->transform == 0) { - coeff >>= fracBits; - } - if (coeff < minVal) { - coeff = minVal; - } else if (coeff > maxVal) { - coeff = maxVal; - } - *dataPtr++ = coeff; - } - } - - // unsigned: inverse DC level shift and clip - } else { - maxVal = (1 << tileComp->prec) - 1; - zeroVal = 1 << (tileComp->prec - 1); - dataPtr = tileComp->data; - for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) { - for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) { - coeff = *dataPtr; - if (tileComp->transform == 0) { - coeff >>= fracBits; - } - coeff += zeroVal; - if (coeff < 0) { - coeff = 0; - } else if (coeff > maxVal) { - coeff = maxVal; - } - *dataPtr++ = coeff; - } - } - } - } - - return gTrue; -} - -GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) { - Guint len, lenH; - - if (!readULong(&len) || - !readULong(boxType)) { - return gFalse; - } - if (len == 1) { - if (!readULong(&lenH) || !readULong(&len)) { - return gFalse; - } - if (lenH) { - error(getPos(), "JPX stream contains a box larger than 2^32 bytes"); - return gFalse; - } - *boxLen = len; - *dataLen = len - 16; - } else if (len == 0) { - *boxLen = 0; - *dataLen = 0; - } else { - *boxLen = len; - *dataLen = len - 8; - } - return gTrue; -} - -int JPXStream::readMarkerHdr(int *segType, Guint *segLen) { - int c; - - do { - do { - if ((c = str->getChar()) == EOF) { - return gFalse; - } - } while (c != 0xff); - do { - if ((c = str->getChar()) == EOF) { - return gFalse; - } - } while (c == 0xff); - } while (c == 0x00); - *segType = c; - if ((c >= 0x30 && c <= 0x3f) || - c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) { - *segLen = 0; - return gTrue; - } - return readUWord(segLen); -} - -GBool JPXStream::readUByte(Guint *x) { - int c0; - - if ((c0 = str->getChar()) == EOF) { - return gFalse; - } - *x = (Guint)c0; - return gTrue; -} - -GBool JPXStream::readByte(int *x) { - int c0; - - if ((c0 = str->getChar()) == EOF) { - return gFalse; - } - *x = c0; - if (c0 & 0x80) { - *x |= -1 - 0xff; - } - return gTrue; -} - -GBool JPXStream::readUWord(Guint *x) { - int c0, c1; - - if ((c0 = str->getChar()) == EOF || - (c1 = str->getChar()) == EOF) { - return gFalse; - } - *x = (Guint)((c0 << 8) | c1); - return gTrue; -} - -GBool JPXStream::readULong(Guint *x) { - int c0, c1, c2, c3; - - if ((c0 = str->getChar()) == EOF || - (c1 = str->getChar()) == EOF || - (c2 = str->getChar()) == EOF || - (c3 = str->getChar()) == EOF) { - return gFalse; - } - *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); - return gTrue; -} - -GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) { - int y, c, i; - - y = 0; - for (i = 0; i < nBytes; ++i) { - if ((c = str->getChar()) == EOF) { - return gFalse; - } - y = (y << 8) + c; - } - if (signd) { - if (y & (1 << (8 * nBytes - 1))) { - y |= -1 << (8 * nBytes); - } - } - *x = y; - return gTrue; -} - -GBool JPXStream::readBits(int nBits, Guint *x) { - int c; - - while (bitBufLen < nBits) { - if ((c = str->getChar()) == EOF) { - return gFalse; - } - ++byteCount; - if (bitBufSkip) { - bitBuf = (bitBuf << 7) | (c & 0x7f); - bitBufLen += 7; - } else { - bitBuf = (bitBuf << 8) | (c & 0xff); - bitBufLen += 8; - } - bitBufSkip = c == 0xff; - } - *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1); - bitBufLen -= nBits; - return gTrue; -} - -void JPXStream::clearBitBuf() { - bitBufLen = 0; - bitBufSkip = gFalse; - byteCount = 0; -} diff --git a/xpdf/xpdf/JPXStream.h b/xpdf/xpdf/JPXStream.h deleted file mode 100644 index 3bc56e0fa..000000000 --- a/xpdf/xpdf/JPXStream.h +++ /dev/null @@ -1,349 +0,0 @@ -//======================================================================== -// -// JPXStream.h -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef JPXSTREAM_H -#define JPXSTREAM_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "Object.h" -#include "Stream.h" - -class JArithmeticDecoderStats; - -//------------------------------------------------------------------------ - -enum JPXColorSpaceType { - jpxCSBiLevel = 0, - jpxCSYCbCr1 = 1, - jpxCSYCbCr2 = 3, - jpxCSYCBCr3 = 4, - jpxCSPhotoYCC = 9, - jpxCSCMY = 11, - jpxCSCMYK = 12, - jpxCSYCCK = 13, - jpxCSCIELab = 14, - jpxCSsRGB = 16, - jpxCSGrayscale = 17, - jpxCSBiLevel2 = 18, - jpxCSCIEJab = 19, - jpxCSCISesRGB = 20, - jpxCSROMMRGB = 21, - jpxCSsRGBYCbCr = 22, - jpxCSYPbPr1125 = 23, - jpxCSYPbPr1250 = 24 -}; - -struct JPXColorSpecCIELab { - Guint rl, ol, ra, oa, rb, ob, il; -}; - -struct JPXColorSpecEnumerated { - JPXColorSpaceType type; // color space type - union { - JPXColorSpecCIELab cieLab; - }; -}; - -struct JPXColorSpec { - Guint meth; // method - int prec; // precedence - union { - JPXColorSpecEnumerated enumerated; - }; -}; - -//------------------------------------------------------------------------ - -struct JPXPalette { - Guint nEntries; // number of entries in the palette - Guint nComps; // number of components in each entry - Guint *bpc; // bits per component, for each component - int *c; // color data: - // c[i*nComps+j] = entry i, component j -}; - -//------------------------------------------------------------------------ - -struct JPXCompMap { - Guint nChannels; // number of channels - Guint *comp; // codestream components mapped to each channel - Guint *type; // 0 for direct use, 1 for palette mapping - Guint *pComp; // palette components to use -}; - -//------------------------------------------------------------------------ - -struct JPXChannelDefn { - Guint nChannels; // number of channels - Guint *idx; // channel indexes - Guint *type; // channel types - Guint *assoc; // channel associations -}; - -//------------------------------------------------------------------------ - -struct JPXTagTreeNode { - GBool finished; // true if this node is finished - Guint val; // current value -}; - -//------------------------------------------------------------------------ - -struct JPXCoeff { - Gushort flags; // flag bits - Gushort len; // number of significant bits in mag - Guint mag; // magnitude value -}; - -// coefficient flags -#define jpxCoeffSignificantB 0 -#define jpxCoeffTouchedB 1 -#define jpxCoeffFirstMagRefB 2 -#define jpxCoeffSignB 7 -#define jpxCoeffSignificant (1 << jpxCoeffSignificantB) -#define jpxCoeffTouched (1 << jpxCoeffTouchedB) -#define jpxCoeffFirstMagRef (1 << jpxCoeffFirstMagRefB) -#define jpxCoeffSign (1 << jpxCoeffSignB) - -//------------------------------------------------------------------------ - -struct JPXCodeBlock { - //----- size - Guint x0, y0, x1, y1; // bounds - - //----- persistent state - GBool seen; // true if this code-block has already - // been seen - Guint lBlock; // base number of bits used for pkt data length - Guint nextPass; // next coding pass - - //---- info from first packet - Guint nZeroBitPlanes; // number of zero bit planes - - //----- info for the current packet - Guint included; // code-block inclusion in this packet: - // 0=not included, 1=included - Guint nCodingPasses; // number of coding passes in this pkt - Guint dataLen; // pkt data length - - //----- coefficient data - JPXCoeff *coeffs; // the coefficients - JArithmeticDecoder // arithmetic decoder - *arithDecoder; - JArithmeticDecoderStats // arithmetic decoder stats - *stats; -}; - -//------------------------------------------------------------------------ - -struct JPXSubband { - //----- computed - Guint x0, y0, x1, y1; // bounds - Guint nXCBs, nYCBs; // number of code-blocks in the x and y - // directions - - //----- tag trees - Guint maxTTLevel; // max tag tree level - JPXTagTreeNode *inclusion; // inclusion tag tree for each subband - JPXTagTreeNode *zeroBitPlane; // zero-bit plane tag tree for each - // subband - - //----- children - JPXCodeBlock *cbs; // the code-blocks (len = nXCBs * nYCBs) -}; - -//------------------------------------------------------------------------ - -struct JPXPrecinct { - //----- computed - Guint x0, y0, x1, y1; // bounds of the precinct - - //----- children - JPXSubband *subbands; // the subbands -}; - -//------------------------------------------------------------------------ - -struct JPXResLevel { - //----- from the COD and COC segments (main and tile) - Guint precinctWidth; // log2(precinct width) - Guint precinctHeight; // log2(precinct height) - - //----- computed - Guint x0, y0, x1, y1; // bounds of the tile-comp (for this res level) - Guint bx0[3], by0[3], // subband bounds - bx1[3], by1[3]; - - //---- children - JPXPrecinct *precincts; // the precincts -}; - -//------------------------------------------------------------------------ - -struct JPXTileComp { - //----- from the SIZ segment - GBool sgned; // 1 for signed, 0 for unsigned - Guint prec; // precision, in bits - Guint hSep; // horizontal separation of samples - Guint vSep; // vertical separation of samples - - //----- from the COD and COC segments (main and tile) - Guint style; // coding style parameter (Scod / Scoc) - Guint nDecompLevels; // number of decomposition levels - Guint codeBlockW; // log2(code-block width) - Guint codeBlockH; // log2(code-block height) - Guint codeBlockStyle; // code-block style - Guint transform; // wavelet transformation - - //----- from the QCD and QCC segments (main and tile) - Guint quantStyle; // quantization style - Guint *quantSteps; // quantization step size for each subband - Guint nQuantSteps; // number of entries in quantSteps - - //----- computed - Guint x0, y0, x1, y1; // bounds of the tile-comp, in ref coords - Guint cbW; // code-block width - Guint cbH; // code-block height - - //----- image data - int *data; // the decoded image data - int *buf; // intermediate buffer for the inverse - // transform - - //----- children - JPXResLevel *resLevels; // the resolution levels - // (len = nDecompLevels + 1) -}; - -//------------------------------------------------------------------------ - -struct JPXTile { - //----- from the COD segments (main and tile) - Guint progOrder; // progression order - Guint nLayers; // number of layers - Guint multiComp; // multiple component transformation - - //----- computed - Guint x0, y0, x1, y1; // bounds of the tile, in ref coords - Guint maxNDecompLevels; // max number of decomposition levels used - // in any component in this tile - - //----- progression order loop counters - Guint comp; // component - Guint res; // resolution level - Guint precinct; // precinct - Guint layer; // layer - - //----- children - JPXTileComp *tileComps; // the tile-components (len = JPXImage.nComps) -}; - -//------------------------------------------------------------------------ - -struct JPXImage { - //----- from the SIZ segment - Guint xSize, ySize; // size of reference grid - Guint xOffset, yOffset; // image offset - Guint xTileSize, yTileSize; // size of tiles - Guint xTileOffset, // offset of first tile - yTileOffset; - Guint nComps; // number of components - - //----- computed - Guint nXTiles; // number of tiles in x direction - Guint nYTiles; // number of tiles in y direction - - //----- children - JPXTile *tiles; // the tiles (len = nXTiles * nYTiles) -}; - -//------------------------------------------------------------------------ - -class JPXStream: public FilterStream { -public: - - JPXStream(Stream *strA); - virtual ~JPXStream(); - virtual StreamKind getKind() { return strJPX; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - virtual void getImageParams(int *bitsPerComponent, - StreamColorSpaceMode *csMode); - -private: - - void fillReadBuf(); - void getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode); - GBool readBoxes(); - GBool readColorSpecBox(Guint dataLen); - GBool readCodestream(Guint len); - GBool readTilePart(); - GBool readTilePartData(Guint tileIdx, - Guint tilePartLen, GBool tilePartToEOC); - GBool readCodeBlockData(JPXTileComp *tileComp, - JPXResLevel *resLevel, - JPXPrecinct *precinct, - JPXSubband *subband, - Guint res, Guint sb, - JPXCodeBlock *cb); - void inverseTransform(JPXTileComp *tileComp); - void inverseTransformLevel(JPXTileComp *tileComp, - Guint r, JPXResLevel *resLevel, - Guint nx0, Guint ny0, - Guint nx1, Guint ny1); - void inverseTransform1D(JPXTileComp *tileComp, - int *data, Guint stride, - Guint i0, Guint i1); - GBool inverseMultiCompAndDC(JPXTile *tile); - GBool readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen); - int readMarkerHdr(int *segType, Guint *segLen); - GBool readUByte(Guint *x); - GBool readByte(int *x); - GBool readUWord(Guint *x); - GBool readULong(Guint *x); - GBool readNBytes(int nBytes, GBool signd, int *x); - GBool readBits(int nBits, Guint *x); - void clearBitBuf(); - - Guint nComps; // number of components - Guint *bpc; // bits per component, for each component - Guint width, height; // image size - GBool haveImgHdr; // set if a JP2/JPX image header has been - // found - JPXColorSpec cs; // color specification - GBool haveCS; // set if a color spec has been found - JPXPalette palette; // the palette - GBool havePalette; // set if a palette has been found - JPXCompMap compMap; // the component mapping - GBool haveCompMap; // set if a component mapping has been found - JPXChannelDefn channelDefn; // channel definition - GBool haveChannelDefn; // set if a channel defn has been found - - JPXImage img; // JPEG2000 decoder data - Guint bitBuf; // buffer for bit reads - int bitBufLen; // number of bits in bitBuf - GBool bitBufSkip; // true if next bit should be skipped - // (for bit stuffing) - Guint byteCount; // number of bytes read since last call - // to clearBitBuf - - Guint curX, curY, curComp; // current position for lookChar/getChar - Guint readBuf; // read buffer - Guint readBufLen; // number of valid bits in readBuf -}; - -#endif diff --git a/xpdf/xpdf/Lexer.cc b/xpdf/xpdf/Lexer.cc deleted file mode 100644 index 5cbcc33a3..000000000 --- a/xpdf/xpdf/Lexer.cc +++ /dev/null @@ -1,501 +0,0 @@ -//======================================================================== -// -// Lexer.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include "Lexer.h" -#include "Error.h" -#include "XRef.h" - -//------------------------------------------------------------------------ - -// A '1' in this array means the character is white space. A '1' or -// '2' means the character ends a name or command. -static char Lexer_specialChars[256] = { - 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x - 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx -}; - -//------------------------------------------------------------------------ -// Lexer -//------------------------------------------------------------------------ - -Lexer::Lexer(XRef *xrefA, Stream *str) { - Object obj; - - xref = xrefA; - - curStr.initStream(str); - streams = new Array(xref); - streams->add(curStr.copy(&obj)); - strPtr = 0; - freeArray = gTrue; - curStr.streamReset(); -} - -Lexer::Lexer(XRef *xrefA, Object *obj) { - Object obj2; - - xref = xrefA; - - if (obj->isStream()) { - streams = new Array(xref); - freeArray = gTrue; - streams->add(obj->copy(&obj2)); - } else { - streams = obj->getArray(); - freeArray = gFalse; - } - strPtr = 0; - if (streams->getLength() > 0) { - streams->get(strPtr, &curStr); - curStr.streamReset(); - } -} - -Lexer::~Lexer() { - if (!curStr.isNone()) { - curStr.streamClose(); - curStr.free(); - } - if (freeArray) { - delete streams; - } -} - -int Lexer::getChar() { - int c; - - c = EOF; - while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) { - curStr.streamClose(); - curStr.free(); - ++strPtr; - if (strPtr < streams->getLength()) { - streams->get(strPtr, &curStr); - curStr.streamReset(); - } - } - return c; -} - -int Lexer::lookChar() { - if (curStr.isNone()) { - return EOF; - } - return curStr.streamLookChar(); -} - -Object *Lexer::getObj(Object *obj, int objNum) { - char *p; - int c, c2; - GBool comment, neg, done; - int numParen; - int xi; - double xf, scale; - GString *s; - int n, m; - - // skip whitespace and comments - comment = gFalse; - while (1) { - if ((c = getChar()) == EOF) { - return obj->initEOF(); - } - if (comment) { - if (c == '\r' || c == '\n') - comment = gFalse; - } else if (c == '%') { - comment = gTrue; - } else if (Lexer_specialChars[c] != 1) { - break; - } - } - - // start reading token - switch (c) { - - // number - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '-': case '.': - neg = gFalse; - xi = 0; - if (c == '-') { - neg = gTrue; - } else if (c == '.') { - goto doReal; - } else { - xi = c - '0'; - } - while (1) { - c = lookChar(); - if (isdigit(c)) { - getChar(); - xi = xi * 10 + (c - '0'); - } else if (c == '.') { - getChar(); - goto doReal; - } else { - break; - } - } - if (neg) - xi = -xi; - obj->initInt(xi); - break; - doReal: - xf = xi; - scale = 0.1; - while (1) { - c = lookChar(); - if (c == '-') { - // ignore minus signs in the middle of numbers to match - // Adobe's behavior - error(getPos(), "Badly formatted number"); - getChar(); - continue; - } - if (!isdigit(c)) { - break; - } - getChar(); - xf = xf + scale * (c - '0'); - scale *= 0.1; - } - if (neg) - xf = -xf; - obj->initReal(xf); - break; - - // string - case '(': - p = tokBuf; - n = 0; - numParen = 1; - done = gFalse; - s = NULL; - do { - c2 = EOF; - switch (c = getChar()) { - - case EOF: -#if 0 - // This breaks some PDF files, e.g., ones from Photoshop. - case '\r': - case '\n': -#endif - error(getPos(), "Unterminated string"); - done = gTrue; - break; - - case '(': - ++numParen; - c2 = c; - break; - - case ')': - if (--numParen == 0) { - done = gTrue; - } else { - c2 = c; - } - break; - - case '\\': - switch (c = getChar()) { - case 'n': - c2 = '\n'; - break; - case 'r': - c2 = '\r'; - break; - case 't': - c2 = '\t'; - break; - case 'b': - c2 = '\b'; - break; - case 'f': - c2 = '\f'; - break; - case '\\': - case '(': - case ')': - c2 = c; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - c2 = c - '0'; - c = lookChar(); - if (c >= '0' && c <= '7') { - getChar(); - c2 = (c2 << 3) + (c - '0'); - c = lookChar(); - if (c >= '0' && c <= '7') { - getChar(); - c2 = (c2 << 3) + (c - '0'); - } - } - break; - case '\r': - c = lookChar(); - if (c == '\n') { - getChar(); - } - break; - case '\n': - break; - case EOF: - error(getPos(), "Unterminated string"); - done = gTrue; - break; - default: - c2 = c; - break; - } - break; - - default: - c2 = c; - break; - } - - if (c2 != EOF) { - if (n == tokBufSize) { - if (!s) - s = new GString(tokBuf, tokBufSize); - else - s->append(tokBuf, tokBufSize); - p = tokBuf; - n = 0; - - // we are growing see if the document is not malformed and we are growing too much - if (objNum != -1) - { - int newObjNum = xref->getNumEntry(getPos()); - if (newObjNum != objNum) - { - error(getPos(), "Unterminated string"); - done = gTrue; - } - } - } - *p++ = (char)c2; - ++n; - } - } while (!done); - if (!s) - s = new GString(tokBuf, n); - else - s->append(tokBuf, n); - obj->initString(s); - break; - - // name - case '/': - p = tokBuf; - n = 0; - while ((c = lookChar()) != EOF && !Lexer_specialChars[c]) { - getChar(); - if (c == '#') { - c2 = lookChar(); - if (c2 >= '0' && c2 <= '9') { - c = c2 - '0'; - } else if (c2 >= 'A' && c2 <= 'F') { - c = c2 - 'A' + 10; - } else if (c2 >= 'a' && c2 <= 'f') { - c = c2 - 'a' + 10; - } else { - goto notEscChar; - } - getChar(); - c <<= 4; - c2 = getChar(); - if (c2 >= '0' && c2 <= '9') { - c += c2 - '0'; - } else if (c2 >= 'A' && c2 <= 'F') { - c += c2 - 'A' + 10; - } else if (c2 >= 'a' && c2 <= 'f') { - c += c2 - 'a' + 10; - } else { - error(getPos(), "Illegal digit in hex char in name"); - } - } - notEscChar: - if (++n == tokBufSize) { - error(getPos(), "Name token too long"); - break; - } - *p++ = c; - } - *p = '\0'; - obj->initName(tokBuf); - break; - - // array punctuation - case '[': - case ']': - tokBuf[0] = c; - tokBuf[1] = '\0'; - obj->initCmd(tokBuf); - break; - - // hex string or dict punctuation - case '<': - c = lookChar(); - - // dict punctuation - if (c == '<') { - getChar(); - tokBuf[0] = tokBuf[1] = '<'; - tokBuf[2] = '\0'; - obj->initCmd(tokBuf); - - // hex string - } else { - p = tokBuf; - m = n = 0; - c2 = 0; - s = NULL; - while (1) { - c = getChar(); - if (c == '>') { - break; - } else if (c == EOF) { - error(getPos(), "Unterminated hex string"); - break; - } else if (Lexer_specialChars[c] != 1) { - c2 = c2 << 4; - if (c >= '0' && c <= '9') - c2 += c - '0'; - else if (c >= 'A' && c <= 'F') - c2 += c - 'A' + 10; - else if (c >= 'a' && c <= 'f') - c2 += c - 'a' + 10; - else - error(getPos(), "Illegal character <%02x> in hex string", c); - if (++m == 2) { - if (n == tokBufSize) { - if (!s) - s = new GString(tokBuf, tokBufSize); - else - s->append(tokBuf, tokBufSize); - p = tokBuf; - n = 0; - } - *p++ = (char)c2; - ++n; - c2 = 0; - m = 0; - } - } - } - if (!s) - s = new GString(tokBuf, n); - else - s->append(tokBuf, n); - if (m == 1) - s->append((char)(c2 << 4)); - obj->initString(s); - } - break; - - // dict punctuation - case '>': - c = lookChar(); - if (c == '>') { - getChar(); - tokBuf[0] = tokBuf[1] = '>'; - tokBuf[2] = '\0'; - obj->initCmd(tokBuf); - } else { - error(getPos(), "Illegal character '>'"); - obj->initError(); - } - break; - - // error - case ')': - case '{': - case '}': - error(getPos(), "Illegal character '%c'", c); - obj->initError(); - break; - - // command - default: - p = tokBuf; - *p++ = c; - n = 1; - while ((c = lookChar()) != EOF && !Lexer_specialChars[c]) { - getChar(); - if (++n == tokBufSize) { - error(getPos(), "Command token too long"); - break; - } - *p++ = c; - } - *p = '\0'; - if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) { - obj->initBool(gTrue); - } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) { - obj->initBool(gFalse); - } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) { - obj->initNull(); - } else { - obj->initCmd(tokBuf); - } - break; - } - - return obj; -} - -void Lexer::skipToNextLine() { - int c; - - while (1) { - c = getChar(); - if (c == EOF || c == '\n') { - return; - } - if (c == '\r') { - if ((c = lookChar()) == '\n') { - getChar(); - } - return; - } - } -} - -GBool Lexer::isSpace(int c) { - return c >= 0 && c <= 0xff && Lexer_specialChars[c] == 1; -} diff --git a/xpdf/xpdf/Lexer.h b/xpdf/xpdf/Lexer.h deleted file mode 100644 index 3333be9f9..000000000 --- a/xpdf/xpdf/Lexer.h +++ /dev/null @@ -1,82 +0,0 @@ -//======================================================================== -// -// Lexer.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef LEXER_H -#define LEXER_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" -#include "Stream.h" - -class XRef; - -#define tokBufSize 128 // size of token buffer - -//------------------------------------------------------------------------ -// Lexer -//------------------------------------------------------------------------ - -class Lexer { -public: - - // Construct a lexer for a single stream. Deletes the stream when - // lexer is deleted. - Lexer(XRef *xrefA, Stream *str); - - // Construct a lexer for a stream or array of streams (assumes obj - // is either a stream or array of streams). - Lexer(XRef *xrefA, Object *obj); - - // Destructor. - ~Lexer(); - - // Get the next object from the input stream. - Object *getObj(Object *obj, int objNum = -1); - - // Skip to the beginning of the next line in the input stream. - void skipToNextLine(); - - // Skip over one character. - void skipChar() { getChar(); } - - // Get stream. - Stream *getStream() - { return curStr.isNone() ? (Stream *)NULL : curStr.getStream(); } - - // Get current position in file. This is only used for error - // messages, so it returns an int instead of a Guint. - int getPos() - { return curStr.isNone() ? -1 : (int)curStr.streamGetPos(); } - - // Set position in file. - void setPos(Guint pos, int dir = 0) - { if (!curStr.isNone()) curStr.streamSetPos(pos, dir); } - - // Returns true if is a whitespace character. - static GBool isSpace(int c); - -private: - - int getChar(); - int lookChar(); - - Array *streams; // array of input streams - int strPtr; // index of current stream - Object curStr; // current stream - GBool freeArray; // should lexer free the streams array? - char tokBuf[tokBufSize]; // temporary token buffer - - XRef *xref; -}; - -#endif diff --git a/xpdf/xpdf/Link.cc b/xpdf/xpdf/Link.cc deleted file mode 100644 index ab833d120..000000000 --- a/xpdf/xpdf/Link.cc +++ /dev/null @@ -1,908 +0,0 @@ -//======================================================================== -// -// Link.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "GString.h" -#include "UGString.h" -#include "Error.h" -#include "Object.h" -#include "Array.h" -#include "Dict.h" -#include "Link.h" - -//------------------------------------------------------------------------ -// LinkAction -//------------------------------------------------------------------------ - -LinkAction *LinkAction::parseDest(Object *obj) { - LinkAction *action; - - action = new LinkGoTo(obj); - if (!action->isOk()) { - delete action; - return NULL; - } - return action; -} - -LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) { - LinkAction *action; - Object obj2, obj3, obj4; - - if (!obj->isDict()) { - error(-1, "Bad annotation action"); - return NULL; - } - - obj->dictLookup("S", &obj2); - - // GoTo action - if (obj2.isName("GoTo")) { - obj->dictLookup("D", &obj3); - action = new LinkGoTo(&obj3); - obj3.free(); - - // GoToR action - } else if (obj2.isName("GoToR")) { - obj->dictLookup("F", &obj3); - obj->dictLookup("D", &obj4); - action = new LinkGoToR(&obj3, &obj4); - obj3.free(); - obj4.free(); - - // Launch action - } else if (obj2.isName("Launch")) { - action = new LinkLaunch(obj); - - // URI action - } else if (obj2.isName("URI")) { - obj->dictLookup("URI", &obj3); - action = new LinkURI(&obj3, baseURI); - obj3.free(); - - // Named action - } else if (obj2.isName("Named")) { - obj->dictLookup("N", &obj3); - action = new LinkNamed(&obj3); - obj3.free(); - - // Movie action - } else if (obj2.isName("Movie")) { - obj->dictLookupNF("Annot", &obj3); - obj->dictLookup("T", &obj4); - action = new LinkMovie(&obj3, &obj4); - obj3.free(); - obj4.free(); - - // unknown action - } else if (obj2.isName()) { - action = new LinkUnknown(obj2.getName()); - - // action is missing or wrong type - } else { - error(-1, "Bad annotation action"); - action = NULL; - } - - obj2.free(); - - if (action && !action->isOk()) { - delete action; - return NULL; - } - return action; -} - -GString *LinkAction::getFileSpecName(Object *fileSpecObj) { - GString *name; - Object obj1; - - name = NULL; - - // string - if (fileSpecObj->isString()) { - name = fileSpecObj->getString()->copy(); - - // dictionary - } else if (fileSpecObj->isDict()) { -#ifdef WIN32 - if (!fileSpecObj->dictLookup("DOS", &obj1)->isString()) { -#else - if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { -#endif - obj1.free(); - fileSpecObj->dictLookup("F", &obj1); - } - if (obj1.isString()) { - name = obj1.getString()->copy(); - } else { - error(-1, "Illegal file spec in link"); - } - obj1.free(); - - // error - } else { - error(-1, "Illegal file spec in link"); - } - - // system-dependent path manipulation - if (name) { -#ifdef WIN32 - int i, j; - - // "//...." --> "\...." - // "/x/...." --> "x:\...." - // "/server/share/...." --> "\\server\share\...." - // convert escaped slashes to slashes and unescaped slashes to backslashes - i = 0; - if (name->getChar(0) == '/') { - if (name->getLength() >= 2 && name->getChar(1) == '/') { - name->del(0); - i = 0; - } else if (name->getLength() >= 2 && - ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') || - (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) && - (name->getLength() == 2 || name->getChar(2) == '/')) { - name->setChar(0, name->getChar(1)); - name->setChar(1, ':'); - i = 2; - } else { - for (j = 2; j < name->getLength(); ++j) { - if (name->getChar(j-1) != '\\' && - name->getChar(j) == '/') { - break; - } - } - if (j < name->getLength()) { - name->setChar(0, '\\'); - name->insert(0, '\\'); - i = 2; - } - } - } - for (; i < name->getLength(); ++i) { - if (name->getChar(i) == '/') { - name->setChar(i, '\\'); - } else if (name->getChar(i) == '\\' && - i+1 < name->getLength() && - name->getChar(i+1) == '/') { - name->del(i); - } - } -#else - // no manipulation needed for Unix -#endif - } - - return name; -} - -//------------------------------------------------------------------------ -// LinkDest -//------------------------------------------------------------------------ - -LinkDest::LinkDest(Array *a) { - Object obj1, obj2; - - // initialize fields - left = bottom = right = top = zoom = 0; - ok = gFalse; - - // get page - if (a->getLength() < 2) { - error(-1, "Annotation destination array is too short"); - return; - } - a->getNF(0, &obj1); - if (obj1.isInt()) { - pageNum = obj1.getInt() + 1; - pageIsRef = gFalse; - } else if (obj1.isRef()) { - pageRef.num = obj1.getRefNum(); - pageRef.gen = obj1.getRefGen(); - pageIsRef = gTrue; - } else { - error(-1, "Bad annotation destination"); - goto err2; - } - obj1.free(); - - // get destination type - a->get(1, &obj1); - - // XYZ link - if (obj1.isName("XYZ")) { - kind = destXYZ; - if (a->getLength() < 3) { - changeLeft = gFalse; - } else { - a->get(2, &obj2); - if (obj2.isNull()) { - changeLeft = gFalse; - } else if (obj2.isNum()) { - changeLeft = gTrue; - left = obj2.getNum(); - } else { - error(-1, "Bad annotation destination position"); - goto err1; - } - obj2.free(); - } - if (a->getLength() < 4) { - changeTop = gFalse; - } else { - a->get(3, &obj2); - if (obj2.isNull()) { - changeTop = gFalse; - } else if (obj2.isNum()) { - changeTop = gTrue; - top = obj2.getNum(); - } else { - error(-1, "Bad annotation destination position"); - goto err1; - } - obj2.free(); - } - if (a->getLength() < 5) { - changeZoom = gFalse; - } else { - a->get(4, &obj2); - if (obj2.isNull()) { - changeZoom = gFalse; - } else if (obj2.isNum()) { - changeZoom = gTrue; - zoom = obj2.getNum(); - } else { - error(-1, "Bad annotation destination position"); - goto err1; - } - obj2.free(); - } - - // Fit link - } else if (obj1.isName("Fit")) { - if (a->getLength() < 2) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFit; - - // FitH link - } else if (obj1.isName("FitH")) { - if (a->getLength() < 3) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitH; - if (!a->get(2, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - top = obj2.getNum(); - obj2.free(); - - // FitV link - } else if (obj1.isName("FitV")) { - if (a->getLength() < 3) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitV; - if (!a->get(2, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - left = obj2.getNum(); - obj2.free(); - - // FitR link - } else if (obj1.isName("FitR")) { - if (a->getLength() < 6) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitR; - if (!a->get(2, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - left = obj2.getNum(); - obj2.free(); - if (!a->get(3, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - bottom = obj2.getNum(); - obj2.free(); - if (!a->get(4, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - right = obj2.getNum(); - obj2.free(); - if (!a->get(5, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - top = obj2.getNum(); - obj2.free(); - - // FitB link - } else if (obj1.isName("FitB")) { - if (a->getLength() < 2) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitB; - - // FitBH link - } else if (obj1.isName("FitBH")) { - if (a->getLength() < 3) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitBH; - if (!a->get(2, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - top = obj2.getNum(); - obj2.free(); - - // FitBV link - } else if (obj1.isName("FitBV")) { - if (a->getLength() < 3) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitBV; - if (!a->get(2, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - left = obj2.getNum(); - obj2.free(); - - // unknown link kind - } else { - error(-1, "Unknown annotation destination type"); - goto err2; - } - - obj1.free(); - ok = gTrue; - return; - - err1: - obj2.free(); - err2: - obj1.free(); -} - -LinkDest::LinkDest(LinkDest *dest) { - kind = dest->kind; - pageIsRef = dest->pageIsRef; - if (pageIsRef) - pageRef = dest->pageRef; - else - pageNum = dest->pageNum; - left = dest->left; - bottom = dest->bottom; - right = dest->right; - top = dest->top; - zoom = dest->zoom; - changeLeft = dest->changeLeft; - changeTop = dest->changeTop; - changeZoom = dest->changeZoom; - ok = gTrue; -} - -//------------------------------------------------------------------------ -// LinkGoTo -//------------------------------------------------------------------------ - -LinkGoTo::LinkGoTo(Object *destObj) { - dest = NULL; - namedDest = NULL; - - // named destination - if (destObj->isName()) { - namedDest = new UGString(destObj->getName()); - } else if (destObj->isString()) { - namedDest = new UGString(*destObj->getString()); - - // destination dictionary - } else if (destObj->isArray()) { - dest = new LinkDest(destObj->getArray()); - if (!dest->isOk()) { - delete dest; - dest = NULL; - } - - // error - } else { - error(-1, "Illegal annotation destination"); - } -} - -LinkGoTo::~LinkGoTo() { - if (dest) - delete dest; - if (namedDest) - delete namedDest; -} - -//------------------------------------------------------------------------ -// LinkGoToR -//------------------------------------------------------------------------ - -LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) { - dest = NULL; - namedDest = NULL; - - // get file name - fileName = getFileSpecName(fileSpecObj); - - // named destination - if (destObj->isName()) { - namedDest = new UGString(destObj->getName()); - } else if (destObj->isString()) { - namedDest = new UGString(*destObj->getString()); - - // destination dictionary - } else if (destObj->isArray()) { - dest = new LinkDest(destObj->getArray()); - if (!dest->isOk()) { - delete dest; - dest = NULL; - } - - // error - } else { - error(-1, "Illegal annotation destination"); - } -} - -LinkGoToR::~LinkGoToR() { - if (fileName) - delete fileName; - if (dest) - delete dest; - if (namedDest) - delete namedDest; -} - - -//------------------------------------------------------------------------ -// LinkLaunch -//------------------------------------------------------------------------ - -LinkLaunch::LinkLaunch(Object *actionObj) { - Object obj1, obj2; - - fileName = NULL; - params = NULL; - - if (actionObj->isDict()) { - if (!actionObj->dictLookup("F", &obj1)->isNull()) { - fileName = getFileSpecName(&obj1); - } else { - obj1.free(); -#ifdef WIN32 - if (actionObj->dictLookup("Win", &obj1)->isDict()) { - obj1.dictLookup("F", &obj2); - fileName = getFileSpecName(&obj2); - obj2.free(); - if (obj1.dictLookup("P", &obj2)->isString()) { - params = obj2.getString()->copy(); - } - obj2.free(); - } else { - error(-1, "Bad launch-type link action"); - } -#else - //~ This hasn't been defined by Adobe yet, so assume it looks - //~ just like the Win dictionary until they say otherwise. - if (actionObj->dictLookup("Unix", &obj1)->isDict()) { - obj1.dictLookup("F", &obj2); - fileName = getFileSpecName(&obj2); - obj2.free(); - if (obj1.dictLookup("P", &obj2)->isString()) { - params = obj2.getString()->copy(); - } - obj2.free(); - } else { - error(-1, "Bad launch-type link action"); - } -#endif - } - obj1.free(); - } -} - -LinkLaunch::~LinkLaunch() { - if (fileName) - delete fileName; - if (params) - delete params; -} - -//------------------------------------------------------------------------ -// LinkURI -//------------------------------------------------------------------------ - -LinkURI::LinkURI(Object *uriObj, GString *baseURI) { - GString *uri2; - int n; - char c; - - uri = NULL; - if (uriObj->isString()) { - uri2 = uriObj->getString()->copy(); - if (baseURI && baseURI->getLength() > 0) { - n = strcspn(uri2->getCString(), "/:"); - if (n == uri2->getLength() || uri2->getChar(n) == '/') { - uri = baseURI->copy(); - c = uri->getChar(uri->getLength() - 1); - if (c == '/' || c == '?') { - if (uri2->getChar(0) == '/') { - uri2->del(0); - } - } else { - if (uri2->getChar(0) != '/') { - uri->append('/'); - } - } - uri->append(uri2); - delete uri2; - } else { - uri = uri2; - } - } else { - uri = uri2; - } - } else { - error(-1, "Illegal URI-type link"); - } -} - -LinkURI::~LinkURI() { - if (uri) - delete uri; -} - -//------------------------------------------------------------------------ -// LinkNamed -//------------------------------------------------------------------------ - -LinkNamed::LinkNamed(Object *nameObj) { - name = NULL; - if (nameObj->isName()) { - name = new GString(nameObj->getName()); - } -} - -LinkNamed::~LinkNamed() { - if (name) { - delete name; - } -} - -//------------------------------------------------------------------------ -// LinkMovie -//------------------------------------------------------------------------ - -LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) { - annotRef.num = -1; - title = NULL; - if (annotObj->isRef()) { - annotRef = annotObj->getRef(); - } else if (titleObj->isString()) { - title = titleObj->getString()->copy(); - } else { - error(-1, "Movie action is missing both the Annot and T keys"); - } -} - -LinkMovie::~LinkMovie() { - if (title) { - delete title; - } -} - -//------------------------------------------------------------------------ -// LinkUnknown -//------------------------------------------------------------------------ - -LinkUnknown::LinkUnknown(const char *actionA) { - action = new GString(actionA); -} - -LinkUnknown::~LinkUnknown() { - delete action; -} - -//------------------------------------------------------------------------ -// LinkBorderStyle -//------------------------------------------------------------------------ - -LinkBorderStyle::LinkBorderStyle(LinkBorderType typeA, double widthA, - double *dashA, int dashLengthA, - double rA, double gA, double bA) { - type = typeA; - width = widthA; - dash = dashA; - dashLength = dashLengthA; - r = rA; - g = gA; - b = bA; -} - -LinkBorderStyle::~LinkBorderStyle() { - if (dash) { - gfree(dash); - } -} - -//------------------------------------------------------------------------ -// Link -//------------------------------------------------------------------------ - -Link::Link(Dict *dict, GString *baseURI) { - Object obj1, obj2, obj3; - LinkBorderType borderType; - double borderWidth; - double *borderDash; - int borderDashLength; - double borderR, borderG, borderB; - double t; - int i; - - borderStyle = NULL; - action = NULL; - ok = gFalse; - - // get rectangle - if (!dict->lookup("Rect", &obj1)->isArray()) { - error(-1, "Annotation rectangle is wrong type"); - goto err2; - } - if (!obj1.arrayGet(0, &obj2)->isNum()) { - error(-1, "Bad annotation rectangle"); - goto err1; - } - x1 = obj2.getNum(); - obj2.free(); - if (!obj1.arrayGet(1, &obj2)->isNum()) { - error(-1, "Bad annotation rectangle"); - goto err1; - } - y1 = obj2.getNum(); - obj2.free(); - if (!obj1.arrayGet(2, &obj2)->isNum()) { - error(-1, "Bad annotation rectangle"); - goto err1; - } - x2 = obj2.getNum(); - obj2.free(); - if (!obj1.arrayGet(3, &obj2)->isNum()) { - error(-1, "Bad annotation rectangle"); - goto err1; - } - y2 = obj2.getNum(); - obj2.free(); - obj1.free(); - if (x1 > x2) { - t = x1; - x1 = x2; - x2 = t; - } - if (y1 > y2) { - t = y1; - y1 = y2; - y2 = t; - } - - // get the border style info - borderType = linkBorderSolid; - borderWidth = 1; - borderDash = NULL; - borderDashLength = 0; - borderR = 0; - borderG = 0; - borderB = 1; - if (dict->lookup("BS", &obj1)->isDict()) { - if (obj1.dictLookup("S", &obj2)->isName()) { - if (obj2.isName("S")) { - borderType = linkBorderSolid; - } else if (obj2.isName("D")) { - borderType = linkBorderDashed; - } else if (obj2.isName("B")) { - borderType = linkBorderEmbossed; - } else if (obj2.isName("I")) { - borderType = linkBorderEngraved; - } else if (obj2.isName("U")) { - borderType = linkBorderUnderlined; - } - } - obj2.free(); - if (obj1.dictLookup("W", &obj2)->isNum()) { - borderWidth = obj2.getNum(); - } - obj2.free(); - if (obj1.dictLookup("D", &obj2)->isArray()) { - borderDashLength = obj2.arrayGetLength(); - borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); - for (i = 0; i < borderDashLength; ++i) { - if (obj2.arrayGet(i, &obj3)->isNum()) { - borderDash[i] = obj3.getNum(); - } else { - borderDash[i] = 1; - } - obj3.free(); - } - } - obj2.free(); - } else { - obj1.free(); - if (dict->lookup("Border", &obj1)->isArray()) { - if (obj1.arrayGetLength() >= 3) { - if (obj1.arrayGet(2, &obj2)->isNum()) { - borderWidth = obj2.getNum(); - } - obj2.free(); - if (obj1.arrayGetLength() >= 4) { - if (obj1.arrayGet(3, &obj2)->isArray()) { - borderType = linkBorderDashed; - borderDashLength = obj2.arrayGetLength(); - borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); - for (i = 0; i < borderDashLength; ++i) { - if (obj2.arrayGet(i, &obj3)->isNum()) { - borderDash[i] = obj3.getNum(); - } else { - borderDash[i] = 1; - } - obj3.free(); - } - } else { - // Adobe draws no border at all if the last element is of - // the wrong type. - borderWidth = 0; - } - obj2.free(); - } - } - } - } - obj1.free(); - if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) { - if (obj1.arrayGet(0, &obj2)->isNum()) { - borderR = obj2.getNum(); - } - obj1.free(); - if (obj1.arrayGet(1, &obj2)->isNum()) { - borderG = obj2.getNum(); - } - obj1.free(); - if (obj1.arrayGet(2, &obj2)->isNum()) { - borderB = obj2.getNum(); - } - obj1.free(); - } - obj1.free(); - borderStyle = new LinkBorderStyle(borderType, borderWidth, - borderDash, borderDashLength, - borderR, borderG, borderB); - - // look for destination - if (!dict->lookup("Dest", &obj1)->isNull()) { - action = LinkAction::parseDest(&obj1); - - // look for action - } else { - obj1.free(); - if (dict->lookup("A", &obj1)->isDict()) { - action = LinkAction::parseAction(&obj1, baseURI); - } - } - obj1.free(); - - // check for bad action - if (action) { - ok = gTrue; - } - - return; - - err1: - obj2.free(); - err2: - obj1.free(); -} - -Link::~Link() { - if (borderStyle) { - delete borderStyle; - } - if (action) { - delete action; - } -} - -//------------------------------------------------------------------------ -// Links -//------------------------------------------------------------------------ - -Links::Links(Object *annots, GString *baseURI) { - Link *link; - Object obj1, obj2; - int size; - int i; - - links = NULL; - size = 0; - numLinks = 0; - - if (annots->isArray()) { - for (i = 0; i < annots->arrayGetLength(); ++i) { - if (annots->arrayGet(i, &obj1)->isDict()) { - if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) { - link = new Link(obj1.getDict(), baseURI); - if (link->isOk()) { - if (numLinks >= size) { - size += 16; - links = (Link **)greallocn(links, size, sizeof(Link *)); - } - links[numLinks++] = link; - } else { - delete link; - } - } - obj2.free(); - } - obj1.free(); - } - } -} - -Links::~Links() { - int i; - - for (i = 0; i < numLinks; ++i) - delete links[i]; - gfree(links); -} - -LinkAction *Links::find(double x, double y) { - int i; - - for (i = numLinks - 1; i >= 0; --i) { - if (links[i]->inRect(x, y)) { - return links[i]->getAction(); - } - } - return NULL; -} - -GBool Links::onLink(double x, double y) { - int i; - - for (i = 0; i < numLinks; ++i) { - if (links[i]->inRect(x, y)) - return gTrue; - } - return gFalse; -} diff --git a/xpdf/xpdf/Link.h b/xpdf/xpdf/Link.h deleted file mode 100644 index c2c973466..000000000 --- a/xpdf/xpdf/Link.h +++ /dev/null @@ -1,410 +0,0 @@ -//======================================================================== -// -// Link.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef LINK_H -#define LINK_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" - -class GString; -class UGString; -class Array; -class Dict; - -//------------------------------------------------------------------------ -// LinkAction -//------------------------------------------------------------------------ - -enum LinkActionKind { - actionGoTo, // go to destination - actionGoToR, // go to destination in new file - actionLaunch, // launch app (or open document) - actionURI, // URI - actionNamed, // named action - actionMovie, // movie action - actionUnknown // anything else -}; - -class LinkAction { -public: - - // Destructor. - virtual ~LinkAction() {} - - // Was the LinkAction created successfully? - virtual GBool isOk() = 0; - - // Check link action type. - virtual LinkActionKind getKind() = 0; - - // Parse a destination (old-style action) name, string, or array. - static LinkAction *parseDest(Object *obj); - - // Parse an action dictionary. - static LinkAction *parseAction(Object *obj, GString *baseURI = NULL); - - // Extract a file name from a file specification (string or - // dictionary). - static GString *getFileSpecName(Object *fileSpecObj); -}; - -//------------------------------------------------------------------------ -// LinkDest -//------------------------------------------------------------------------ - -enum LinkDestKind { - destXYZ, - destFit, - destFitH, - destFitV, - destFitR, - destFitB, - destFitBH, - destFitBV -}; - -class LinkDest { -public: - - // Build a LinkDest from the array. - LinkDest(Array *a); - - // Copy a LinkDest. - LinkDest *copy() { return new LinkDest(this); } - - // Was the LinkDest created successfully? - GBool isOk() { return ok; } - - // Accessors. - LinkDestKind getKind() { return kind; } - GBool isPageRef() { return pageIsRef; } - int getPageNum() { return pageNum; } - Ref getPageRef() { return pageRef; } - double getLeft() { return left; } - double getBottom() { return bottom; } - double getRight() { return right; } - double getTop() { return top; } - double getZoom() { return zoom; } - GBool getChangeLeft() { return changeLeft; } - GBool getChangeTop() { return changeTop; } - GBool getChangeZoom() { return changeZoom; } - -private: - - LinkDestKind kind; // destination type - GBool pageIsRef; // is the page a reference or number? - union { - Ref pageRef; // reference to page - int pageNum; // one-relative page number - }; - double left, bottom; // position - double right, top; - double zoom; // zoom factor - GBool changeLeft, changeTop; // for destXYZ links, which position - GBool changeZoom; // components to change - GBool ok; // set if created successfully - - LinkDest(LinkDest *dest); -}; - -//------------------------------------------------------------------------ -// LinkGoTo -//------------------------------------------------------------------------ - -class LinkGoTo: public LinkAction { -public: - - // Build a LinkGoTo from a destination (dictionary, name, or string). - LinkGoTo(Object *destObj); - - // Destructor. - virtual ~LinkGoTo(); - - // Was the LinkGoTo created successfully? - virtual GBool isOk() { return dest || namedDest; } - - // Accessors. - virtual LinkActionKind getKind() { return actionGoTo; } - LinkDest *getDest() { return dest; } - UGString *getNamedDest() { return namedDest; } - -private: - - LinkDest *dest; // regular destination (NULL for remote - // link with bad destination) - UGString *namedDest; // named destination (only one of dest and - // and namedDest may be non-NULL) -}; - -//------------------------------------------------------------------------ -// LinkGoToR -//------------------------------------------------------------------------ - -class LinkGoToR: public LinkAction { -public: - - // Build a LinkGoToR from a file spec (dictionary) and destination - // (dictionary, name, or string). - LinkGoToR(Object *fileSpecObj, Object *destObj); - - // Destructor. - virtual ~LinkGoToR(); - - // Was the LinkGoToR created successfully? - virtual GBool isOk() { return fileName && (dest || namedDest); } - - // Accessors. - virtual LinkActionKind getKind() { return actionGoToR; } - GString *getFileName() { return fileName; } - LinkDest *getDest() { return dest; } - UGString *getNamedDest() { return namedDest; } - -private: - - GString *fileName; // file name - LinkDest *dest; // regular destination (NULL for remote - // link with bad destination) - UGString *namedDest; // named destination (only one of dest and - // and namedDest may be non-NULL) -}; - -//------------------------------------------------------------------------ -// LinkLaunch -//------------------------------------------------------------------------ - -class LinkLaunch: public LinkAction { -public: - - // Build a LinkLaunch from an action dictionary. - LinkLaunch(Object *actionObj); - - // Destructor. - virtual ~LinkLaunch(); - - // Was the LinkLaunch created successfully? - virtual GBool isOk() { return fileName != NULL; } - - // Accessors. - virtual LinkActionKind getKind() { return actionLaunch; } - GString *getFileName() { return fileName; } - GString *getParams() { return params; } - -private: - - GString *fileName; // file name - GString *params; // parameters -}; - -//------------------------------------------------------------------------ -// LinkURI -//------------------------------------------------------------------------ - -class LinkURI: public LinkAction { -public: - - // Build a LinkURI given the URI (string) and base URI. - LinkURI(Object *uriObj, GString *baseURI); - - // Destructor. - virtual ~LinkURI(); - - // Was the LinkURI created successfully? - virtual GBool isOk() { return uri != NULL; } - - // Accessors. - virtual LinkActionKind getKind() { return actionURI; } - GString *getURI() { return uri; } - -private: - - GString *uri; // the URI -}; - -//------------------------------------------------------------------------ -// LinkNamed -//------------------------------------------------------------------------ - -class LinkNamed: public LinkAction { -public: - - // Build a LinkNamed given the action name. - LinkNamed(Object *nameObj); - - virtual ~LinkNamed(); - - virtual GBool isOk() { return name != NULL; } - - virtual LinkActionKind getKind() { return actionNamed; } - GString *getName() { return name; } - -private: - - GString *name; -}; - -//------------------------------------------------------------------------ -// LinkMovie -//------------------------------------------------------------------------ - -class LinkMovie: public LinkAction { -public: - - LinkMovie(Object *annotObj, Object *titleObj); - - virtual ~LinkMovie(); - - virtual GBool isOk() { return annotRef.num >= 0 || title != NULL; } - - virtual LinkActionKind getKind() { return actionMovie; } - GBool hasAnnotRef() { return annotRef.num >= 0; } - Ref *getAnnotRef() { return &annotRef; } - GString *getTitle() { return title; } - -private: - - Ref annotRef; - GString *title; -}; - -//------------------------------------------------------------------------ -// LinkUnknown -//------------------------------------------------------------------------ - -class LinkUnknown: public LinkAction { -public: - - // Build a LinkUnknown with the specified action type. - LinkUnknown(const char *actionA); - - // Destructor. - virtual ~LinkUnknown(); - - // Was the LinkUnknown create successfully? - virtual GBool isOk() { return action != NULL; } - - // Accessors. - virtual LinkActionKind getKind() { return actionUnknown; } - GString *getAction() { return action; } - -private: - - GString *action; // action subtype -}; - -//------------------------------------------------------------------------ -// LinkBorderStyle -//------------------------------------------------------------------------ - -enum LinkBorderType { - linkBorderSolid, - linkBorderDashed, - linkBorderEmbossed, - linkBorderEngraved, - linkBorderUnderlined -}; - -class LinkBorderStyle { -public: - - LinkBorderStyle(LinkBorderType typeA, double widthA, - double *dashA, int dashLengthA, - double rA, double gA, double bA); - ~LinkBorderStyle(); - - LinkBorderType getType() { return type; } - double getWidth() { return width; } - void getDash(double **dashA, int *dashLengthA) - { *dashA = dash; *dashLengthA = dashLength; } - void getColor(double *rA, double *gA, double *bA) - { *rA = r; *gA = g; *bA = b; } - -private: - - LinkBorderType type; - double width; - double *dash; - int dashLength; - double r, g, b; -}; - -//------------------------------------------------------------------------ -// Link -//------------------------------------------------------------------------ - -class Link { -public: - - // Construct a link, given its dictionary. - Link(Dict *dict, GString *baseURI); - - // Destructor. - ~Link(); - - // Was the link created successfully? - GBool isOk() { return ok; } - - // Check if point is inside the link rectangle. - GBool inRect(double x, double y) - { return x1 <= x && x <= x2 && y1 <= y && y <= y2; } - - // Get action. - LinkAction *getAction() { return action; } - - // Get the link rectangle. - void getRect(double *xa1, double *ya1, double *xa2, double *ya2) - { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; } - - // Get the border style info. - LinkBorderStyle *getBorderStyle() { return borderStyle; } - -private: - - double x1, y1; // lower left corner - double x2, y2; // upper right corner - LinkBorderStyle *borderStyle; // border style - LinkAction *action; // action - GBool ok; // is link valid? -}; - -//------------------------------------------------------------------------ -// Links -//------------------------------------------------------------------------ - -class Links { -public: - - // Extract links from array of annotations. - Links(Object *annots, GString *baseURI); - - // Destructor. - ~Links(); - - // Iterate through list of links. - int getNumLinks() { return numLinks; } - Link *getLink(int i) { return links[i]; } - - // If point , is in a link, return the associated action; - // else return NULL. - LinkAction *find(double x, double y); - - // Return true if , is in a link. - GBool onLink(double x, double y); - -private: - - Link **links; - int numLinks; -}; - -#endif diff --git a/xpdf/xpdf/Makefile.am b/xpdf/xpdf/Makefile.am deleted file mode 100644 index f24d09dd9..000000000 --- a/xpdf/xpdf/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../fofi -I$(srcdir)/../splash -I$(srcdir)/../goo $(all_includes) $(LIBFREETYPE_CFLAGS) $(XFT_CFLAGS) $(X_INCLUDES) $(QT_INCLUDES) - -libxpdf_la_LDFLAGS = $(all_libraries) -libxpdf_la_LIBADD = $(LIB_X11) $(LIBFREETYPE_LIBS) $(LIBPAPER_LIBS) $(XFT_LIBS) $(LIBJPEG) ../goo/libgoo.la ../fofi/libfofi.la ../splash/libsplash.la -libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ - Catalog.cc CharCodeToUnicode.cc CMap.cc Decrypt.cc Dict.cc DCTStream.cc \ - FontEncodingTables.cc Function.cc Gfx.cc \ - GfxFont.cc GfxState.cc GlobalParams.cc JArithmeticDecoder.cc \ - JBIG2Stream.cc Lexer.cc Link.cc NameToCharCode.cc Object.cc Outline.cc \ - OutputDev.cc PDFDoc.cc PDFDocEncoding.cc PSTokenizer.cc \ - Page.cc Parser.cc PSOutputDev.cc SecurityHandler.cc SplashOutputDev.cc Stream.cc JPXStream.cc \ - TextOutputDev.cc UnicodeMap.cc UnicodeTypeTable.cc UGString.cc XRef.cc - -noinst_LTLIBRARIES = libxpdf.la - -# This fixes crash in Bug 109015 which i assume is a compiler bug -# as adding some correctly placed printf in SplashOutputDev::convertPath() makes this -# option unneeded -KDE_CXXFLAGS=$(NOREGMOVE) diff --git a/xpdf/xpdf/NameToCharCode.cc b/xpdf/xpdf/NameToCharCode.cc deleted file mode 100644 index a2438cb96..000000000 --- a/xpdf/xpdf/NameToCharCode.cc +++ /dev/null @@ -1,116 +0,0 @@ -//======================================================================== -// -// NameToCharCode.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "NameToCharCode.h" - -//------------------------------------------------------------------------ - -struct NameToCharCodeEntry { - const char *name; - CharCode c; -}; - -//------------------------------------------------------------------------ - -NameToCharCode::NameToCharCode() { - int i; - - size = 31; - len = 0; - tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); - for (i = 0; i < size; ++i) { - tab[i].name = NULL; - } -} - -NameToCharCode::~NameToCharCode() { - int i; - - for (i = 0; i < size; ++i) { - if (tab[i].name) { - gfree((void*)tab[i].name); - } - } - gfree(tab); -} - -void NameToCharCode::add(const char *name, CharCode c) { - NameToCharCodeEntry *oldTab; - int h, i, oldSize; - - // expand the table if necessary - if (len >= size / 2) { - oldSize = size; - oldTab = tab; - size = 2*size + 1; - tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); - for (h = 0; h < size; ++h) { - tab[h].name = NULL; - } - for (i = 0; i < oldSize; ++i) { - if (oldTab[i].name) { - h = hash(oldTab[i].name); - while (tab[h].name) { - if (++h == size) { - h = 0; - } - } - tab[h] = oldTab[i]; - } - } - gfree(oldTab); - } - - // add the new name - h = hash(name); - while (tab[h].name && strcmp(tab[h].name, name)) { - if (++h == size) { - h = 0; - } - } - if (!tab[h].name) { - tab[h].name = copyString(name); - } - tab[h].c = c; - - ++len; -} - -CharCode NameToCharCode::lookup(const char *name) { - int h; - - h = hash(name); - while (tab[h].name) { - if (!strcmp(tab[h].name, name)) { - return tab[h].c; - } - if (++h == size) { - h = 0; - } - } - return 0; -} - -int NameToCharCode::hash(const char *name) { - const char *p; - unsigned int h; - - h = 0; - for (p = name; *p; ++p) { - h = 17 * h + (int)(*p & 0xff); - } - return (int)(h % size); -} diff --git a/xpdf/xpdf/NameToCharCode.h b/xpdf/xpdf/NameToCharCode.h deleted file mode 100644 index 6548133cd..000000000 --- a/xpdf/xpdf/NameToCharCode.h +++ /dev/null @@ -1,42 +0,0 @@ -//======================================================================== -// -// NameToCharCode.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef NAMETOCHARCODE_H -#define NAMETOCHARCODE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "CharTypes.h" - -struct NameToCharCodeEntry; - -//------------------------------------------------------------------------ - -class NameToCharCode { -public: - - NameToCharCode(); - ~NameToCharCode(); - - void add(const char *name, CharCode c); - CharCode lookup(const char *name); - -private: - - int hash(const char *name); - - NameToCharCodeEntry *tab; - int size; - int len; -}; - -#endif diff --git a/xpdf/xpdf/NameToUnicodeTable.h b/xpdf/xpdf/NameToUnicodeTable.h deleted file mode 100644 index 7ef1cf029..000000000 --- a/xpdf/xpdf/NameToUnicodeTable.h +++ /dev/null @@ -1,1097 +0,0 @@ -//======================================================================== -// -// NameToUnicodeTable.h -// -// Copyright 2001-2004 Glyph & Cog, LLC -// -//======================================================================== - -static struct { - Unicode u; - const char *name; -} nameToUnicodeTab[] = { - {0x0021, "!"}, - {0x0023, "#"}, - {0x0024, "$"}, - {0x0025, "%"}, - {0x0026, "&"}, - {0x0027, "'"}, - {0x0028, "("}, - {0x0029, ")"}, - {0x002a, "*"}, - {0x002b, "+"}, - {0x002c, ","}, - {0x002d, "-"}, - {0x002e, "."}, - {0x002f, "/"}, - {0x0030, "0"}, - {0x0031, "1"}, - {0x0032, "2"}, - {0x0033, "3"}, - {0x0034, "4"}, - {0x0035, "5"}, - {0x0036, "6"}, - {0x0037, "7"}, - {0x0038, "8"}, - {0x0039, "9"}, - {0x003a, ":"}, - {0x003b, ";"}, - {0x003c, "<"}, - {0x003d, "="}, - {0x003e, ">"}, - {0x003f, "?"}, - {0x0040, "@"}, - {0x0041, "A"}, - {0x00c6, "AE"}, - {0x01fc, "AEacute"}, - {0xf7e6, "AEsmall"}, - {0x00c1, "Aacute"}, - {0xf7e1, "Aacutesmall"}, - {0x0102, "Abreve"}, - {0x00c2, "Acircumflex"}, - {0xf7e2, "Acircumflexsmall"}, - {0xf6c9, "Acute"}, - {0xf7b4, "Acutesmall"}, - {0x00c4, "Adieresis"}, - {0xf7e4, "Adieresissmall"}, - {0x00c0, "Agrave"}, - {0xf7e0, "Agravesmall"}, - {0x0391, "Alpha"}, - {0x0386, "Alphatonos"}, - {0x0100, "Amacron"}, - {0x0104, "Aogonek"}, - {0x00c5, "Aring"}, - {0x01fa, "Aringacute"}, - {0xf7e5, "Aringsmall"}, - {0xf761, "Asmall"}, - {0x00c3, "Atilde"}, - {0xf7e3, "Atildesmall"}, - {0x0042, "B"}, - {0x0392, "Beta"}, - {0xf6f4, "Brevesmall"}, - {0xf762, "Bsmall"}, - {0x0043, "C"}, - {0x0106, "Cacute"}, - {0xf6ca, "Caron"}, - {0xf6f5, "Caronsmall"}, - {0x010c, "Ccaron"}, - {0x00c7, "Ccedilla"}, - {0xf7e7, "Ccedillasmall"}, - {0x0108, "Ccircumflex"}, - {0x010a, "Cdotaccent"}, - {0xf7b8, "Cedillasmall"}, - {0x03a7, "Chi"}, - {0xf6f6, "Circumflexsmall"}, - {0xf763, "Csmall"}, - {0x0044, "D"}, - {0x010e, "Dcaron"}, - {0x0110, "Dcroat"}, - {0x2206, "Delta"}, - {0xf6cb, "Dieresis"}, - {0xf6cc, "DieresisAcute"}, - {0xf6cd, "DieresisGrave"}, - {0xf7a8, "Dieresissmall"}, - {0xf6f7, "Dotaccentsmall"}, - {0xf764, "Dsmall"}, - {0x0045, "E"}, - {0x00c9, "Eacute"}, - {0xf7e9, "Eacutesmall"}, - {0x0114, "Ebreve"}, - {0x011a, "Ecaron"}, - {0x00ca, "Ecircumflex"}, - {0xf7ea, "Ecircumflexsmall"}, - {0x00cb, "Edieresis"}, - {0xf7eb, "Edieresissmall"}, - {0x0116, "Edotaccent"}, - {0x00c8, "Egrave"}, - {0xf7e8, "Egravesmall"}, - {0x0112, "Emacron"}, - {0x014a, "Eng"}, - {0x0118, "Eogonek"}, - {0x0395, "Epsilon"}, - {0x0388, "Epsilontonos"}, - {0xf765, "Esmall"}, - {0x0397, "Eta"}, - {0x0389, "Etatonos"}, - {0x00d0, "Eth"}, - {0xf7f0, "Ethsmall"}, - {0x20ac, "Euro"}, - {0x0046, "F"}, - {0xf766, "Fsmall"}, - {0x0047, "G"}, - {0x0393, "Gamma"}, - {0x011e, "Gbreve"}, - {0x01e6, "Gcaron"}, - {0x011c, "Gcircumflex"}, - {0x0122, "Gcommaaccent"}, - {0x0120, "Gdotaccent"}, - {0xf6ce, "Grave"}, - {0xf760, "Gravesmall"}, - {0xf767, "Gsmall"}, - {0x0048, "H"}, - {0x25cf, "H18533"}, - {0x25aa, "H18543"}, - {0x25ab, "H18551"}, - {0x25a1, "H22073"}, - {0x0126, "Hbar"}, - {0x0124, "Hcircumflex"}, - {0xf768, "Hsmall"}, - {0xf6cf, "Hungarumlaut"}, - {0xf6f8, "Hungarumlautsmall"}, - {0x0049, "I"}, - {0x0132, "IJ"}, - {0x00cd, "Iacute"}, - {0xf7ed, "Iacutesmall"}, - {0x012c, "Ibreve"}, - {0x00ce, "Icircumflex"}, - {0xf7ee, "Icircumflexsmall"}, - {0x00cf, "Idieresis"}, - {0xf7ef, "Idieresissmall"}, - {0x0130, "Idotaccent"}, - {0x2111, "Ifraktur"}, - {0x00cc, "Igrave"}, - {0xf7ec, "Igravesmall"}, - {0x012a, "Imacron"}, - {0x012e, "Iogonek"}, - {0x0399, "Iota"}, - {0x03aa, "Iotadieresis"}, - {0x038a, "Iotatonos"}, - {0xf769, "Ismall"}, - {0x0128, "Itilde"}, - {0x004a, "J"}, - {0x0134, "Jcircumflex"}, - {0xf76a, "Jsmall"}, - {0x004b, "K"}, - {0x039a, "Kappa"}, - {0x0136, "Kcommaaccent"}, - {0xf76b, "Ksmall"}, - {0x004c, "L"}, - {0xf6bf, "LL"}, - {0x0139, "Lacute"}, - {0x039b, "Lambda"}, - {0x013d, "Lcaron"}, - {0x013b, "Lcommaaccent"}, - {0x013f, "Ldot"}, - {0x0141, "Lslash"}, - {0xf6f9, "Lslashsmall"}, - {0xf76c, "Lsmall"}, - {0x004d, "M"}, - {0xf6d0, "Macron"}, - {0xf7af, "Macronsmall"}, - {0xf76d, "Msmall"}, - {0x039c, "Mu"}, - {0x004e, "N"}, - {0x0143, "Nacute"}, - {0x0147, "Ncaron"}, - {0x0145, "Ncommaaccent"}, - {0xf76e, "Nsmall"}, - {0x00d1, "Ntilde"}, - {0xf7f1, "Ntildesmall"}, - {0x039d, "Nu"}, - {0x004f, "O"}, - {0x0152, "OE"}, - {0xf6fa, "OEsmall"}, - {0x00d3, "Oacute"}, - {0xf7f3, "Oacutesmall"}, - {0x014e, "Obreve"}, - {0x00d4, "Ocircumflex"}, - {0xf7f4, "Ocircumflexsmall"}, - {0x00d6, "Odieresis"}, - {0xf7f6, "Odieresissmall"}, - {0xf6fb, "Ogoneksmall"}, - {0x00d2, "Ograve"}, - {0xf7f2, "Ogravesmall"}, - {0x01a0, "Ohorn"}, - {0x0150, "Ohungarumlaut"}, - {0x014c, "Omacron"}, - {0x2126, "Omega"}, - {0x038f, "Omegatonos"}, - {0x039f, "Omicron"}, - {0x038c, "Omicrontonos"}, - {0x00d8, "Oslash"}, - {0x01fe, "Oslashacute"}, - {0xf7f8, "Oslashsmall"}, - {0xf76f, "Osmall"}, - {0x00d5, "Otilde"}, - {0xf7f5, "Otildesmall"}, - {0x0050, "P"}, - {0x03a6, "Phi"}, - {0x03a0, "Pi"}, - {0x03a8, "Psi"}, - {0xf770, "Psmall"}, - {0x0051, "Q"}, - {0xf771, "Qsmall"}, - {0x0052, "R"}, - {0x0154, "Racute"}, - {0x0158, "Rcaron"}, - {0x0156, "Rcommaaccent"}, - {0x211c, "Rfraktur"}, - {0x03a1, "Rho"}, - {0xf6fc, "Ringsmall"}, - {0xf772, "Rsmall"}, - {0x0053, "S"}, - {0x250c, "SF010000"}, - {0x2514, "SF020000"}, - {0x2510, "SF030000"}, - {0x2518, "SF040000"}, - {0x253c, "SF050000"}, - {0x252c, "SF060000"}, - {0x2534, "SF070000"}, - {0x251c, "SF080000"}, - {0x2524, "SF090000"}, - {0x2500, "SF100000"}, - {0x2502, "SF110000"}, - {0x2561, "SF190000"}, - {0x2562, "SF200000"}, - {0x2556, "SF210000"}, - {0x2555, "SF220000"}, - {0x2563, "SF230000"}, - {0x2551, "SF240000"}, - {0x2557, "SF250000"}, - {0x255d, "SF260000"}, - {0x255c, "SF270000"}, - {0x255b, "SF280000"}, - {0x255e, "SF360000"}, - {0x255f, "SF370000"}, - {0x255a, "SF380000"}, - {0x2554, "SF390000"}, - {0x2569, "SF400000"}, - {0x2566, "SF410000"}, - {0x2560, "SF420000"}, - {0x2550, "SF430000"}, - {0x256c, "SF440000"}, - {0x2567, "SF450000"}, - {0x2568, "SF460000"}, - {0x2564, "SF470000"}, - {0x2565, "SF480000"}, - {0x2559, "SF490000"}, - {0x2558, "SF500000"}, - {0x2552, "SF510000"}, - {0x2553, "SF520000"}, - {0x256b, "SF530000"}, - {0x256a, "SF540000"}, - {0x015a, "Sacute"}, - {0x0160, "Scaron"}, - {0xf6fd, "Scaronsmall"}, - {0x015e, "Scedilla"}, - {0x015c, "Scircumflex"}, - {0x0218, "Scommaaccent"}, - {0x03a3, "Sigma"}, - {0xf773, "Ssmall"}, - {0x0054, "T"}, - {0x03a4, "Tau"}, - {0x0166, "Tbar"}, - {0x0164, "Tcaron"}, - {0x0162, "Tcommaaccent"}, - {0x0398, "Theta"}, - {0x00de, "Thorn"}, - {0xf7fe, "Thornsmall"}, - {0xf6fe, "Tildesmall"}, - {0xf774, "Tsmall"}, - {0x0055, "U"}, - {0x00da, "Uacute"}, - {0xf7fa, "Uacutesmall"}, - {0x016c, "Ubreve"}, - {0x00db, "Ucircumflex"}, - {0xf7fb, "Ucircumflexsmall"}, - {0x00dc, "Udieresis"}, - {0xf7fc, "Udieresissmall"}, - {0x00d9, "Ugrave"}, - {0xf7f9, "Ugravesmall"}, - {0x01af, "Uhorn"}, - {0x0170, "Uhungarumlaut"}, - {0x016a, "Umacron"}, - {0x0172, "Uogonek"}, - {0x03a5, "Upsilon"}, - {0x03d2, "Upsilon1"}, - {0x03ab, "Upsilondieresis"}, - {0x038e, "Upsilontonos"}, - {0x016e, "Uring"}, - {0xf775, "Usmall"}, - {0x0168, "Utilde"}, - {0x0056, "V"}, - {0xf776, "Vsmall"}, - {0x0057, "W"}, - {0x1e82, "Wacute"}, - {0x0174, "Wcircumflex"}, - {0x1e84, "Wdieresis"}, - {0x1e80, "Wgrave"}, - {0xf777, "Wsmall"}, - {0x0058, "X"}, - {0x039e, "Xi"}, - {0xf778, "Xsmall"}, - {0x0059, "Y"}, - {0x00dd, "Yacute"}, - {0xf7fd, "Yacutesmall"}, - {0x0176, "Ycircumflex"}, - {0x0178, "Ydieresis"}, - {0xf7ff, "Ydieresissmall"}, - {0x1ef2, "Ygrave"}, - {0xf779, "Ysmall"}, - {0x005a, "Z"}, - {0x0179, "Zacute"}, - {0x017d, "Zcaron"}, - {0xf6ff, "Zcaronsmall"}, - {0x017b, "Zdotaccent"}, - {0x0396, "Zeta"}, - {0xf77a, "Zsmall"}, - {0x0022, "\""}, - {0x005c, "\\"}, - {0x005d, "]"}, - {0x005e, "^"}, - {0x005f, "_"}, - {0x0060, "`"}, - {0x0061, "a"}, - {0x00e1, "aacute"}, - {0x0103, "abreve"}, - {0x00e2, "acircumflex"}, - {0x00b4, "acute"}, - {0x0301, "acutecomb"}, - {0x00e4, "adieresis"}, - {0x00e6, "ae"}, - {0x01fd, "aeacute"}, - {0x2015, "afii00208"}, - {0x0410, "afii10017"}, - {0x0411, "afii10018"}, - {0x0412, "afii10019"}, - {0x0413, "afii10020"}, - {0x0414, "afii10021"}, - {0x0415, "afii10022"}, - {0x0401, "afii10023"}, - {0x0416, "afii10024"}, - {0x0417, "afii10025"}, - {0x0418, "afii10026"}, - {0x0419, "afii10027"}, - {0x041a, "afii10028"}, - {0x041b, "afii10029"}, - {0x041c, "afii10030"}, - {0x041d, "afii10031"}, - {0x041e, "afii10032"}, - {0x041f, "afii10033"}, - {0x0420, "afii10034"}, - {0x0421, "afii10035"}, - {0x0422, "afii10036"}, - {0x0423, "afii10037"}, - {0x0424, "afii10038"}, - {0x0425, "afii10039"}, - {0x0426, "afii10040"}, - {0x0427, "afii10041"}, - {0x0428, "afii10042"}, - {0x0429, "afii10043"}, - {0x042a, "afii10044"}, - {0x042b, "afii10045"}, - {0x042c, "afii10046"}, - {0x042d, "afii10047"}, - {0x042e, "afii10048"}, - {0x042f, "afii10049"}, - {0x0490, "afii10050"}, - {0x0402, "afii10051"}, - {0x0403, "afii10052"}, - {0x0404, "afii10053"}, - {0x0405, "afii10054"}, - {0x0406, "afii10055"}, - {0x0407, "afii10056"}, - {0x0408, "afii10057"}, - {0x0409, "afii10058"}, - {0x040a, "afii10059"}, - {0x040b, "afii10060"}, - {0x040c, "afii10061"}, - {0x040e, "afii10062"}, - {0xf6c4, "afii10063"}, - {0xf6c5, "afii10064"}, - {0x0430, "afii10065"}, - {0x0431, "afii10066"}, - {0x0432, "afii10067"}, - {0x0433, "afii10068"}, - {0x0434, "afii10069"}, - {0x0435, "afii10070"}, - {0x0451, "afii10071"}, - {0x0436, "afii10072"}, - {0x0437, "afii10073"}, - {0x0438, "afii10074"}, - {0x0439, "afii10075"}, - {0x043a, "afii10076"}, - {0x043b, "afii10077"}, - {0x043c, "afii10078"}, - {0x043d, "afii10079"}, - {0x043e, "afii10080"}, - {0x043f, "afii10081"}, - {0x0440, "afii10082"}, - {0x0441, "afii10083"}, - {0x0442, "afii10084"}, - {0x0443, "afii10085"}, - {0x0444, "afii10086"}, - {0x0445, "afii10087"}, - {0x0446, "afii10088"}, - {0x0447, "afii10089"}, - {0x0448, "afii10090"}, - {0x0449, "afii10091"}, - {0x044a, "afii10092"}, - {0x044b, "afii10093"}, - {0x044c, "afii10094"}, - {0x044d, "afii10095"}, - {0x044e, "afii10096"}, - {0x044f, "afii10097"}, - {0x0491, "afii10098"}, - {0x0452, "afii10099"}, - {0x0453, "afii10100"}, - {0x0454, "afii10101"}, - {0x0455, "afii10102"}, - {0x0456, "afii10103"}, - {0x0457, "afii10104"}, - {0x0458, "afii10105"}, - {0x0459, "afii10106"}, - {0x045a, "afii10107"}, - {0x045b, "afii10108"}, - {0x045c, "afii10109"}, - {0x045e, "afii10110"}, - {0x040f, "afii10145"}, - {0x0462, "afii10146"}, - {0x0472, "afii10147"}, - {0x0474, "afii10148"}, - {0xf6c6, "afii10192"}, - {0x045f, "afii10193"}, - {0x0463, "afii10194"}, - {0x0473, "afii10195"}, - {0x0475, "afii10196"}, - {0xf6c7, "afii10831"}, - {0xf6c8, "afii10832"}, - {0x04d9, "afii10846"}, - {0x200e, "afii299"}, - {0x200f, "afii300"}, - {0x200d, "afii301"}, - {0x066a, "afii57381"}, - {0x060c, "afii57388"}, - {0x0660, "afii57392"}, - {0x0661, "afii57393"}, - {0x0662, "afii57394"}, - {0x0663, "afii57395"}, - {0x0664, "afii57396"}, - {0x0665, "afii57397"}, - {0x0666, "afii57398"}, - {0x0667, "afii57399"}, - {0x0668, "afii57400"}, - {0x0669, "afii57401"}, - {0x061b, "afii57403"}, - {0x061f, "afii57407"}, - {0x0621, "afii57409"}, - {0x0622, "afii57410"}, - {0x0623, "afii57411"}, - {0x0624, "afii57412"}, - {0x0625, "afii57413"}, - {0x0626, "afii57414"}, - {0x0627, "afii57415"}, - {0x0628, "afii57416"}, - {0x0629, "afii57417"}, - {0x062a, "afii57418"}, - {0x062b, "afii57419"}, - {0x062c, "afii57420"}, - {0x062d, "afii57421"}, - {0x062e, "afii57422"}, - {0x062f, "afii57423"}, - {0x0630, "afii57424"}, - {0x0631, "afii57425"}, - {0x0632, "afii57426"}, - {0x0633, "afii57427"}, - {0x0634, "afii57428"}, - {0x0635, "afii57429"}, - {0x0636, "afii57430"}, - {0x0637, "afii57431"}, - {0x0638, "afii57432"}, - {0x0639, "afii57433"}, - {0x063a, "afii57434"}, - {0x0640, "afii57440"}, - {0x0641, "afii57441"}, - {0x0642, "afii57442"}, - {0x0643, "afii57443"}, - {0x0644, "afii57444"}, - {0x0645, "afii57445"}, - {0x0646, "afii57446"}, - {0x0648, "afii57448"}, - {0x0649, "afii57449"}, - {0x064a, "afii57450"}, - {0x064b, "afii57451"}, - {0x064c, "afii57452"}, - {0x064d, "afii57453"}, - {0x064e, "afii57454"}, - {0x064f, "afii57455"}, - {0x0650, "afii57456"}, - {0x0651, "afii57457"}, - {0x0652, "afii57458"}, - {0x0647, "afii57470"}, - {0x06a4, "afii57505"}, - {0x067e, "afii57506"}, - {0x0686, "afii57507"}, - {0x0698, "afii57508"}, - {0x06af, "afii57509"}, - {0x0679, "afii57511"}, - {0x0688, "afii57512"}, - {0x0691, "afii57513"}, - {0x06ba, "afii57514"}, - {0x06d2, "afii57519"}, - {0x06d5, "afii57534"}, - {0x20aa, "afii57636"}, - {0x05be, "afii57645"}, - {0x05c3, "afii57658"}, - {0x05d0, "afii57664"}, - {0x05d1, "afii57665"}, - {0x05d2, "afii57666"}, - {0x05d3, "afii57667"}, - {0x05d4, "afii57668"}, - {0x05d5, "afii57669"}, - {0x05d6, "afii57670"}, - {0x05d7, "afii57671"}, - {0x05d8, "afii57672"}, - {0x05d9, "afii57673"}, - {0x05da, "afii57674"}, - {0x05db, "afii57675"}, - {0x05dc, "afii57676"}, - {0x05dd, "afii57677"}, - {0x05de, "afii57678"}, - {0x05df, "afii57679"}, - {0x05e0, "afii57680"}, - {0x05e1, "afii57681"}, - {0x05e2, "afii57682"}, - {0x05e3, "afii57683"}, - {0x05e4, "afii57684"}, - {0x05e5, "afii57685"}, - {0x05e6, "afii57686"}, - {0x05e7, "afii57687"}, - {0x05e8, "afii57688"}, - {0x05e9, "afii57689"}, - {0x05ea, "afii57690"}, - {0xfb2a, "afii57694"}, - {0xfb2b, "afii57695"}, - {0xfb4b, "afii57700"}, - {0xfb1f, "afii57705"}, - {0x05f0, "afii57716"}, - {0x05f1, "afii57717"}, - {0x05f2, "afii57718"}, - {0xfb35, "afii57723"}, - {0x05b4, "afii57793"}, - {0x05b5, "afii57794"}, - {0x05b6, "afii57795"}, - {0x05bb, "afii57796"}, - {0x05b8, "afii57797"}, - {0x05b7, "afii57798"}, - {0x05b0, "afii57799"}, - {0x05b2, "afii57800"}, - {0x05b1, "afii57801"}, - {0x05b3, "afii57802"}, - {0x05c2, "afii57803"}, - {0x05c1, "afii57804"}, - {0x05b9, "afii57806"}, - {0x05bc, "afii57807"}, - {0x05bd, "afii57839"}, - {0x05bf, "afii57841"}, - {0x05c0, "afii57842"}, - {0x02bc, "afii57929"}, - {0x2105, "afii61248"}, - {0x2113, "afii61289"}, - {0x2116, "afii61352"}, - {0x202c, "afii61573"}, - {0x202d, "afii61574"}, - {0x202e, "afii61575"}, - {0x200c, "afii61664"}, - {0x066d, "afii63167"}, - {0x02bd, "afii64937"}, - {0x00e0, "agrave"}, - {0x2135, "aleph"}, - {0x03b1, "alpha"}, - {0x03ac, "alphatonos"}, - {0x0101, "amacron"}, - {0x0026, "ampersand"}, - {0xf726, "ampersandsmall"}, - {0x2220, "angle"}, - {0x2329, "angleleft"}, - {0x232a, "angleright"}, - {0x0387, "anoteleia"}, - {0x0105, "aogonek"}, - {0x2248, "approxequal"}, - {0x00e5, "aring"}, - {0x01fb, "aringacute"}, - {0x2194, "arrowboth"}, - {0x21d4, "arrowdblboth"}, - {0x21d3, "arrowdbldown"}, - {0x21d0, "arrowdblleft"}, - {0x21d2, "arrowdblright"}, - {0x21d1, "arrowdblup"}, - {0x2193, "arrowdown"}, - {0xf8e7, "arrowhorizex"}, - {0x2190, "arrowleft"}, - {0x2192, "arrowright"}, - {0x2191, "arrowup"}, - {0x2195, "arrowupdn"}, - {0x21a8, "arrowupdnbse"}, - {0xf8e6, "arrowvertex"}, - {0x005e, "asciicircum"}, - {0x007e, "asciitilde"}, - {0x002a, "asterisk"}, - {0x2217, "asteriskmath"}, - {0xf6e9, "asuperior"}, - {0x0040, "at"}, - {0x00e3, "atilde"}, - {0x0062, "b"}, - {0x005c, "backslash"}, - {0x007c, "bar"}, - {0x03b2, "beta"}, - {0x2588, "block"}, - {0xf8f4, "braceex"}, - {0x007b, "braceleft"}, - {0xf8f3, "braceleftbt"}, - {0xf8f2, "braceleftmid"}, - {0xf8f1, "bracelefttp"}, - {0x007d, "braceright"}, - {0xf8fe, "bracerightbt"}, - {0xf8fd, "bracerightmid"}, - {0xf8fc, "bracerighttp"}, - {0x005b, "bracketleft"}, - {0xf8f0, "bracketleftbt"}, - {0xf8ef, "bracketleftex"}, - {0xf8ee, "bracketlefttp"}, - {0x005d, "bracketright"}, - {0xf8fb, "bracketrightbt"}, - {0xf8fa, "bracketrightex"}, - {0xf8f9, "bracketrighttp"}, - {0x02d8, "breve"}, - {0x00a6, "brokenbar"}, - {0xf6ea, "bsuperior"}, - {0x2022, "bullet"}, - {0x0063, "c"}, - {0x0107, "cacute"}, - {0x02c7, "caron"}, - {0x21b5, "carriagereturn"}, - {0x010d, "ccaron"}, - {0x00e7, "ccedilla"}, - {0x0109, "ccircumflex"}, - {0x010b, "cdotaccent"}, - {0x00b8, "cedilla"}, - {0x00a2, "cent"}, - {0xf6df, "centinferior"}, - {0xf7a2, "centoldstyle"}, - {0xf6e0, "centsuperior"}, - {0x03c7, "chi"}, - {0x25cb, "circle"}, - {0x2297, "circlemultiply"}, - {0x2295, "circleplus"}, - {0x02c6, "circumflex"}, - {0x2663, "club"}, - {0x003a, "colon"}, - {0x20a1, "colonmonetary"}, - {0x002c, "comma"}, - {0xf6c3, "commaaccent"}, - {0xf6e1, "commainferior"}, - {0xf6e2, "commasuperior"}, - {0x2245, "congruent"}, - {0x00a9, "copyright"}, - {0x00a9, "copyrightsans"}, - {0x00a9, "copyrightserif"}, - {0x00a4, "currency"}, - {0xf6d1, "cyrBreve"}, - {0xf6d2, "cyrFlex"}, - {0xf6d4, "cyrbreve"}, - {0xf6d5, "cyrflex"}, - {0x0064, "d"}, - {0x2020, "dagger"}, - {0x2021, "daggerdbl"}, - {0xf6d3, "dblGrave"}, - {0xf6d6, "dblgrave"}, - {0x010f, "dcaron"}, - {0x0111, "dcroat"}, - {0x00b0, "degree"}, - {0x03b4, "delta"}, - {0x2666, "diamond"}, - {0x00a8, "dieresis"}, - {0xf6d7, "dieresisacute"}, - {0xf6d8, "dieresisgrave"}, - {0x0385, "dieresistonos"}, - {0x00f7, "divide"}, - {0x2593, "dkshade"}, - {0x2584, "dnblock"}, - {0x0024, "dollar"}, - {0xf6e3, "dollarinferior"}, - {0xf724, "dollaroldstyle"}, - {0xf6e4, "dollarsuperior"}, - {0x20ab, "dong"}, - {0x02d9, "dotaccent"}, - {0x0323, "dotbelowcomb"}, - {0x0131, "dotlessi"}, - {0xf6be, "dotlessj"}, - {0x22c5, "dotmath"}, - {0xf6eb, "dsuperior"}, - {0x0065, "e"}, - {0x00e9, "eacute"}, - {0x0115, "ebreve"}, - {0x011b, "ecaron"}, - {0x00ea, "ecircumflex"}, - {0x00eb, "edieresis"}, - {0x0117, "edotaccent"}, - {0x00e8, "egrave"}, - {0x0038, "eight"}, - {0x2088, "eightinferior"}, - {0xf738, "eightoldstyle"}, - {0x2078, "eightsuperior"}, - {0x2208, "element"}, - {0x2026, "ellipsis"}, - {0x0113, "emacron"}, - {0x2014, "emdash"}, - {0x2205, "emptyset"}, - {0x2013, "endash"}, - {0x014b, "eng"}, - {0x0119, "eogonek"}, - {0x03b5, "epsilon"}, - {0x03ad, "epsilontonos"}, - {0x003d, "equal"}, - {0x2261, "equivalence"}, - {0x212e, "estimated"}, - {0xf6ec, "esuperior"}, - {0x03b7, "eta"}, - {0x03ae, "etatonos"}, - {0x00f0, "eth"}, - {0x0021, "exclam"}, - {0x203c, "exclamdbl"}, - {0x00a1, "exclamdown"}, - {0xf7a1, "exclamdownsmall"}, - {0x0021, "exclamleft"}, - {0xf721, "exclamsmall"}, - {0x2203, "existential"}, - {0x0066, "f"}, - {0x2640, "female"}, - {0xfb00, "ff"}, - {0xfb03, "ffi"}, - {0xfb04, "ffl"}, - {0xfb01, "fi"}, - {0x2012, "figuredash"}, - {0x25a0, "filledbox"}, - {0x25ac, "filledrect"}, - {0x0035, "five"}, - {0x215d, "fiveeighths"}, - {0x2085, "fiveinferior"}, - {0xf735, "fiveoldstyle"}, - {0x2075, "fivesuperior"}, - {0xfb02, "fl"}, - {0x0192, "florin"}, - {0x0034, "four"}, - {0x2084, "fourinferior"}, - {0xf734, "fouroldstyle"}, - {0x2074, "foursuperior"}, - {0x2044, "fraction"}, - {0x20a3, "franc"}, - {0x0067, "g"}, - {0x03b3, "gamma"}, - {0x011f, "gbreve"}, - {0x01e7, "gcaron"}, - {0x011d, "gcircumflex"}, - {0x0123, "gcommaaccent"}, - {0x0121, "gdotaccent"}, - {0x00df, "germandbls"}, - {0x2207, "gradient"}, - {0x0060, "grave"}, - {0x0300, "gravecomb"}, - {0x003e, "greater"}, - {0x2265, "greaterequal"}, - {0x00ab, "guillemotleft"}, - {0x00bb, "guillemotright"}, - {0x2039, "guilsinglleft"}, - {0x203a, "guilsinglright"}, - {0x0068, "h"}, - {0x0127, "hbar"}, - {0x0125, "hcircumflex"}, - {0x2665, "heart"}, - {0x0309, "hookabovecomb"}, - {0x2302, "house"}, - {0x02dd, "hungarumlaut"}, - {0x002d, "hyphen"}, - {0xf6e5, "hypheninferior"}, - {0xf6e6, "hyphensuperior"}, - {0x0069, "i"}, - {0x00ed, "iacute"}, - {0x012d, "ibreve"}, - {0x00ee, "icircumflex"}, - {0x00ef, "idieresis"}, - {0x00ec, "igrave"}, - {0x0133, "ij"}, - {0x012b, "imacron"}, - {0x221e, "infinity"}, - {0x222b, "integral"}, - {0x2321, "integralbt"}, - {0xf8f5, "integralex"}, - {0x2320, "integraltp"}, - {0x2229, "intersection"}, - {0x25d8, "invbullet"}, - {0x25d9, "invcircle"}, - {0x263b, "invsmileface"}, - {0x012f, "iogonek"}, - {0x03b9, "iota"}, - {0x03ca, "iotadieresis"}, - {0x0390, "iotadieresistonos"}, - {0x03af, "iotatonos"}, - {0xf6ed, "isuperior"}, - {0x0129, "itilde"}, - {0x006a, "j"}, - {0x0135, "jcircumflex"}, - {0x006b, "k"}, - {0x03ba, "kappa"}, - {0x0137, "kcommaaccent"}, - {0x0138, "kgreenlandic"}, - {0x006c, "l"}, - {0x013a, "lacute"}, - {0x03bb, "lambda"}, - {0x013e, "lcaron"}, - {0x013c, "lcommaaccent"}, - {0x0140, "ldot"}, - {0x003c, "less"}, - {0x2264, "lessequal"}, - {0x258c, "lfblock"}, - {0x20a4, "lira"}, - {0xf6c0, "ll"}, - {0x2227, "logicaland"}, - {0x00ac, "logicalnot"}, - {0x2228, "logicalor"}, - {0x017f, "longs"}, - {0x25ca, "lozenge"}, - {0x0142, "lslash"}, - {0xf6ee, "lsuperior"}, - {0x2591, "ltshade"}, - {0x006d, "m"}, - {0x00af, "macron"}, - {0x2642, "male"}, - {0x2212, "minus"}, - {0x2032, "minute"}, - {0xf6ef, "msuperior"}, - {0x00b5, "mu"}, - {0x00d7, "multiply"}, - {0x266a, "musicalnote"}, - {0x266b, "musicalnotedbl"}, - {0x006e, "n"}, - {0x0144, "nacute"}, - {0x0149, "napostrophe"}, - {0x00a0, "nbspace"}, - {0x0148, "ncaron"}, - {0x0146, "ncommaaccent"}, - {0x0039, "nine"}, - {0x2089, "nineinferior"}, - {0xf739, "nineoldstyle"}, - {0x2079, "ninesuperior"}, - {0x00a0, "nonbreakingspace"}, - {0x2209, "notelement"}, - {0x2260, "notequal"}, - {0x2284, "notsubset"}, - {0x207f, "nsuperior"}, - {0x00f1, "ntilde"}, - {0x03bd, "nu"}, - {0x0023, "numbersign"}, - {0x006f, "o"}, - {0x00f3, "oacute"}, - {0x014f, "obreve"}, - {0x00f4, "ocircumflex"}, - {0x00f6, "odieresis"}, - {0x0153, "oe"}, - {0x02db, "ogonek"}, - {0x00f2, "ograve"}, - {0x01a1, "ohorn"}, - {0x0151, "ohungarumlaut"}, - {0x014d, "omacron"}, - {0x03c9, "omega"}, - {0x03d6, "omega1"}, - {0x03ce, "omegatonos"}, - {0x03bf, "omicron"}, - {0x03cc, "omicrontonos"}, - {0x0031, "one"}, - {0x2024, "onedotenleader"}, - {0x215b, "oneeighth"}, - {0xf6dc, "onefitted"}, - {0x00bd, "onehalf"}, - {0x2081, "oneinferior"}, - {0xf731, "oneoldstyle"}, - {0x00bc, "onequarter"}, - {0x00b9, "onesuperior"}, - {0x2153, "onethird"}, - {0x25e6, "openbullet"}, - {0x00aa, "ordfeminine"}, - {0x00ba, "ordmasculine"}, - {0x221f, "orthogonal"}, - {0x00f8, "oslash"}, - {0x01ff, "oslashacute"}, - {0xf6f0, "osuperior"}, - {0x00f5, "otilde"}, - {0x0070, "p"}, - {0x00b6, "paragraph"}, - {0x0028, "parenleft"}, - {0xf8ed, "parenleftbt"}, - {0xf8ec, "parenleftex"}, - {0x208d, "parenleftinferior"}, - {0x207d, "parenleftsuperior"}, - {0xf8eb, "parenlefttp"}, - {0x0029, "parenright"}, - {0xf8f8, "parenrightbt"}, - {0xf8f7, "parenrightex"}, - {0x208e, "parenrightinferior"}, - {0x207e, "parenrightsuperior"}, - {0xf8f6, "parenrighttp"}, - {0x2202, "partialdiff"}, - {0x0025, "percent"}, - {0x002e, "period"}, - {0x00b7, "periodcentered"}, - {0xf6e7, "periodinferior"}, - {0xf6e8, "periodsuperior"}, - {0x22a5, "perpendicular"}, - {0x2030, "perthousand"}, - {0x20a7, "peseta"}, - {0x03c6, "phi"}, - {0x03d5, "phi1"}, - {0x03c0, "pi"}, - {0x002b, "plus"}, - {0x00b1, "plusminus"}, - {0x211e, "prescription"}, - {0x220f, "product"}, - {0x2282, "propersubset"}, - {0x2283, "propersuperset"}, - {0x221d, "proportional"}, - {0x03c8, "psi"}, - {0x0071, "q"}, - {0x003f, "question"}, - {0x00bf, "questiondown"}, - {0xf7bf, "questiondownsmall"}, - {0xf73f, "questionsmall"}, - {0x0022, "quotedbl"}, - {0x201e, "quotedblbase"}, - {0x201c, "quotedblleft"}, - {0x201d, "quotedblright"}, - {0x2018, "quoteleft"}, - {0x201b, "quotereversed"}, - {0x2019, "quoteright"}, - {0x201a, "quotesinglbase"}, - {0x0027, "quotesingle"}, - {0x0072, "r"}, - {0x0155, "racute"}, - {0x221a, "radical"}, - {0xf8e5, "radicalex"}, - {0x0159, "rcaron"}, - {0x0157, "rcommaaccent"}, - {0x2286, "reflexsubset"}, - {0x2287, "reflexsuperset"}, - {0x00ae, "registered"}, - {0x00ae, "registersans"}, - {0x00ae, "registerserif"}, - {0x2310, "revlogicalnot"}, - {0x03c1, "rho"}, - {0x02da, "ring"}, - {0xf6f1, "rsuperior"}, - {0x2590, "rtblock"}, - {0xf6dd, "rupiah"}, - {0x0073, "s"}, - {0x015b, "sacute"}, - {0x0161, "scaron"}, - {0x015f, "scedilla"}, - {0x015d, "scircumflex"}, - {0x0219, "scommaaccent"}, - {0x2033, "second"}, - {0x00a7, "section"}, - {0x003b, "semicolon"}, - {0x0037, "seven"}, - {0x215e, "seveneighths"}, - {0x2087, "seveninferior"}, - {0xf737, "sevenoldstyle"}, - {0x2077, "sevensuperior"}, - {0x2592, "shade"}, - {0x03c3, "sigma"}, - {0x03c2, "sigma1"}, - {0x223c, "similar"}, - {0x0036, "six"}, - {0x2086, "sixinferior"}, - {0xf736, "sixoldstyle"}, - {0x2076, "sixsuperior"}, - {0x002f, "slash"}, - {0x263a, "smileface"}, - {0x0020, "space"}, - {0x2660, "spade"}, - {0xf6f2, "ssuperior"}, - {0x00a3, "sterling"}, - {0x220b, "suchthat"}, - {0x2211, "summation"}, - {0x263c, "sun"}, - {0x0074, "t"}, - {0x03c4, "tau"}, - {0x0167, "tbar"}, - {0x0165, "tcaron"}, - {0x0163, "tcommaaccent"}, - {0x2234, "therefore"}, - {0x03b8, "theta"}, - {0x03d1, "theta1"}, - {0x00fe, "thorn"}, - {0x0033, "three"}, - {0x215c, "threeeighths"}, - {0x2083, "threeinferior"}, - {0xf733, "threeoldstyle"}, - {0x00be, "threequarters"}, - {0xf6de, "threequartersemdash"}, - {0x00b3, "threesuperior"}, - {0x02dc, "tilde"}, - {0x0303, "tildecomb"}, - {0x0384, "tonos"}, - {0x2122, "trademark"}, - {0x2122, "trademarksans"}, - {0x2122, "trademarkserif"}, - {0x25bc, "triagdn"}, - {0x25c4, "triaglf"}, - {0x25ba, "triagrt"}, - {0x25b2, "triagup"}, - {0xf6f3, "tsuperior"}, - {0x0032, "two"}, - {0x2025, "twodotenleader"}, - {0x2082, "twoinferior"}, - {0xf732, "twooldstyle"}, - {0x00b2, "twosuperior"}, - {0x2154, "twothirds"}, - {0x0075, "u"}, - {0x00fa, "uacute"}, - {0x016d, "ubreve"}, - {0x00fb, "ucircumflex"}, - {0x00fc, "udieresis"}, - {0x00f9, "ugrave"}, - {0x01b0, "uhorn"}, - {0x0171, "uhungarumlaut"}, - {0x016b, "umacron"}, - {0x005f, "underscore"}, - {0x2017, "underscoredbl"}, - {0x222a, "union"}, - {0x2200, "universal"}, - {0x0173, "uogonek"}, - {0x2580, "upblock"}, - {0x03c5, "upsilon"}, - {0x03cb, "upsilondieresis"}, - {0x03b0, "upsilondieresistonos"}, - {0x03cd, "upsilontonos"}, - {0x016f, "uring"}, - {0x0169, "utilde"}, - {0x0076, "v"}, - {0x0077, "w"}, - {0x1e83, "wacute"}, - {0x0175, "wcircumflex"}, - {0x1e85, "wdieresis"}, - {0x2118, "weierstrass"}, - {0x1e81, "wgrave"}, - {0x0078, "x"}, - {0x03be, "xi"}, - {0x0079, "y"}, - {0x00fd, "yacute"}, - {0x0177, "ycircumflex"}, - {0x00ff, "ydieresis"}, - {0x00a5, "yen"}, - {0x1ef3, "ygrave"}, - {0x007a, "z"}, - {0x017a, "zacute"}, - {0x017e, "zcaron"}, - {0x017c, "zdotaccent"}, - {0x0030, "zero"}, - {0x2080, "zeroinferior"}, - {0xf730, "zerooldstyle"}, - {0x2070, "zerosuperior"}, - {0x03b6, "zeta"}, - {0x007b, "{"}, - {0x007c, "|"}, - {0x007d, "}"}, - {0x007e, "~"}, - { 0, NULL } -}; diff --git a/xpdf/xpdf/Object.cc b/xpdf/xpdf/Object.cc deleted file mode 100644 index 9960dc5a8..000000000 --- a/xpdf/xpdf/Object.cc +++ /dev/null @@ -1,235 +0,0 @@ -//======================================================================== -// -// Object.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "Object.h" -#include "Array.h" -#include "Dict.h" -#include "Error.h" -#include "Stream.h" -#include "XRef.h" - -//------------------------------------------------------------------------ -// Object -//------------------------------------------------------------------------ - -const char *objTypeNames[numObjTypes] = { - "boolean", - "integer", - "real", - "string", - "name", - "null", - "array", - "dictionary", - "stream", - "ref", - "cmd", - "error", - "eof", - "none" -}; - -#ifdef DEBUG_MEM -int Object::numAlloc[numObjTypes] = - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -#endif - -Object *Object::initArray(XRef *xref) { - initObj(objArray); - array = new Array(xref); - return this; -} - -Object *Object::initDict(XRef *xref) { - initObj(objDict); - dict = new Dict(xref); - return this; -} - -Object *Object::initDict(Dict *dictA) { - initObj(objDict); - dict = dictA; - dict->incRef(); - return this; -} - -Object *Object::initStream(Stream *streamA) { - initObj(objStream); - stream = streamA; - return this; -} - -Object *Object::copy(Object *obj) { - *obj = *this; - switch (type) { - case objString: - obj->string = string->copy(); - break; - case objName: - obj->name = copyString(name); - break; - case objArray: - array->incRef(); - break; - case objDict: - dict->incRef(); - break; - case objStream: - stream->incRef(); - break; - case objCmd: - obj->cmd = copyString(cmd); - break; - default: - break; - } -#ifdef DEBUG_MEM - ++numAlloc[type]; -#endif - return obj; -} - -Object *Object::fetch(XRef *xref, Object *obj) { - return (type == objRef && xref) ? - xref->fetch(ref.num, ref.gen, obj) : copy(obj); -} - -void Object::free() { - switch (type) { - case objString: - delete string; - break; - case objName: - gfree((void*)name); - break; - case objArray: - if (!array->decRef()) { - delete array; - } - break; - case objDict: - if (!dict->decRef()) { - delete dict; - } - break; - case objStream: - if (!stream->decRef()) { - delete stream; - } - break; - case objCmd: - gfree((void*)cmd); - break; - default: - break; - } -#ifdef DEBUG_MEM - --numAlloc[type]; -#endif - type = objNone; -} - -const char *Object::getTypeName() { - return objTypeNames[type]; -} - -void Object::print(FILE *f) { - Object obj; - int i; - - switch (type) { - case objBool: - fprintf(f, "%s", booln ? "true" : "false"); - break; - case objInt: - fprintf(f, "%d", intg); - break; - case objReal: - fprintf(f, "%g", real); - break; - case objString: - fprintf(f, "("); - fwrite(string->getCString(), 1, string->getLength(), f); - fprintf(f, ")"); - break; - case objName: - fprintf(f, "/%s", name); - break; - case objNull: - fprintf(f, "null"); - break; - case objArray: - fprintf(f, "["); - for (i = 0; i < arrayGetLength(); ++i) { - if (i > 0) - fprintf(f, " "); - arrayGetNF(i, &obj); - obj.print(f); - obj.free(); - } - fprintf(f, "]"); - break; - case objDict: - fprintf(f, "<<"); - for (i = 0; i < dictGetLength(); ++i) { - fprintf(f, " /%s ", dictGetKey(i)); - dictGetValNF(i, &obj); - obj.print(f); - obj.free(); - } - fprintf(f, " >>"); - break; - case objStream: - fprintf(f, ""); - break; - case objRef: - fprintf(f, "%d %d R", ref.num, ref.gen); - break; - case objCmd: - fprintf(f, "%s", cmd); - break; - case objError: - fprintf(f, ""); - break; - case objEOF: - fprintf(f, ""); - break; - case objNone: - fprintf(f, ""); - break; - } -} - -void Object::memCheck(FILE * -#ifdef DEBUG_MEM - f -#endif -) { -#ifdef DEBUG_MEM - int i; - int t; - - t = 0; - for (i = 0; i < numObjTypes; ++i) - t += numAlloc[i]; - if (t > 0) { - fprintf(f, "Allocated objects:\n"); - for (i = 0; i < numObjTypes; ++i) { - if (numAlloc[i] > 0) - fprintf(f, " %-20s: %6d\n", objTypeNames[i], numAlloc[i]); - } - } -#endif -} diff --git a/xpdf/xpdf/Object.h b/xpdf/xpdf/Object.h deleted file mode 100644 index 2a1d927be..000000000 --- a/xpdf/xpdf/Object.h +++ /dev/null @@ -1,304 +0,0 @@ -//======================================================================== -// -// Object.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef OBJECT_H -#define OBJECT_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include -#include "gtypes.h" -#include "gmem.h" -#include "GString.h" - -class XRef; -class Array; -class Dict; -class Stream; -class UGString; - -//------------------------------------------------------------------------ -// Ref -//------------------------------------------------------------------------ - -struct Ref { - int num; // object number - int gen; // generation number -}; - -//------------------------------------------------------------------------ -// object types -//------------------------------------------------------------------------ - -enum ObjType { - // simple objects - objBool, // boolean - objInt, // integer - objReal, // real - objString, // string - objName, // name - objNull, // null - - // complex objects - objArray, // array - objDict, // dictionary - objStream, // stream - objRef, // indirect reference - - // special objects - objCmd, // command name - objError, // error return from Lexer - objEOF, // end of file return from Lexer - objNone // uninitialized object -}; - -#define numObjTypes 14 // total number of object types - -//------------------------------------------------------------------------ -// Object -//------------------------------------------------------------------------ - -#ifdef DEBUG_MEM -#define initObj(t) ++numAlloc[type = t] -#else -#define initObj(t) type = t -#endif - -class Object { -public: - - // Default constructor. - Object(): - type(objNone) {} - - // Initialize an object. - Object *initBool(GBool boolnA) - { initObj(objBool); booln = boolnA; return this; } - Object *initInt(int intgA) - { initObj(objInt); intg = intgA; return this; } - Object *initReal(double realA) - { initObj(objReal); real = realA; return this; } - Object *initString(GString *stringA) - { initObj(objString); string = stringA; return this; } - Object *initName(const char *nameA) - { initObj(objName); name = copyString(nameA); return this; } - Object *initNull() - { initObj(objNull); return this; } - Object *initArray(XRef *xref); - Object *initDict(XRef *xref); - Object *initDict(Dict *dictA); - Object *initStream(Stream *streamA); - Object *initRef(int numA, int genA) - { initObj(objRef); ref.num = numA; ref.gen = genA; return this; } - Object *initCmd(const char *cmdA) - { initObj(objCmd); cmd = copyString(cmdA); return this; } - Object *initError() - { initObj(objError); return this; } - Object *initEOF() - { initObj(objEOF); return this; } - - // Copy an object. - Object *copy(Object *obj); - - // If object is a Ref, fetch and return the referenced object. - // Otherwise, return a copy of the object. - Object *fetch(XRef *xref, Object *obj); - - // Free object contents. - void free(); - - // Type checking. - ObjType getType() { return type; } - GBool isBool() { return type == objBool; } - GBool isInt() { return type == objInt; } - GBool isReal() { return type == objReal; } - GBool isNum() { return type == objInt || type == objReal; } - GBool isString() { return type == objString; } - GBool isName() { return type == objName; } - GBool isNull() { return type == objNull; } - GBool isArray() { return type == objArray; } - GBool isDict() { return type == objDict; } - GBool isStream() { return type == objStream; } - GBool isRef() { return type == objRef; } - GBool isCmd() { return type == objCmd; } - GBool isError() { return type == objError; } - GBool isEOF() { return type == objEOF; } - GBool isNone() { return type == objNone; } - - // Special type checking. - GBool isName(const char *nameA) - { return type == objName && !strcmp(name, nameA); } - GBool isDict(const char *dictType); - GBool isStream(char *dictType); - GBool isCmd(const char *cmdA) - { return type == objCmd && !strcmp(cmd, cmdA); } - - // Accessors. NB: these assume object is of correct type. - GBool getBool() { return booln; } - int getInt() { return intg; } - double getReal() { return real; } - double getNum() { return type == objInt ? (double)intg : real; } - GString *getString() { return string; } - const char *getName() { return name; } - Array *getArray() { return array; } - Dict *getDict() { return dict; } - Stream *getStream() { return stream; } - Ref getRef() { return ref; } - int getRefNum() { return ref.num; } - int getRefGen() { return ref.gen; } - const char *getCmd() { return cmd; } - - // Array accessors. - int arrayGetLength(); - void arrayAdd(Object *elem); - Object *arrayGet(int i, Object *obj); - Object *arrayGetNF(int i, Object *obj); - - // Dict accessors. - int dictGetLength(); - void dictAdd(const UGString &key, Object *val); - GBool dictIs(const char *dictType); - Object *dictLookup(const UGString &key, Object *obj); - Object *dictLookupNF(const UGString &key, Object *obj); - UGString *dictGetKey(int i); - Object *dictGetVal(int i, Object *obj); - Object *dictGetValNF(int i, Object *obj); - - // Stream accessors. - GBool streamIs(char *dictType); - void streamReset(); - void streamClose(); - int streamGetChar(); - int streamLookChar(); - char *streamGetLine(char *buf, int size); - Guint streamGetPos(); - void streamSetPos(Guint pos, int dir = 0); - Dict *streamGetDict(); - - // Output. - const char *getTypeName(); - void print(FILE *f = stdout); - - // Memory testing. - static void memCheck(FILE *f); - -private: - - ObjType type; // object type - union { // value for each type: - GBool booln; // boolean - int intg; // integer - double real; // real - GString *string; // string - const char *name; // name - Array *array; // array - Dict *dict; // dictionary - Stream *stream; // stream - Ref ref; // indirect reference - const char *cmd; // command - }; - -#ifdef DEBUG_MEM - static int // number of each type of object - numAlloc[numObjTypes]; // currently allocated -#endif -}; - -//------------------------------------------------------------------------ -// Array accessors. -//------------------------------------------------------------------------ - -#include "Array.h" - -inline int Object::arrayGetLength() - { return array->getLength(); } - -inline void Object::arrayAdd(Object *elem) - { array->add(elem); } - -inline Object *Object::arrayGet(int i, Object *obj) - { return array->get(i, obj); } - -inline Object *Object::arrayGetNF(int i, Object *obj) - { return array->getNF(i, obj); } - -//------------------------------------------------------------------------ -// Dict accessors. -//------------------------------------------------------------------------ - -#include "Dict.h" - -inline int Object::dictGetLength() - { return dict->getLength(); } - -inline void Object::dictAdd(const UGString &key, Object *val) - { dict->add(key, val); } - -inline GBool Object::dictIs(const char *dictType) - { return dict->is(dictType); } - -inline GBool Object::isDict(const char *dictType) - { return type == objDict && dictIs(dictType); } - -inline Object *Object::dictLookup(const UGString &key, Object *obj) - { return dict->lookup(key, obj); } - -inline Object *Object::dictLookupNF(const UGString &key, Object *obj) - { return dict->lookupNF(key, obj); } - -inline UGString *Object::dictGetKey(int i) - { return dict->getKey(i); } - -inline Object *Object::dictGetVal(int i, Object *obj) - { return dict->getVal(i, obj); } - -inline Object *Object::dictGetValNF(int i, Object *obj) - { return dict->getValNF(i, obj); } - -//------------------------------------------------------------------------ -// Stream accessors. -//------------------------------------------------------------------------ - -#include "Stream.h" - -inline GBool Object::streamIs(char *dictType) - { return stream->getDict()->is(dictType); } - -inline GBool Object::isStream(char *dictType) - { return type == objStream && streamIs(dictType); } - -inline void Object::streamReset() - { stream->reset(); } - -inline void Object::streamClose() - { stream->close(); } - -inline int Object::streamGetChar() - { return stream->getChar(); } - -inline int Object::streamLookChar() - { return stream->lookChar(); } - -inline char *Object::streamGetLine(char *buf, int size) - { return stream->getLine(buf, size); } - -inline Guint Object::streamGetPos() - { return stream->getPos(); } - -inline void Object::streamSetPos(Guint pos, int dir) - { stream->setPos(pos, dir); } - -inline Dict *Object::streamGetDict() - { return stream->getDict(); } - -#endif diff --git a/xpdf/xpdf/Outline.cc b/xpdf/xpdf/Outline.cc deleted file mode 100644 index cc607e2eb..000000000 --- a/xpdf/xpdf/Outline.cc +++ /dev/null @@ -1,152 +0,0 @@ -//======================================================================== -// -// Outline.cc -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "gmem.h" -#include "GString.h" -#include "GList.h" -#include "Link.h" -#include "PDFDocEncoding.h" -#include "UGString.h" -#include "Outline.h" - -//------------------------------------------------------------------------ - -Outline::Outline(Object *outlineObj, XRef *xref) { - Object first, last; - - items = NULL; - if (!outlineObj->isDict()) { - return; - } - items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first), - outlineObj->dictLookupNF("Last", &last), - xref); - first.free(); - last.free(); -} - -Outline::~Outline() { - if (items) { - deleteGList(items, OutlineItem); - } -} - -//------------------------------------------------------------------------ - -OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { - Object obj1; - GString *s; - int i; - - xref = xrefA; - title = NULL; - action = NULL; - kids = NULL; - - if (dict->lookup("Title", &obj1)->isString()) { - s = obj1.getString(); - if ((s->getChar(0) & 0xff) == 0xfe && - (s->getChar(1) & 0xff) == 0xff) { - titleLen = (s->getLength() - 2) / 2; - title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); - for (i = 0; i < titleLen; ++i) { - title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) | - (s->getChar(3 + 2*i) & 0xff); - } - } else { - titleLen = s->getLength(); - title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); - for (i = 0; i < titleLen; ++i) { - title[i] = pdfDocEncoding[s->getChar(i) & 0xff]; - } - } - } else { - titleLen = 0; - } - obj1.free(); - - if (!dict->lookup("Dest", &obj1)->isNull()) { - action = LinkAction::parseDest(&obj1); - } else { - obj1.free(); - if (!dict->lookup("A", &obj1)->isNull()) { - action = LinkAction::parseAction(&obj1); - } - } - obj1.free(); - - dict->lookupNF("First", &firstRef); - dict->lookupNF("Last", &lastRef); - dict->lookupNF("Next", &nextRef); - - startsOpen = gFalse; - if (dict->lookup("Count", &obj1)->isInt()) { - if (obj1.getInt() > 0) { - startsOpen = gTrue; - } - } - obj1.free(); -} - -OutlineItem::~OutlineItem() { - close(); - if (title) { - gfree(title); - } - if (action) { - delete action; - } - firstRef.free(); - lastRef.free(); - nextRef.free(); -} - -GList *OutlineItem::readItemList(Object *firstItemRef, Object *lastItemRef, - XRef *xrefA) { - GList *items; - OutlineItem *item; - Object obj; - Object *p; - - items = new GList(); - p = firstItemRef; - while (p->isRef()) { - if (!p->fetch(xrefA, &obj)->isDict()) { - obj.free(); - break; - } - item = new OutlineItem(obj.getDict(), xrefA); - obj.free(); - items->append(item); - if (p->getRef().num == lastItemRef->getRef().num && - p->getRef().gen == lastItemRef->getRef().gen) { - break; - } - p = &item->nextRef; - } - return items; -} - -void OutlineItem::open() { - if (!kids) { - kids = readItemList(&firstRef, &lastRef, xref); - } -} - -void OutlineItem::close() { - if (kids) { - deleteGList(kids, OutlineItem); - kids = NULL; - } -} diff --git a/xpdf/xpdf/Outline.h b/xpdf/xpdf/Outline.h deleted file mode 100644 index f38f8d161..000000000 --- a/xpdf/xpdf/Outline.h +++ /dev/null @@ -1,76 +0,0 @@ -//======================================================================== -// -// Outline.h -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef OUTLINE_H -#define OUTLINE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" -#include "CharTypes.h" - -class GString; -class GList; -class XRef; -class LinkAction; - -//------------------------------------------------------------------------ - -class Outline { -public: - - Outline(Object *outlineObj, XRef *xref); - ~Outline(); - - GList *getItems() { return items; } - -private: - - GList *items; // NULL if document has no outline - // [OutlineItem] -}; - -//------------------------------------------------------------------------ - -class OutlineItem { -public: - - OutlineItem(Dict *dict, XRef *xrefA); - ~OutlineItem(); - - static GList *readItemList(Object *firstItemRef, Object *lastItemRef, - XRef *xrefA); - - void open(); - void close(); - - Unicode *getTitle() { return title; } - int getTitleLength() { return titleLen; } - LinkAction *getAction() { return action; } - GBool isOpen() { return startsOpen; } - GBool hasKids() { return firstRef.isRef(); } - GList *getKids() { return kids; } - -private: - - XRef *xref; - Unicode *title; - int titleLen; - LinkAction *action; - Object firstRef; - Object lastRef; - Object nextRef; - GBool startsOpen; - GList *kids; // NULL unless this item is open [OutlineItem] -}; - -#endif diff --git a/xpdf/xpdf/OutputDev.cc b/xpdf/xpdf/OutputDev.cc deleted file mode 100644 index 6fd37d0a2..000000000 --- a/xpdf/xpdf/OutputDev.cc +++ /dev/null @@ -1,129 +0,0 @@ -//======================================================================== -// -// OutputDev.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "Object.h" -#include "Stream.h" -#include "GfxState.h" -#include "OutputDev.h" - -//------------------------------------------------------------------------ -// OutputDev -//------------------------------------------------------------------------ - -void OutputDev::setDefaultCTM(double *ctm) { - int i; - double det; - - for (i = 0; i < 6; ++i) { - defCTM[i] = ctm[i]; - } - det = 1 / (defCTM[0] * defCTM[3] - defCTM[1] * defCTM[2]); - defICTM[0] = defCTM[3] * det; - defICTM[1] = -defCTM[1] * det; - defICTM[2] = -defCTM[2] * det; - defICTM[3] = defCTM[0] * det; - defICTM[4] = (defCTM[2] * defCTM[5] - defCTM[3] * defCTM[4]) * det; - defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det; -} - -void OutputDev::cvtDevToUser(double dx, double dy, double *ux, double *uy) { - *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4]; - *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5]; -} - -void OutputDev::cvtUserToDev(double ux, double uy, int *dx, int *dy) { - *dx = (int)(defCTM[0] * ux + defCTM[2] * uy + defCTM[4] + 0.5); - *dy = (int)(defCTM[1] * ux + defCTM[3] * uy + defCTM[5] + 0.5); -} - -void OutputDev::updateAll(GfxState *state) { - updateLineDash(state); - updateFlatness(state); - updateLineJoin(state); - updateLineCap(state); - updateMiterLimit(state); - updateLineWidth(state); - updateFillColorSpace(state); - updateFillColor(state); - updateStrokeColorSpace(state); - updateStrokeColor(state); - updateBlendMode(state); - updateFillOpacity(state); - updateStrokeOpacity(state); - updateFillOverprint(state); - updateStrokeOverprint(state); - updateFont(state); -} - -GBool OutputDev::beginType3Char(GfxState */*state*/, double /*x*/, double /*y*/, - double /*dx*/, double /*dy*/, - CharCode /*code*/, Unicode */*u*/, int /*uLen*/) { - return gFalse; -} - -void OutputDev::drawImageMask(GfxState */*state*/, Object */*ref*/, Stream *str, - int width, int height, GBool /*invert*/, - GBool inlineImg) { - int i, j; - - if (inlineImg) { - str->reset(); - j = height * ((width + 7) / 8); - for (i = 0; i < j; ++i) - str->getChar(); - str->close(); - } -} - -void OutputDev::drawImage(GfxState */*state*/, Object */*ref*/, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - int */*maskColors*/, GBool inlineImg) { - int i, j; - - if (inlineImg) { - str->reset(); - j = height * ((width * colorMap->getNumPixelComps() * - colorMap->getBits() + 7) / 8); - for (i = 0; i < j; ++i) - str->getChar(); - str->close(); - } -} - -void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - Stream */*maskStr*/, - int /*maskWidth*/, int /*maskHeight*/, - GBool /*maskInvert*/) { - drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); -} - -void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - Stream */*maskStr*/, - int /*maskWidth*/, int /*maskHeight*/, - GfxImageColorMap */*maskColorMap*/) { - drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); -} - -#if OPI_SUPPORT -void OutputDev::opiBegin(GfxState *state, Dict *opiDict) { -} - -void OutputDev::opiEnd(GfxState *state, Dict *opiDict) { -} -#endif diff --git a/xpdf/xpdf/OutputDev.h b/xpdf/xpdf/OutputDev.h deleted file mode 100644 index 39adf8a59..000000000 --- a/xpdf/xpdf/OutputDev.h +++ /dev/null @@ -1,205 +0,0 @@ -//======================================================================== -// -// OutputDev.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef OUTPUTDEV_H -#define OUTPUTDEV_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "CharTypes.h" - -class GString; -class GfxState; -class GfxColorSpace; -class GfxImageColorMap; -class GfxFunctionShading; -class GfxAxialShading; -class GfxRadialShading; -class Stream; -class Link; -class Catalog; - -//------------------------------------------------------------------------ -// OutputDev -//------------------------------------------------------------------------ - -class OutputDev { -public: - - // Constructor. - OutputDev() {} - - // Destructor. - virtual ~OutputDev() {} - - //----- get info about output device - - // Does this device use upside-down coordinates? - // (Upside-down means (0,0) is the top left corner of the page.) - virtual GBool upsideDown() = 0; - - // Does this device use drawChar() or drawString()? - virtual GBool useDrawChar() = 0; - - // Does this device use tilingPatternFill()? If this returns false, - // tiling pattern fills will be reduced to a series of other drawing - // operations. - virtual GBool useTilingPatternFill() { return gFalse; } - - // Does this device use functionShadedFill(), axialShadedFill(), and - // radialShadedFill()? If this returns false, these shaded fills - // will be reduced to a series of other drawing operations. - virtual GBool useShadedFills() { return gFalse; } - - // Does this device use beginType3Char/endType3Char? Otherwise, - // text in Type 3 fonts will be drawn with drawChar/drawString. - virtual GBool interpretType3Chars() = 0; - - // Does this device need non-text content? - virtual GBool needNonText() { return gTrue; } - - //----- initialization and control - - // Set default transform matrix. - virtual void setDefaultCTM(double *ctm); - - // Start a page. - virtual void startPage(int /*pageNum*/, GfxState */*state*/) {} - - // End a page. - virtual void endPage() {} - - // Dump page contents to display. - virtual void dump() {} - - //----- coordinate conversion - - // Convert between device and user coordinates. - virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy); - virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy); - - double *getDefCTM() { return defCTM; } - double *getDefICTM() { return defICTM; } - - //----- link borders - virtual void drawLink(Link */*link*/, Catalog */*catalog*/) {} - - //----- save/restore graphics state - virtual void saveState(GfxState */*state*/) {} - virtual void restoreState(GfxState */*state*/) {} - - //----- update graphics state - virtual void updateAll(GfxState *state); - virtual void updateCTM(GfxState */*state*/, double /*m11*/, double /*m12*/, - double /*m21*/, double /*m22*/, double /*m31*/, double /*m32*/) {} - virtual void updateLineDash(GfxState */*state*/) {} - virtual void updateFlatness(GfxState */*state*/) {} - virtual void updateLineJoin(GfxState */*state*/) {} - virtual void updateLineCap(GfxState */*state*/) {} - virtual void updateMiterLimit(GfxState */*state*/) {} - virtual void updateLineWidth(GfxState */*state*/) {} - virtual void updateFillColorSpace(GfxState */*state*/) {} - virtual void updateStrokeColorSpace(GfxState */*state*/) {} - virtual void updateFillColor(GfxState */*state*/) {} - virtual void updateStrokeColor(GfxState */*state*/) {} - virtual void updateBlendMode(GfxState */*state*/) {} - virtual void updateFillOpacity(GfxState */*state*/) {} - virtual void updateStrokeOpacity(GfxState */*state*/) {} - virtual void updateFillOverprint(GfxState */*state*/) {} - virtual void updateStrokeOverprint(GfxState */*state*/) {} - - //----- update text state - virtual void updateFont(GfxState */*state*/) {} - virtual void updateTextMat(GfxState */*state*/) {} - virtual void updateCharSpace(GfxState */*state*/) {} - virtual void updateRender(GfxState */*state*/) {} - virtual void updateRise(GfxState */*state*/) {} - virtual void updateWordSpace(GfxState */*state*/) {} - virtual void updateHorizScaling(GfxState */*state*/) {} - virtual void updateTextPos(GfxState */*state*/) {} - virtual void updateTextShift(GfxState */*state*/, double /*shift*/) {} - - //----- path painting - virtual void stroke(GfxState */*state*/) {} - virtual void fill(GfxState */*state*/) {} - virtual void eoFill(GfxState */*state*/) {} - virtual void tilingPatternFill(GfxState */*state*/, Object */*str*/, - int /*paintType*/, Dict */*resDict*/, - double */*mat*/, double */*bbox*/, - int /*x0*/, int /*y0*/, int /*x1*/, int /*y1*/, - double /*xStep*/, double /*yStep*/) {} - virtual void functionShadedFill(GfxState */*state*/, - GfxFunctionShading */*shading*/) {} - virtual void axialShadedFill(GfxState */*state*/, GfxAxialShading */*shading*/) {} - virtual void radialShadedFill(GfxState */*state*/, GfxRadialShading */*shading*/) {} - - //----- path clipping - virtual void clip(GfxState */*state*/) {} - virtual void eoClip(GfxState */*state*/) {} - - //----- text drawing - virtual void beginStringOp(GfxState */*state*/) {} - virtual void endStringOp(GfxState */*state*/) {} - virtual void beginString(GfxState */*state*/, GString */*s*/) {} - virtual void endString(GfxState */*state*/) {} - virtual void drawChar(GfxState */*state*/, double /*x*/, double /*y*/, - double /*dx*/, double /*dy*/, - double /*originX*/, double /*originY*/, - CharCode /*code*/, int /*nBytes*/, Unicode */*u*/, int /*uLen*/) {} - virtual void drawString(GfxState */*state*/, GString */*s*/) {} - virtual GBool beginType3Char(GfxState *state, double x, double y, - double dx, double dy, - CharCode code, Unicode *u, int uLen); - virtual void endType3Char(GfxState */*state*/) {} - virtual void endTextObject(GfxState */*state*/) {} - - //----- image drawing - virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg); - virtual void drawImage(GfxState *state, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - int *maskColors, GBool inlineImg); - virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - Stream *maskStr, int maskWidth, int maskHeight, - GBool maskInvert); - virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - Stream *maskStr, - int maskWidth, int maskHeight, - GfxImageColorMap *maskColorMap); - -#if OPI_SUPPORT - //----- OPI functions - virtual void opiBegin(GfxState *state, Dict *opiDict); - virtual void opiEnd(GfxState *state, Dict *opiDict); -#endif - - //----- Type 3 font operators - virtual void type3D0(GfxState */*state*/, double /*wx*/, double /*wy*/) {} - virtual void type3D1(GfxState */*state*/, double /*wx*/, double /*wy*/, - double /*llx*/, double /*lly*/, double /*urx*/, double /*ury*/) {} - - //----- PostScript XObjects - virtual void psXObject(Stream */*psStream*/, Stream */*level1Stream*/) {} - -private: - - double defCTM[6]; // default coordinate transform matrix - double defICTM[6]; // inverse of default CTM -}; - -#endif diff --git a/xpdf/xpdf/PDFDoc.cc b/xpdf/xpdf/PDFDoc.cc deleted file mode 100644 index 0046d37cf..000000000 --- a/xpdf/xpdf/PDFDoc.cc +++ /dev/null @@ -1,473 +0,0 @@ -//======================================================================== -// -// PDFDoc.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include "GString.h" -#include "xpdf_config.h" -#include "GlobalParams.h" -#include "Page.h" -#include "Catalog.h" -#include "Stream.h" -#include "XRef.h" -#include "Link.h" -#include "OutputDev.h" -#include "Error.h" -#include "ErrorCodes.h" -#include "Lexer.h" -#include "Parser.h" -#include "SecurityHandler.h" -#ifndef DISABLE_OUTLINE -#include "Outline.h" -#endif -#include "UGString.h" -#include "PDFDoc.h" - -//------------------------------------------------------------------------ - -#define headerSearchSize 1024 // read this many bytes at beginning of - // file to look for '%PDF' - -//------------------------------------------------------------------------ -// PDFDoc -//------------------------------------------------------------------------ - -PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, - GString *userPassword, void *guiDataA) { - Object obj; - GString *fileName1, *fileName2; - - ok = gFalse; - errCode = errNone; - - guiData = guiDataA; - - file = NULL; - str = NULL; - xref = NULL; - catalog = NULL; - links = NULL; -#ifndef DISABLE_OUTLINE - outline = NULL; -#endif - - fileName = fileNameA; - fileName1 = fileName; - - - // try to open file - fileName2 = NULL; -#ifdef VMS - if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) { - error(-1, "Couldn't open file '%s'", fileName1->getCString()); - errCode = errOpenFile; - return; - } -#else - if (!(file = fopen(fileName1->getCString(), "rb"))) { - fileName2 = fileName->copy(); - fileName2->lowerCase(); - if (!(file = fopen(fileName2->getCString(), "rb"))) { - fileName2->upperCase(); - if (!(file = fopen(fileName2->getCString(), "rb"))) { - error(-1, "Couldn't open file '%s'", fileName->getCString()); - delete fileName2; - errCode = errOpenFile; - return; - } - } - delete fileName2; - } -#endif - - // create stream - obj.initNull(); - str = new FileStream(file, 0, gFalse, 0, &obj); - - ok = setup(ownerPassword, userPassword); -} - -#ifdef WIN32 -PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword, - GString *userPassword, void *guiDataA) { - OSVERSIONINFO version; - wchar_t fileName2[_MAX_PATH + 1]; - Object obj; - int i; - - ok = gFalse; - errCode = errNone; - - guiData = guiDataA; - - file = NULL; - str = NULL; - xref = NULL; - catalog = NULL; - links = NULL; -#ifndef DISABLE_OUTLINE - outline = NULL; -#endif - - //~ file name should be stored in Unicode (?) - fileName = new GString(); - for (i = 0; i < fileNameLen; ++i) { - fileName->append((char)fileNameA[i]); - } - - // zero-terminate the file name string - for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) { - fileName2[i] = fileNameA[i]; - } - fileName2[i] = 0; - - // try to open file - // NB: _wfopen is only available in NT - version.dwOSVersionInfoSize = sizeof(version); - GetVersionEx(&version); - if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { - file = _wfopen(fileName2, L"rb"); - } else { - file = fopen(fileName->getCString(), "rb"); - } - if (!file) { - error(-1, "Couldn't open file '%s'", fileName->getCString()); - errCode = errOpenFile; - return; - } - - // create stream - obj.initNull(); - str = new FileStream(file, 0, gFalse, 0, &obj); - - ok = setup(ownerPassword, userPassword); -} -#endif - -PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, - GString *userPassword, void *guiDataA) { - ok = gFalse; - errCode = errNone; - guiData = guiDataA; - fileName = NULL; - file = NULL; - str = strA; - xref = NULL; - catalog = NULL; - links = NULL; -#ifndef DISABLE_OUTLINE - outline = NULL; -#endif - ok = setup(ownerPassword, userPassword); -} - -GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { - str->reset(); - - char *eof = new char[1025]; - int pos = str->getPos(); - str->setPos(1024, -1); - int i, ch; - for (i = 0; i < 1024; i++) - { - ch = str->getChar(); - if (ch == EOF) - break; - eof[i] = ch; - } - eof[i] = '\0'; - - bool found = false; - for (i = i - 5; i >= 0; i--) { - if (strncmp (&eof[i], "%%EOF", 5) == 0) { - found = true; - break; - } - } - if (!found) - { - error(-1, "Document does not have ending %%EOF"); - errCode = errDamaged; - delete[] eof; - return gFalse; - } - delete[] eof; - - str->setPos(pos); - - // check header - checkHeader(); - - // read xref table - xref = new XRef(str); - if (!xref->isOk()) { - error(-1, "Couldn't read xref table"); - errCode = xref->getErrorCode(); - return gFalse; - } - - // check for encryption - if (!checkEncryption(ownerPassword, userPassword)) { - errCode = errEncrypted; - return gFalse; - } - - // read catalog - catalog = new Catalog(xref); - if (!catalog->isOk()) { - error(-1, "Couldn't read page catalog"); - errCode = errBadCatalog; - return gFalse; - } - -#ifndef DISABLE_OUTLINE - // read outline - outline = new Outline(catalog->getOutline(), xref); -#endif - - // done - return gTrue; -} - -PDFDoc::~PDFDoc() { -#ifndef DISABLE_OUTLINE - if (outline) { - delete outline; - } -#endif - if (catalog) { - delete catalog; - } - if (xref) { - delete xref; - } - if (str) { - delete str; - } - if (file) { - fclose(file); - } - if (fileName) { - delete fileName; - } - if (links) { - delete links; - } -} - -// Check for a PDF header on this stream. Skip past some garbage -// if necessary. -void PDFDoc::checkHeader() { - char hdrBuf[headerSearchSize+1]; - char *p; - int i; - - pdfVersion = 0; - for (i = 0; i < headerSearchSize; ++i) { - hdrBuf[i] = str->getChar(); - } - hdrBuf[headerSearchSize] = '\0'; - for (i = 0; i < headerSearchSize - 5; ++i) { - if (!strncmp(&hdrBuf[i], "%PDF-", 5)) { - break; - } - } - if (i >= headerSearchSize - 5) { - error(-1, "May not be a PDF file (continuing anyway)"); - return; - } - str->moveStart(i); - if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) { - error(-1, "May not be a PDF file (continuing anyway)"); - return; - } - pdfVersion = atof(p); - if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') || - pdfVersion > supportedPDFVersionNum + 0.0001) { - error(-1, "PDF version %s -- xpdf supports version %s" - " (continuing anyway)", p, supportedPDFVersionStr); - } -} - -GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) { - Object encrypt; - GBool encrypted; - SecurityHandler *secHdlr; - GBool ret; - - xref->getTrailerDict()->dictLookup("Encrypt", &encrypt); - if ((encrypted = encrypt.isDict())) { - if ((secHdlr = SecurityHandler::make(this, &encrypt))) { - if (secHdlr->checkEncryption(ownerPassword, userPassword)) { - // authorization succeeded - xref->setEncryption(secHdlr->getPermissionFlags(), - secHdlr->getOwnerPasswordOk(), - secHdlr->getFileKey(), - secHdlr->getFileKeyLength(), - secHdlr->getEncVersion()); - ret = gTrue; - } else { - // authorization failed - ret = gFalse; - } - delete secHdlr; - } else { - // couldn't find the matching security handler - ret = gFalse; - } - } else { - // document is not encrypted - ret = gTrue; - } - encrypt.free(); - return ret; -} - -void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool useMediaBox, GBool crop, - GBool doLinks, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { - Page *p; - - if (globalParams->getPrintCommands()) { - printf("***** page %d *****\n", page); - } - p = catalog->getPage(page); - if (doLinks) { - if (links) { - delete links; - } - getLinks(p); - p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog, - abortCheckCbk, abortCheckCbkData); - } else { - p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog, - abortCheckCbk, abortCheckCbkData); - } -} - -void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, - double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool doLinks, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { - int page; - - for (page = firstPage; page <= lastPage; ++page) { - displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, doLinks, - abortCheckCbk, abortCheckCbkData); - } -} - -void PDFDoc::displayPages(OutputDev *out, list &pages, - double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool doLinks, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) -{ - list::const_iterator i; - - for(i = pages.begin(); i != pages.end(); ++i) - displayPage(out, *i, hDPI, vDPI, rotate, useMediaBox, crop, doLinks, - abortCheckCbk, abortCheckCbkData); -} - -void PDFDoc::displayPageSlice(OutputDev *out, int page, - double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool doLinks, - int sliceX, int sliceY, int sliceW, int sliceH, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { - Page *p; - - p = catalog->getPage(page); - if (doLinks) { - if (links) { - delete links; - } - getLinks(p); - p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, - sliceX, sliceY, sliceW, sliceH, - links, catalog, abortCheckCbk, abortCheckCbkData); - } else { - p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, - sliceX, sliceY, sliceW, sliceH, - NULL, catalog, abortCheckCbk, abortCheckCbkData); - } -} - -Links *PDFDoc::takeLinks() { - Links *ret; - - ret = links; - links = NULL; - return ret; -} - -GBool PDFDoc::isLinearized() { - Parser *parser; - Object obj1, obj2, obj3, obj4, obj5; - GBool lin; - - lin = gFalse; - obj1.initNull(); - parser = new Parser(xref, - new Lexer(xref, - str->makeSubStream(str->getStart(), gFalse, 0, &obj1))); - parser->getObj(&obj1); - parser->getObj(&obj2); - parser->getObj(&obj3); - parser->getObj(&obj4); - if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && - obj4.isDict()) { - obj4.dictLookup("Linearized", &obj5); - if (obj5.isNum() && obj5.getNum() > 0) { - lin = gTrue; - } - obj5.free(); - } - obj4.free(); - obj3.free(); - obj2.free(); - obj1.free(); - delete parser; - return lin; -} - -GBool PDFDoc::saveAs(GString *name) { - FILE *f; - int c; - - if (!(f = fopen(name->getCString(), "wb"))) { - error(-1, "Couldn't open file '%s'", name->getCString()); - return gFalse; - } - str->reset(); - while ((c = str->getChar()) != EOF) { - fputc(c, f); - } - str->close(); - fclose(f); - return gTrue; -} - -void PDFDoc::getLinks(Page *page) { - Object obj; - - links = new Links(page->getAnnots(&obj), catalog->getBaseURI()); - obj.free(); -} diff --git a/xpdf/xpdf/PDFDoc.h b/xpdf/xpdf/PDFDoc.h deleted file mode 100644 index 4542e9158..000000000 --- a/xpdf/xpdf/PDFDoc.h +++ /dev/null @@ -1,195 +0,0 @@ -//======================================================================== -// -// PDFDoc.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef PDFDOC_H -#define PDFDOC_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include -#include "XRef.h" -#include "Link.h" -#include "Catalog.h" -#include "Page.h" - -class GString; -class BaseStream; -class OutputDev; -class Links; -class LinkAction; -class LinkDest; -class Outline; - -using namespace std; - -//------------------------------------------------------------------------ -// PDFDoc -//------------------------------------------------------------------------ - -class PDFDoc { -public: - - PDFDoc(GString *fileNameA, GString *ownerPassword = NULL, - GString *userPassword = NULL, void *guiDataA = NULL); -#ifdef WIN32 - PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword = NULL, - GString *userPassword = NULL, void *guiDataA = NULL); -#endif - PDFDoc(BaseStream *strA, GString *ownerPassword = NULL, - GString *userPassword = NULL, void *guiDataA = NULL); - ~PDFDoc(); - - // Was PDF document successfully opened? - GBool isOk() { return ok; } - - // Get the error code (if isOk() returns false). - int getErrorCode() { return errCode; } - - // Get file name. - GString *getFileName() { return fileName; } - - // Get the xref table. - XRef *getXRef() { return xref; } - - // Get catalog. - Catalog *getCatalog() { return catalog; } - - // Get base stream. - BaseStream *getBaseStream() { return str; } - - // Get page parameters. - double getPageMediaWidth(int page) - { return catalog->getPage(page)->getMediaWidth(); } - double getPageMediaHeight(int page) - { return catalog->getPage(page)->getMediaHeight(); } - double getPageCropWidth(int page) - { return catalog->getPage(page)->getCropWidth(); } - double getPageCropHeight(int page) - { return catalog->getPage(page)->getCropHeight(); } - int getPageRotate(int page) - { return catalog->getPage(page)->getRotate(); } - - // Get number of pages. - int getNumPages() { return catalog->getNumPages(); } - - // Return the contents of the metadata stream, or NULL if there is - // no metadata. - GString *readMetadata() { return catalog->readMetadata(); } - - // Return the structure tree root object. - Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); } - - // Display a page. - void displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool useMediaBox, GBool crop, - GBool doLinks, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - - // Display a range of pages. - void displayPages(OutputDev *out, int firstPage, int lastPage, - double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool doLinks, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - - // Added by kpdf authors - // Display some pages - void displayPages(OutputDev *out, list &pages, - double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool doLinks, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - - - // Display part of a page. - void displayPageSlice(OutputDev *out, int page, - double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool doLinks, - int sliceX, int sliceY, int sliceW, int sliceH, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - - // Find a page, given its object ID. Returns page number, or 0 if - // not found. - int findPage(int num, int gen) { return catalog->findPage(num, gen); } - - // Returns the links for the current page, transferring ownership to - // the caller. - Links *takeLinks(); - - // Find a named destination. Returns the link destination, or - // NULL if is not a destination. - LinkDest *findDest(UGString *name) - { return catalog->findDest(name); } - -#ifndef DISABLE_OUTLINE - // Return the outline object. - Outline *getOutline() { return outline; } -#endif - - // Is the file encrypted? - GBool isEncrypted() { return xref->isEncrypted(); } - - // Check various permissions. - GBool okToPrint(GBool ignoreOwnerPW = gFalse) - { return xref->okToPrint(ignoreOwnerPW); } - GBool okToChange(GBool ignoreOwnerPW = gFalse) - { return xref->okToChange(ignoreOwnerPW); } - GBool okToCopy(GBool ignoreOwnerPW = gFalse) - { return xref->okToCopy(ignoreOwnerPW); } - GBool okToAddNotes(GBool ignoreOwnerPW = gFalse) - { return xref->okToAddNotes(ignoreOwnerPW); } - - // Is this document linearized? - GBool isLinearized(); - - // Return the document's Info dictionary (if any). - Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); } - Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); } - - // Return the PDF version specified by the file. - double getPDFVersion() { return pdfVersion; } - - // Save this file with another name. - GBool saveAs(GString *name); - - // Return a pointer to the GUI (XPDFCore or WinPDFCore object). - void *getGUIData() { return guiData; } - - -private: - - GBool setup(GString *ownerPassword, GString *userPassword); - void checkHeader(); - GBool checkEncryption(GString *ownerPassword, GString *userPassword); - void getLinks(Page *page); - - GString *fileName; - FILE *file; - BaseStream *str; - void *guiData; - double pdfVersion; - XRef *xref; - Catalog *catalog; - Links *links; -#ifndef DISABLE_OUTLINE - Outline *outline; -#endif - - - GBool ok; - int errCode; -}; - -#endif diff --git a/xpdf/xpdf/PDFDocEncoding.cc b/xpdf/xpdf/PDFDocEncoding.cc deleted file mode 100644 index 89dc38283..000000000 --- a/xpdf/xpdf/PDFDocEncoding.cc +++ /dev/null @@ -1,44 +0,0 @@ -//======================================================================== -// -// PDFDocEncoding.h -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include "PDFDocEncoding.h" - -Unicode pdfDocEncoding[256] = { - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 00 - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 10 - 0x02d8, 0x02c7, 0x02c6, 0x02d9, 0x02dd, 0x02db, 0x02da, 0x02dc, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20 - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30 - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40 - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50 - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60 - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70 - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000, - 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, // 80 - 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, - 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x0141, 0x0152, 0x0160, // 90 - 0x0178, 0x017d, 0x0131, 0x0142, 0x0153, 0x0161, 0x017e, 0x0000, - 0x20ac, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, // a0 - 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x0000, 0x00ae, 0x00af, - 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, // b0 - 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, - 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, // c0 - 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, - 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, // d0 - 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, - 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, // e0 - 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, - 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, // f0 - 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff -}; diff --git a/xpdf/xpdf/PDFDocEncoding.h b/xpdf/xpdf/PDFDocEncoding.h deleted file mode 100644 index 3259d3e10..000000000 --- a/xpdf/xpdf/PDFDocEncoding.h +++ /dev/null @@ -1,16 +0,0 @@ -//======================================================================== -// -// PDFDocEncoding.h -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef PDFDOCENCODING_H -#define PDFDOCENCODING_H - -#include "CharTypes.h" - -extern Unicode pdfDocEncoding[256]; - -#endif diff --git a/xpdf/xpdf/PSOutputDev.cc b/xpdf/xpdf/PSOutputDev.cc deleted file mode 100644 index 50186c3f8..000000000 --- a/xpdf/xpdf/PSOutputDev.cc +++ /dev/null @@ -1,4953 +0,0 @@ -//======================================================================== -// -// PSOutputDev.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include -#include "GString.h" -#include "GList.h" -#include "config.h" -#include "GlobalParams.h" -#include "Object.h" -#include "Error.h" -#include "Function.h" -#include "Gfx.h" -#include "GfxState.h" -#include "GfxFont.h" -#include "UnicodeMap.h" -#include "FoFiType1C.h" -#include "FoFiTrueType.h" -#include "Catalog.h" -#include "Page.h" -#include "Stream.h" -#include "Annot.h" -#include "UGString.h" -#include "PSOutputDev.h" - -#ifdef MACOS -// needed for setting type/creator of MacOS files -#include "ICSupport.h" -#endif - -//------------------------------------------------------------------------ -// PostScript prolog and setup -//------------------------------------------------------------------------ - -// The '~' escapes mark prolog code that is emitted only in certain -// levels: -// -// ~[123][sn] -// ^ ^----- s=psLevel*Sep, n=psLevel* -// +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3* - -static const char *prolog[] = { - "/xpdf 75 dict def xpdf begin", - "% PDF special state", - "/pdfDictSize 15 def", - "~1sn", - "/pdfStates 64 array def", - " 0 1 63 {", - " pdfStates exch pdfDictSize dict", - " dup /pdfStateIdx 3 index put", - " put", - " } for", - "~123sn", - "/pdfSetup {", - " 3 1 roll 2 array astore", - " /setpagedevice where {", - " pop 3 dict begin", - " /PageSize exch def", - " /ImagingBBox null def", - " /Policies 1 dict dup begin /PageSize 3 def end def", - " { /Duplex true def } if", - " currentdict end setpagedevice", - " } {", - " pop pop", - " } ifelse", - "} def", - "~1sn", - "/pdfOpNames [", - " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke", - " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender", - " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath", - "] def", - "~123sn", - "/pdfStartPage {", - "~1sn", - " pdfStates 0 get begin", - "~23sn", - " pdfDictSize dict begin", - "~23n", - " /pdfFillCS [] def", - " /pdfFillXform {} def", - " /pdfStrokeCS [] def", - " /pdfStrokeXform {} def", - "~1n", - " /pdfFill 0 def", - " /pdfStroke 0 def", - "~1s", - " /pdfFill [0 0 0 1] def", - " /pdfStroke [0 0 0 1] def", - "~23sn", - " /pdfFill [0] def", - " /pdfStroke [0] def", - " /pdfFillOP false def", - " /pdfStrokeOP false def", - "~123sn", - " /pdfLastFill false def", - " /pdfLastStroke false def", - " /pdfTextMat [1 0 0 1 0 0] def", - " /pdfFontSize 0 def", - " /pdfCharSpacing 0 def", - " /pdfTextRender 0 def", - " /pdfTextRise 0 def", - " /pdfWordSpacing 0 def", - " /pdfHorizScaling 1 def", - " /pdfTextClipPath [] def", - "} def", - "/pdfEndPage { end } def", - "~23s", - "% separation convention operators", - "/findcmykcustomcolor where {", - " pop", - "}{", - " /findcmykcustomcolor { 5 array astore } def", - "} ifelse", - "/setcustomcolor where {", - " pop", - "}{", - " /setcustomcolor {", - " exch", - " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch", - " 0 4 getinterval cvx", - " [ exch /dup load exch { mul exch dup } /forall load", - " /pop load dup ] cvx", - " ] setcolorspace setcolor", - " } def", - "} ifelse", - "/customcolorimage where {", - " pop", - "}{", - " /customcolorimage {", - " gsave", - " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch", - " 0 4 getinterval", - " [ exch /dup load exch { mul exch dup } /forall load", - " /pop load dup ] cvx", - " ] setcolorspace", - " 10 dict begin", - " /ImageType 1 def", - " /DataSource exch def", - " /ImageMatrix exch def", - " /BitsPerComponent exch def", - " /Height exch def", - " /Width exch def", - " /Decode [1 0] def", - " currentdict end", - " image", - " grestore", - " } def", - "} ifelse", - "~123sn", - "% PDF color state", - "~1n", - "/g { dup /pdfFill exch def setgray", - " /pdfLastFill true def /pdfLastStroke false def } def", - "/G { dup /pdfStroke exch def setgray", - " /pdfLastStroke true def /pdfLastFill false def } def", - "/fCol {", - " pdfLastFill not {", - " pdfFill setgray", - " /pdfLastFill true def /pdfLastStroke false def", - " } if", - "} def", - "/sCol {", - " pdfLastStroke not {", - " pdfStroke setgray", - " /pdfLastStroke true def /pdfLastFill false def", - " } if", - "} def", - "~1s", - "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor", - " /pdfLastFill true def /pdfLastStroke false def } def", - "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor", - " /pdfLastStroke true def /pdfLastFill false def } def", - "/fCol {", - " pdfLastFill not {", - " pdfFill aload pop setcmykcolor", - " /pdfLastFill true def /pdfLastStroke false def", - " } if", - "} def", - "/sCol {", - " pdfLastStroke not {", - " pdfStroke aload pop setcmykcolor", - " /pdfLastStroke true def /pdfLastFill false def", - " } if", - "} def", - "~23n", - "/cs { /pdfFillXform exch def dup /pdfFillCS exch def", - " setcolorspace } def", - "/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def", - " setcolorspace } def", - "/sc { pdfLastFill not { pdfFillCS setcolorspace } if", - " dup /pdfFill exch def aload pop pdfFillXform setcolor", - " /pdfLastFill true def /pdfLastStroke false def } def", - "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if", - " dup /pdfStroke exch def aload pop pdfStrokeXform setcolor", - " /pdfLastStroke true def /pdfLastFill false def } def", - "/op { /pdfFillOP exch def", - " pdfLastFill { pdfFillOP setoverprint } if } def", - "/OP { /pdfStrokeOP exch def", - " pdfLastStroke { pdfStrokeOP setoverprint } if } def", - "/fCol {", - " pdfLastFill not {", - " pdfFillCS setcolorspace", - " pdfFill aload pop pdfFillXform setcolor", - " pdfFillOP setoverprint", - " /pdfLastFill true def /pdfLastStroke false def", - " } if", - "} def", - "/sCol {", - " pdfLastStroke not {", - " pdfStrokeCS setcolorspace", - " pdfStroke aload pop pdfStrokeXform setcolor", - " pdfStrokeOP setoverprint", - " /pdfLastStroke true def /pdfLastFill false def", - " } if", - "} def", - "~23s", - "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor", - " /pdfLastFill true def /pdfLastStroke false def } def", - "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor", - " /pdfLastStroke true def /pdfLastFill false def } def", - "/ck { 6 copy 6 array astore /pdfFill exch def", - " findcmykcustomcolor exch setcustomcolor", - " /pdfLastFill true def /pdfLastStroke false def } def", - "/CK { 6 copy 6 array astore /pdfStroke exch def", - " findcmykcustomcolor exch setcustomcolor", - " /pdfLastStroke true def /pdfLastFill false def } def", - "/op { /pdfFillOP exch def", - " pdfLastFill { pdfFillOP setoverprint } if } def", - "/OP { /pdfStrokeOP exch def", - " pdfLastStroke { pdfStrokeOP setoverprint } if } def", - "/fCol {", - " pdfLastFill not {", - " pdfFill aload length 4 eq {", - " setcmykcolor", - " }{", - " findcmykcustomcolor exch setcustomcolor", - " } ifelse", - " pdfFillOP setoverprint", - " /pdfLastFill true def /pdfLastStroke false def", - " } if", - "} def", - "/sCol {", - " pdfLastStroke not {", - " pdfStroke aload length 4 eq {", - " setcmykcolor", - " }{", - " findcmykcustomcolor exch setcustomcolor", - " } ifelse", - " pdfStrokeOP setoverprint", - " /pdfLastStroke true def /pdfLastFill false def", - " } if", - "} def", - "~123sn", - "% build a font", - "/pdfMakeFont {", - " 4 3 roll findfont", - " 4 2 roll matrix scale makefont", - " dup length dict begin", - " { 1 index /FID ne { def } { pop pop } ifelse } forall", - " /Encoding exch def", - " currentdict", - " end", - " definefont pop", - "} def", - "/pdfMakeFont16 {", - " exch findfont", - " dup length dict begin", - " { 1 index /FID ne { def } { pop pop } ifelse } forall", - " /WMode exch def", - " currentdict", - " end", - " definefont pop", - "} def", - "~3sn", - "/pdfMakeFont16L3 {", - " 1 index /CIDFont resourcestatus {", - " pop pop 1 index /CIDFont findresource /CIDFontType known", - " } {", - " false", - " } ifelse", - " {", - " 0 eq { /Identity-H } { /Identity-V } ifelse", - " exch 1 array astore composefont pop", - " } {", - " pdfMakeFont16", - " } ifelse", - "} def", - "~123sn", - "% graphics state operators", - "~1sn", - "/q {", - " gsave", - " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for", - " pdfStates pdfStateIdx 1 add get begin", - " pdfOpNames { exch def } forall", - "} def", - "/Q { end grestore } def", - "~23sn", - "/q { gsave pdfDictSize dict begin } def", - "/Q {", - " end grestore", - " /pdfLastFill where {", - " pop", - " pdfLastFill {", - " pdfFillOP setoverprint", - " } {", - " pdfStrokeOP setoverprint", - " } ifelse", - " } if", - "} def", - "~123sn", - "/cm { concat } def", - "/d { setdash } def", - "/i { setflat } def", - "/j { setlinejoin } def", - "/J { setlinecap } def", - "/M { setmiterlimit } def", - "/w { setlinewidth } def", - "% path segment operators", - "/m { moveto } def", - "/l { lineto } def", - "/c { curveto } def", - "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto", - " neg 0 rlineto closepath } def", - "/h { closepath } def", - "% path painting operators", - "/S { sCol stroke } def", - "/Sf { fCol stroke } def", - "/f { fCol fill } def", - "/f* { fCol eofill } def", - "% clipping operators", - "/W { clip newpath } def", - "/W* { eoclip newpath } def", - "% text state operators", - "/Tc { /pdfCharSpacing exch def } def", - "/Tf { dup /pdfFontSize exch def", - " dup pdfHorizScaling mul exch matrix scale", - " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put", - " exch findfont exch makefont setfont } def", - "/Tr { /pdfTextRender exch def } def", - "/Ts { /pdfTextRise exch def } def", - "/Tw { /pdfWordSpacing exch def } def", - "/Tz { /pdfHorizScaling exch def } def", - "% text positioning operators", - "/Td { pdfTextMat transform moveto } def", - "/Tm { /pdfTextMat exch def } def", - "% text string operators", - "/cshow where {", - " pop", - " /cshow2 {", - " dup {", - " pop pop", - " 1 string dup 0 3 index put 3 index exec", - " } exch cshow", - " pop pop", - " } def", - "}{", - " /cshow2 {", - " currentfont /FontType get 0 eq {", - " 0 2 2 index length 1 sub {", - " 2 copy get exch 1 add 2 index exch get", - " 2 copy exch 256 mul add", - " 2 string dup 0 6 5 roll put dup 1 5 4 roll put", - " 3 index exec", - " } for", - " } {", - " dup {", - " 1 string dup 0 3 index put 3 index exec", - " } forall", - " } ifelse", - " pop pop", - " } def", - "} ifelse", - "/awcp {", // awidthcharpath - " exch {", - " false charpath", - " 5 index 5 index rmoveto", - " 6 index eq { 7 index 7 index rmoveto } if", - " } exch cshow2", - " 6 {pop} repeat", - "} def", - "/Tj {", - " fCol", // because stringwidth has to draw Type 3 chars - " 1 index stringwidth pdfTextMat idtransform pop", - " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse", - " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32", - " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0", - " pdfTextMat dtransform", - " 6 5 roll Tj1", - "} def", - "/Tj16 {", - " fCol", // because stringwidth has to draw Type 3 chars - " 2 index stringwidth pdfTextMat idtransform pop", - " sub exch div", - " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32", - " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0", - " pdfTextMat dtransform", - " 6 5 roll Tj1", - "} def", - "/Tj16V {", - " fCol", // because stringwidth has to draw Type 3 chars - " 2 index stringwidth pdfTextMat idtransform exch pop", - " sub exch div", - " 0 pdfWordSpacing pdfTextMat dtransform 32", - " 4 3 roll pdfCharSpacing add 0 exch", - " pdfTextMat dtransform", - " 6 5 roll Tj1", - "} def", - "/Tj1 {", - " 0 pdfTextRise pdfTextMat dtransform rmoveto", - " currentpoint 8 2 roll", - " pdfTextRender 1 and 0 eq {", - " 6 copy awidthshow", - " } if", - " pdfTextRender 3 and dup 1 eq exch 2 eq or {", - " 7 index 7 index moveto", - " 6 copy", - " currentfont /FontType get 3 eq { fCol } { sCol } ifelse", - " false awcp currentpoint stroke moveto", - " } if", - " pdfTextRender 4 and 0 ne {", - " 8 6 roll moveto", - " false awcp", - " /pdfTextClipPath [ pdfTextClipPath aload pop", - " {/moveto cvx}", - " {/lineto cvx}", - " {/curveto cvx}", - " {/closepath cvx}", - " pathforall ] def", - " currentpoint newpath moveto", - " } {", - " 8 {pop} repeat", - " } ifelse", - " 0 pdfTextRise neg pdfTextMat dtransform rmoveto", - "} def", - "/TJm { pdfFontSize 0.001 mul mul neg 0", - " pdfTextMat dtransform rmoveto } def", - "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch", - " pdfTextMat dtransform rmoveto } def", - "/Tclip { pdfTextClipPath cvx exec clip newpath", - " /pdfTextClipPath [] def } def", - "~1ns", - "% Level 1 image operators", - "~1n", - "/pdfIm1 {", - " /pdfImBuf1 4 index string def", - " { currentfile pdfImBuf1 readhexstring pop } image", - "} def", - "~1s", - "/pdfIm1Sep {", - " /pdfImBuf1 4 index string def", - " /pdfImBuf2 4 index string def", - " /pdfImBuf3 4 index string def", - " /pdfImBuf4 4 index string def", - " { currentfile pdfImBuf1 readhexstring pop }", - " { currentfile pdfImBuf2 readhexstring pop }", - " { currentfile pdfImBuf3 readhexstring pop }", - " { currentfile pdfImBuf4 readhexstring pop }", - " true 4 colorimage", - "} def", - "~1ns", - "/pdfImM1 {", - " fCol /pdfImBuf1 4 index 7 add 8 idiv string def", - " { currentfile pdfImBuf1 readhexstring pop } imagemask", - "} def", - "/pdfImM1a {", - " { 2 copy get exch 1 add exch } imagemask", - " pop pop", - "} def", - "~23sn", - "% Level 2 image operators", - "/pdfImBuf 100 string def", - "/pdfIm {", - " image", - " { currentfile pdfImBuf readline", - " not { pop exit } if", - " (%-EOD-) eq { exit } if } loop", - "} def", - "~23s", - "/pdfImSep {", - " findcmykcustomcolor exch", - " dup /Width get /pdfImBuf1 exch string def", - " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def", - " /pdfImDecodeLow exch def", - " begin Width Height BitsPerComponent ImageMatrix DataSource end", - " /pdfImData exch def", - " { pdfImData pdfImBuf1 readstring pop", - " 0 1 2 index length 1 sub {", - " 1 index exch 2 copy get", - " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi", - " 255 exch sub put", - " } for }", - " 6 5 roll customcolorimage", - " { currentfile pdfImBuf readline", - " not { pop exit } if", - " (%-EOD-) eq { exit } if } loop", - "} def", - "~23sn", - "/pdfImM {", - " fCol imagemask", - " { currentfile pdfImBuf readline", - " not { pop exit } if", - " (%-EOD-) eq { exit } if } loop", - "} def", - "/pdfImClip {", - " gsave", - " 0 2 4 index length 1 sub {", - " dup 4 index exch 2 copy", - " get 5 index div put", - " 1 add 3 index exch 2 copy", - " get 3 index div put", - " } for", - " pop pop rectclip", - "} def", - "/pdfImClipEnd { grestore } def", - "~23n", - "% shading operators", - "/colordelta {", - " false 0 1 3 index length 1 sub {", - " dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {", - " pop true", - " } if", - " } for", - " exch pop exch pop", - "} def", - "/funcCol { func n array astore } def", - "/funcSH {", - " dup 0 eq {", - " true", - " } {", - " dup 6 eq {", - " false", - " } {", - " 4 index 4 index funcCol dup", - " 6 index 4 index funcCol dup", - " 3 1 roll colordelta 3 1 roll", - " 5 index 5 index funcCol dup", - " 3 1 roll colordelta 3 1 roll", - " 6 index 8 index funcCol dup", - " 3 1 roll colordelta 3 1 roll", - " colordelta or or or", - " } ifelse", - " } ifelse", - " {", - " 1 add", - " 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch", - " 6 index 6 index 4 index 4 index 4 index funcSH", - " 2 index 6 index 6 index 4 index 4 index funcSH", - " 6 index 2 index 4 index 6 index 4 index funcSH", - " 5 3 roll 3 2 roll funcSH pop pop", - " } {", - " pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul", - " funcCol sc", - " dup 4 index exch mat transform m", - " 3 index 3 index mat transform l", - " 1 index 3 index mat transform l", - " mat transform l pop pop h f*", - " } ifelse", - "} def", - "/axialCol {", - " dup 0 lt {", - " pop t0", - " } {", - " dup 1 gt {", - " pop t1", - " } {", - " dt mul t0 add", - " } ifelse", - " } ifelse", - " func n array astore", - "} def", - "/axialSH {", - " dup 0 eq {", - " true", - " } {", - " dup 8 eq {", - " false", - " } {", - " 2 index axialCol 2 index axialCol colordelta", - " } ifelse", - " } ifelse", - " {", - " 1 add 3 1 roll 2 copy add 0.5 mul", - " dup 4 3 roll exch 4 index axialSH", - " exch 3 2 roll axialSH", - " } {", - " pop 2 copy add 0.5 mul axialCol sc", - " exch dup dx mul x0 add exch dy mul y0 add", - " 3 2 roll dup dx mul x0 add exch dy mul y0 add", - " dx abs dy abs ge {", - " 2 copy yMin sub dy mul dx div add yMin m", - " yMax sub dy mul dx div add yMax l", - " 2 copy yMax sub dy mul dx div add yMax l", - " yMin sub dy mul dx div add yMin l", - " h f*", - " } {", - " exch 2 copy xMin sub dx mul dy div add xMin exch m", - " xMax sub dx mul dy div add xMax exch l", - " exch 2 copy xMax sub dx mul dy div add xMax exch l", - " xMin sub dx mul dy div add xMin exch l", - " h f*", - " } ifelse", - " } ifelse", - "} def", - "/radialCol {", - " dup t0 lt {", - " pop t0", - " } {", - " dup t1 gt {", - " pop t1", - " } if", - " } ifelse", - " func n array astore", - "} def", - "/radialSH {", - " dup 0 eq {", - " true", - " } {", - " dup 8 eq {", - " false", - " } {", - " 2 index dt mul t0 add radialCol", - " 2 index dt mul t0 add radialCol colordelta", - " } ifelse", - " } ifelse", - " {", - " 1 add 3 1 roll 2 copy add 0.5 mul", - " dup 4 3 roll exch 4 index radialSH", - " exch 3 2 roll radialSH", - " } {", - " pop 2 copy add 0.5 mul dt mul t0 add axialCol sc", - " exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", - " 0 360 arc h", - " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", - " 0 360 arc h f*", - " } ifelse", - "} def", - "~123sn", - "end", - NULL -}; - -static const char *cmapProlog[] = { - "/CIDInit /ProcSet findresource begin", - "10 dict begin", - " begincmap", - " /CMapType 1 def", - " /CMapName /Identity-H def", - " /CIDSystemInfo 3 dict dup begin", - " /Registry (Adobe) def", - " /Ordering (Identity) def", - " /Supplement 0 def", - " end def", - " 1 begincodespacerange", - " <0000> ", - " endcodespacerange", - " 0 usefont", - " 1 begincidrange", - " <0000> 0", - " endcidrange", - " endcmap", - " currentdict CMapName exch /CMap defineresource pop", - "end", - "10 dict begin", - " begincmap", - " /CMapType 1 def", - " /CMapName /Identity-V def", - " /CIDSystemInfo 3 dict dup begin", - " /Registry (Adobe) def", - " /Ordering (Identity) def", - " /Supplement 0 def", - " end def", - " /WMode 1 def", - " 1 begincodespacerange", - " <0000> ", - " endcodespacerange", - " 0 usefont", - " 1 begincidrange", - " <0000> 0", - " endcidrange", - " endcmap", - " currentdict CMapName exch /CMap defineresource pop", - "end", - "end", - NULL -}; - -//------------------------------------------------------------------------ -// Fonts -//------------------------------------------------------------------------ - -struct PSSubstFont { - const char *psName; // PostScript name - double mWidth; // width of 'm' character -}; - -static const char *psFonts[] = { - "Courier", - "Courier-Bold", - "Courier-Oblique", - "Courier-BoldOblique", - "Helvetica", - "Helvetica-Bold", - "Helvetica-Oblique", - "Helvetica-BoldOblique", - "Symbol", - "Times-Roman", - "Times-Bold", - "Times-Italic", - "Times-BoldItalic", - "ZapfDingbats", - NULL -}; - -static PSSubstFont psSubstFonts[] = { - {"Helvetica", 0.833}, - {"Helvetica-Oblique", 0.833}, - {"Helvetica-Bold", 0.889}, - {"Helvetica-BoldOblique", 0.889}, - {"Times-Roman", 0.788}, - {"Times-Italic", 0.722}, - {"Times-Bold", 0.833}, - {"Times-BoldItalic", 0.778}, - {"Courier", 0.600}, - {"Courier-Oblique", 0.600}, - {"Courier-Bold", 0.600}, - {"Courier-BoldOblique", 0.600} -}; - -// Encoding info for substitute 16-bit font -struct PSFont16Enc { - Ref fontID; - GString *enc; -}; - -//------------------------------------------------------------------------ -// process colors -//------------------------------------------------------------------------ - -#define psProcessCyan 1 -#define psProcessMagenta 2 -#define psProcessYellow 4 -#define psProcessBlack 8 -#define psProcessCMYK 15 - -//------------------------------------------------------------------------ -// PSOutCustomColor -//------------------------------------------------------------------------ - -class PSOutCustomColor { -public: - - PSOutCustomColor(double cA, double mA, - double yA, double kA, GString *nameA); - ~PSOutCustomColor(); - - double c, m, y, k; - GString *name; - PSOutCustomColor *next; -}; - -PSOutCustomColor::PSOutCustomColor(double cA, double mA, - double yA, double kA, GString *nameA) { - c = cA; - m = mA; - y = yA; - k = kA; - name = nameA; - next = NULL; -} - -PSOutCustomColor::~PSOutCustomColor() { - delete name; -} - -//------------------------------------------------------------------------ -// DeviceNRecoder -//------------------------------------------------------------------------ - -class DeviceNRecoder: public FilterStream { -public: - - DeviceNRecoder(Stream *strA, int widthA, int heightA, - GfxImageColorMap *colorMapA); - virtual ~DeviceNRecoder(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual int getChar() - { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; } - virtual int lookChar() - { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; } - virtual GString *getPSFilter(int /*psLevel*/, const char */*indent*/) { return NULL; } - virtual GBool isBinary(GBool /*last = gTrue*/) { return gTrue; } - virtual GBool isEncoder() { return gTrue; } - -private: - - GBool fillBuf(); - - int width, height; - GfxImageColorMap *colorMap; - Function *func; - ImageStream *imgStr; - int buf[gfxColorMaxComps]; - int pixelIdx; - int bufIdx; - int bufSize; -}; - -DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA, - GfxImageColorMap *colorMapA): - FilterStream(strA) { - width = widthA; - height = heightA; - colorMap = colorMapA; - imgStr = NULL; - pixelIdx = 0; - bufIdx = gfxColorMaxComps; - bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> - getAlt()->getNComps(); - func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> - getTintTransformFunc(); -} - -DeviceNRecoder::~DeviceNRecoder() { - if (imgStr) { - delete imgStr; - } -} - -void DeviceNRecoder::reset() { - imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), - colorMap->getBits()); - imgStr->reset(); -} - -GBool DeviceNRecoder::fillBuf() { - Guchar pixBuf[gfxColorMaxComps]; - GfxColor color; - double x[gfxColorMaxComps], y[gfxColorMaxComps]; - int i; - - if (pixelIdx >= width * height) { - return gFalse; - } - imgStr->getPixel(pixBuf); - colorMap->getColor(pixBuf, &color); - for (i = 0; - i < ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->getNComps(); - ++i) { - x[i] = colToDbl(color.c[i]); - } - func->transform(x, y); - for (i = 0; i < bufSize; ++i) { - buf[i] = (int)(y[i] * 255 + 0.5); - } - bufIdx = 0; - ++pixelIdx; - return gTrue; -} - -//------------------------------------------------------------------------ -// PSOutputDev -//------------------------------------------------------------------------ - -extern "C" { -typedef void (*SignalFunc)(int); -} - -static void outputToFile(void *stream, const char *data, int len) { - fwrite(data, 1, len, (FILE *)stream); -} - -PSOutputDev::PSOutputDev(const char *fileName, XRef *xrefA, Catalog *catalog, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, - GBool manualCtrlA) { - FILE *f; - PSFileType fileTypeA; - - underlayCbk = NULL; - underlayCbkData = NULL; - overlayCbk = NULL; - overlayCbkData = NULL; - - fontIDs = NULL; - fontFileIDs = NULL; - fontFileNames = NULL; - font16Enc = NULL; - xobjStack = NULL; - embFontList = NULL; - customColors = NULL; - haveTextClip = gFalse; - t3String = NULL; - - // open file or pipe - if (!strcmp(fileName, "-")) { - fileTypeA = psStdout; - f = stdout; - } else if (fileName[0] == '|') { - fileTypeA = psPipe; -#ifdef HAVE_POPEN -#ifndef WIN32 - signal(SIGPIPE, (SignalFunc)SIG_IGN); -#endif - if (!(f = popen(fileName + 1, "w"))) { - error(-1, "Couldn't run print command '%s'", fileName); - ok = gFalse; - return; - } -#else - error(-1, "Print commands are not supported ('%s')", fileName); - ok = gFalse; - return; -#endif - } else { - fileTypeA = psFile; - if (!(f = fopen(fileName, "w"))) { - error(-1, "Couldn't open PostScript file '%s'", fileName); - ok = gFalse; - return; - } - } - - init(outputToFile, f, fileTypeA, - xrefA, catalog, firstPage, lastPage, modeA, - imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); -} - -PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, - XRef *xrefA, Catalog *catalog, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, - GBool manualCtrlA) { - underlayCbk = NULL; - underlayCbkData = NULL; - overlayCbk = NULL; - overlayCbkData = NULL; - - fontIDs = NULL; - fontFileIDs = NULL; - fontFileNames = NULL; - font16Enc = NULL; - xobjStack = NULL; - embFontList = NULL; - customColors = NULL; - haveTextClip = gFalse; - t3String = NULL; - - init(outputFuncA, outputStreamA, psGeneric, - xrefA, catalog, firstPage, lastPage, modeA, - imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); -} - -void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, - PSFileType fileTypeA, XRef *xrefA, Catalog *catalog, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, - GBool manualCtrlA) { - Page *page; - PDFRectangle *box; - - setlocale(LC_NUMERIC,"POSIX"); - // initialize - ok = gTrue; - outputFunc = outputFuncA; - outputStream = outputStreamA; - fileType = fileTypeA; - xref = xrefA; - level = globalParams->getPSLevel(); - mode = modeA; - paperWidth = globalParams->getPSPaperWidth(); - paperHeight = globalParams->getPSPaperHeight(); - imgLLX = imgLLXA; - imgLLY = imgLLYA; - imgURX = imgURXA; - imgURY = imgURYA; - if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) { - globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY); - } - if (paperWidth < 0 || paperHeight < 0) { - // this check is needed in case the document has zero pages - if (firstPage > 0 && firstPage <= catalog->getNumPages()) { - page = catalog->getPage(firstPage); - paperWidth = (int)ceil(page->getMediaWidth()); - paperHeight = (int)ceil(page->getMediaHeight()); - } else { - paperWidth = 1; - paperHeight = 1; - } - imgLLX = imgLLY = 0; - imgURX = paperWidth; - imgURY = paperHeight; - } - manualCtrl = manualCtrlA; - if (mode == psModeForm) { - lastPage = firstPage; - } - processColors = 0; - inType3Char = gFalse; - -#if OPI_SUPPORT - // initialize OPI nesting levels - opi13Nest = 0; - opi20Nest = 0; -#endif - - tx0 = ty0 = 0; - xScale0 = yScale0 = 0; - rotate0 = -1; - clipLLX0 = clipLLY0 = 0; - clipURX0 = clipURY0 = -1; - - // initialize fontIDs, fontFileIDs, and fontFileNames lists - fontIDSize = 64; - fontIDLen = 0; - fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref)); - fontFileIDSize = 64; - fontFileIDLen = 0; - fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref)); - fontFileNameSize = 64; - fontFileNameLen = 0; - fontFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *)); - psFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *)); - nextTrueTypeNum = 0; - font16EncLen = 0; - font16EncSize = 0; - - xobjStack = new GList(); - numSaves = 0; - numTilingPatterns = 0; - nextFunc = 0; - - // initialize embedded font resource comment list - embFontList = new GString(); - - if (!manualCtrl) { - // this check is needed in case the document has zero pages - if (firstPage > 0 && firstPage <= catalog->getNumPages()) { - writeHeader(firstPage, lastPage, - catalog->getPage(firstPage)->getMediaBox(), - catalog->getPage(firstPage)->getCropBox(), - catalog->getPage(firstPage)->getRotate()); - } else { - box = new PDFRectangle(0, 0, 1, 1); - writeHeader(firstPage, lastPage, box, box, 0); - delete box; - } - if (mode != psModeForm) { - writePS("%%BeginProlog\n"); - } - writeXpdfProcset(); - if (mode != psModeForm) { - writePS("%%EndProlog\n"); - writePS("%%BeginSetup\n"); - } - writeDocSetup(catalog, firstPage, lastPage); - if (mode != psModeForm) { - writePS("%%EndSetup\n"); - } - } - - // initialize sequential page number - seqPage = 1; -} - -PSOutputDev::~PSOutputDev() { - PSOutCustomColor *cc; - int i; - - if (ok) { - if (!manualCtrl) { - writePS("%%Trailer\n"); - writeTrailer(); - if (mode != psModeForm) { - writePS("%%EOF\n"); - } - } - if (fileType == psFile) { -#ifdef MACOS - ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); -#endif - fclose((FILE *)outputStream); - } -#ifdef HAVE_POPEN - else if (fileType == psPipe) { - pclose((FILE *)outputStream); -#ifndef WIN32 - signal(SIGPIPE, (SignalFunc)SIG_DFL); -#endif - } -#endif - } - if (embFontList) { - delete embFontList; - } - if (fontIDs) { - gfree(fontIDs); - } - if (fontFileIDs) { - gfree(fontFileIDs); - } - if (fontFileNames) { - for (i = 0; i < fontFileNameLen; ++i) { - delete fontFileNames[i]; - } - gfree(fontFileNames); - } - if (psFileNames) { - for (i = 0; i < fontFileNameLen; ++i) { - if (psFileNames[i]) - delete psFileNames[i]; - } - gfree(psFileNames); - } - if (font16Enc) { - for (i = 0; i < font16EncLen; ++i) { - delete font16Enc[i].enc; - } - gfree(font16Enc); - } - if (xobjStack) { - delete xobjStack; - } - while (customColors) { - cc = customColors; - customColors = cc->next; - delete cc; - } -} - -void PSOutputDev::writeHeader(int firstPage, int lastPage, - PDFRectangle *mediaBox, PDFRectangle *cropBox, - int pageRotate) { - double x1, y1, x2, y2; - - switch (mode) { - case psModePS: - writePS("%!PS-Adobe-3.0\n"); - writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); - writePSFmt("%%%%LanguageLevel: %d\n", - (level == psLevel1 || level == psLevel1Sep) ? 1 : - (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); - if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { - writePS("%%DocumentProcessColors: (atend)\n"); - writePS("%%DocumentCustomColors: (atend)\n"); - } - writePS("%%DocumentSuppliedResources: (atend)\n"); - writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n", - paperWidth, paperHeight); - writePSFmt("%%%%BoundingBox: 0 0 %d %d\n", paperWidth, paperHeight); - writePSFmt("%%%%Pages: %d\n", lastPage - firstPage + 1); - writePS("%%EndComments\n"); - writePS("%%BeginDefaults\n"); - writePS("%%PageMedia: plain\n"); - writePS("%%EndDefaults\n"); - break; - case psModeEPS: - writePS("%!PS-Adobe-3.0 EPSF-3.0\n"); - writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); - writePSFmt("%%%%LanguageLevel: %d\n", - (level == psLevel1 || level == psLevel1Sep) ? 1 : - (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); - if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { - writePS("%%DocumentProcessColors: (atend)\n"); - writePS("%%DocumentCustomColors: (atend)\n"); - } - epsX1 = cropBox->x1; - epsY1 = cropBox->y1; - epsX2 = cropBox->x2; - epsY2 = cropBox->y2; - if (pageRotate == 0 || pageRotate == 180) { - x1 = epsX1; - y1 = epsY1; - x2 = epsX2; - y2 = epsY2; - } else { // pageRotate == 90 || pageRotate == 270 - x1 = 0; - y1 = 0; - x2 = epsY2 - epsY1; - y2 = epsX2 - epsX1; - } - writePSFmt("%%%%BoundingBox: %d %d %d %d\n", - (int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2)); - if (floor(x1) != ceil(x1) || floor(y1) != ceil(y1) || - floor(x2) != ceil(x2) || floor(y2) != ceil(y2)) { - writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", x1, y1, x2, y2); - } - writePS("%%DocumentSuppliedResources: (atend)\n"); - writePS("%%EndComments\n"); - break; - case psModeForm: - writePS("%!PS-Adobe-3.0 Resource-Form\n"); - writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); - writePSFmt("%%%%LanguageLevel: %d\n", - (level == psLevel1 || level == psLevel1Sep) ? 1 : - (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); - if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { - writePS("%%DocumentProcessColors: (atend)\n"); - writePS("%%DocumentCustomColors: (atend)\n"); - } - writePS("%%DocumentSuppliedResources: (atend)\n"); - writePS("%%EndComments\n"); - writePS("32 dict dup begin\n"); - writePSFmt("/BBox [%d %d %d %d] def\n", - (int)floor(mediaBox->x1), (int)floor(mediaBox->y1), - (int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2)); - writePS("/FormType 1 def\n"); - writePS("/Matrix [1 0 0 1 0 0] def\n"); - break; - } -} - -void PSOutputDev::writeXpdfProcset() { - GBool lev1, lev2, lev3, sep, nonSep; - const char **p; - const char *q; - - writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion); - lev1 = lev2 = lev3 = sep = nonSep = gTrue; - for (p = prolog; *p; ++p) { - if ((*p)[0] == '~') { - lev1 = lev2 = lev3 = sep = nonSep = gFalse; - for (q = *p + 1; *q; ++q) { - switch (*q) { - case '1': lev1 = gTrue; break; - case '2': lev2 = gTrue; break; - case '3': lev3 = gTrue; break; - case 's': sep = gTrue; break; - case 'n': nonSep = gTrue; break; - } - } - } else if ((level == psLevel1 && lev1 && nonSep) || - (level == psLevel1Sep && lev1 && sep) || - (level == psLevel2 && lev2 && nonSep) || - (level == psLevel2Sep && lev2 && sep) || - (level == psLevel3 && lev3 && nonSep) || - (level == psLevel3Sep && lev3 && sep)) { - writePSFmt("%s\n", *p); - } - } - writePS("%%EndResource\n"); - - if (level >= psLevel3) { - for (p = cmapProlog; *p; ++p) { - writePSFmt("%s\n", *p); - } - } -} - -void PSOutputDev::writeDocSetup(Catalog *catalog, - int firstPage, int lastPage) { - Page *page; - Dict *resDict; - Annots *annots; - Object obj1, obj2; - int pg, i; - - if (mode == psModeForm) { - // swap the form and xpdf dicts - writePS("xpdf end begin dup begin\n"); - } else { - writePS("xpdf begin\n"); - } - for (pg = firstPage; pg <= lastPage; ++pg) { - page = catalog->getPage(pg); - if ((resDict = page->getResourceDict())) { - setupResources(resDict); - } - annots = new Annots(xref, catalog, page->getAnnots(&obj1)); - obj1.free(); - for (i = 0; i < annots->getNumAnnots(); ++i) { - if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) { - obj1.streamGetDict()->lookup("Resources", &obj2); - if (obj2.isDict()) { - setupResources(obj2.getDict()); - } - obj2.free(); - } - obj1.free(); - } - delete annots; - } - if (mode != psModeForm) { - if (mode != psModeEPS && !manualCtrl) { - writePSFmt("%d %d %s pdfSetup\n", - paperWidth, paperHeight, - globalParams->getPSDuplex() ? "true" : "false"); - } -#if OPI_SUPPORT - if (globalParams->getPSOPI()) { - writePS("/opiMatrix matrix currentmatrix def\n"); - } -#endif - } -} - -void PSOutputDev::writePageTrailer() { - if (mode != psModeForm) { - writePS("pdfEndPage\n"); - } -} - -void PSOutputDev::writeTrailer() { - PSOutCustomColor *cc; - - if (mode == psModeForm) { - writePS("/Foo exch /Form defineresource pop\n"); - } else { - writePS("end\n"); - writePS("%%DocumentSuppliedResources:\n"); - writePS(embFontList->getCString()); - if (level == psLevel1Sep || level == psLevel2Sep || - level == psLevel3Sep) { - writePS("%%DocumentProcessColors:"); - if (processColors & psProcessCyan) { - writePS(" Cyan"); - } - if (processColors & psProcessMagenta) { - writePS(" Magenta"); - } - if (processColors & psProcessYellow) { - writePS(" Yellow"); - } - if (processColors & psProcessBlack) { - writePS(" Black"); - } - writePS("\n"); - writePS("%%DocumentCustomColors:"); - for (cc = customColors; cc; cc = cc->next) { - writePSFmt(" (%s)", cc->name->getCString()); - } - writePS("\n"); - writePS("%%CMYKCustomColor:\n"); - for (cc = customColors; cc; cc = cc->next) { - writePSFmt("%%%%+ %g %g %g %g (%s)\n", - cc->c, cc->m, cc->y, cc->k, cc->name->getCString()); - } - } - } -} - -void PSOutputDev::setupResources(Dict *resDict) { - Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj; - Ref ref0, ref1; - GBool skip; - int i, j; - - setupFonts(resDict); - setupImages(resDict); - - //----- recursively scan XObjects - resDict->lookup("XObject", &xObjDict); - if (xObjDict.isDict()) { - for (i = 0; i < xObjDict.dictGetLength(); ++i) { - - // avoid infinite recursion on XObjects - skip = gFalse; - if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) { - ref0 = xObjRef.getRef(); - for (j = 0; j < xobjStack->getLength(); ++j) { - ref1 = *(Ref *)xobjStack->get(j); - if (ref1.num == ref0.num && ref1.gen == ref0.gen) { - skip = gTrue; - break; - } - } - if (!skip) { - xobjStack->append(&ref0); - } - } - if (!skip) { - - // process the XObject's resource dictionary - xObjDict.dictGetVal(i, &xObj); - if (xObj.isStream()) { - xObj.streamGetDict()->lookup("Resources", &resObj); - if (resObj.isDict()) { - setupResources(resObj.getDict()); - } - resObj.free(); - } - xObj.free(); - } - - if (xObjRef.isRef() && !skip) { - xobjStack->del(xobjStack->getLength() - 1); - } - xObjRef.free(); - } - } - xObjDict.free(); - - //----- recursively scan Patterns - resDict->lookup("Pattern", &patDict); - if (patDict.isDict()) { - inType3Char = gTrue; - for (i = 0; i < patDict.dictGetLength(); ++i) { - - // avoid infinite recursion on Patterns - skip = gFalse; - if ((patDict.dictGetValNF(i, &patRef)->isRef())) { - ref0 = patRef.getRef(); - for (j = 0; j < xobjStack->getLength(); ++j) { - ref1 = *(Ref *)xobjStack->get(j); - if (ref1.num == ref0.num && ref1.gen == ref0.gen) { - skip = gTrue; - break; - } - } - if (!skip) { - xobjStack->append(&ref0); - } - } - if (!skip) { - - // process the Pattern's resource dictionary - patDict.dictGetVal(i, &pat); - if (pat.isStream()) { - pat.streamGetDict()->lookup("Resources", &resObj); - if (resObj.isDict()) { - setupResources(resObj.getDict()); - } - resObj.free(); - } - pat.free(); - } - - if (patRef.isRef() && !skip) { - xobjStack->del(xobjStack->getLength() - 1); - } - patRef.free(); - } - inType3Char = gFalse; - } - patDict.free(); -} - -void PSOutputDev::setupFonts(Dict *resDict) { - Object obj1, obj2; - Ref r; - GfxFontDict *gfxFontDict; - GfxFont *font; - int i; - - gfxFontDict = NULL; - resDict->lookupNF("Font", &obj1); - if (obj1.isRef()) { - obj1.fetch(xref, &obj2); - if (obj2.isDict()) { - r = obj1.getRef(); - gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict()); - } - obj2.free(); - } else if (obj1.isDict()) { - gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict()); - } - if (gfxFontDict) { - for (i = 0; i < gfxFontDict->getNumFonts(); ++i) { - if ((font = gfxFontDict->getFont(i))) { - setupFont(font, resDict); - } - } - delete gfxFontDict; - } - obj1.free(); -} - -void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { - Ref fontFileID; - GString *name; - PSFontParam *fontParam; - GString *psName; - char type3Name[64], buf[16]; - GBool subst; - UnicodeMap *uMap; - const char *charName; - double xs, ys; - int code; - double w1, w2; - double *fm; - int i, j; - DisplayFontParam *dfp; - - // check if font is already set up - for (i = 0; i < fontIDLen; ++i) { - if (fontIDs[i].num == font->getID()->num && - fontIDs[i].gen == font->getID()->gen) { - return; - } - } - - // add entry to fontIDs list - if (fontIDLen >= fontIDSize) { - fontIDSize += 64; - fontIDs = (Ref *)greallocn(fontIDs, fontIDSize, sizeof(Ref)); - } - fontIDs[fontIDLen++] = *font->getID(); - - xs = ys = 1; - subst = gFalse; - - // check for resident 8-bit font - if (font->getName() && - (fontParam = globalParams->getPSFont(font->getName()))) { - psName = new GString(fontParam->psFontName->getCString()); - - // check for embedded Type 1 font - } else if (globalParams->getPSEmbedType1() && - font->getType() == fontType1 && - font->getEmbeddedFontID(&fontFileID)) { - psName = filterPSName(font->getEmbeddedFontName()); - setupEmbeddedType1Font(&fontFileID, psName); - - // check for embedded Type 1C font - } else if (globalParams->getPSEmbedType1() && - font->getType() == fontType1C && - font->getEmbeddedFontID(&fontFileID)) { - psName = filterPSName(font->getEmbeddedFontName()); - setupEmbeddedType1CFont(font, &fontFileID, psName); - - // check for external Type 1 font file - } else if (globalParams->getPSEmbedType1() && - font->getType() == fontType1 && - font->getExtFontFile()) { - // this assumes that the PS font name matches the PDF font name - psName = font->getName()->copy(); - setupExternalType1Font(font->getExtFontFile(), psName); - - // check for embedded TrueType font - } else if (globalParams->getPSEmbedTrueType() && - font->getType() == fontTrueType && - font->getEmbeddedFontID(&fontFileID)) { - psName = filterPSName(font->getEmbeddedFontName()); - setupEmbeddedTrueTypeFont(font, &fontFileID, psName); - - // check for external TrueType font file - } else if (globalParams->getPSEmbedTrueType() && - font->getType() == fontTrueType && - font->getExtFontFile()) { - psName = setupExternalTrueTypeFont(font); - - // check for embedded CID PostScript font - } else if (globalParams->getPSEmbedCIDPostScript() && - font->getType() == fontCIDType0C && - font->getEmbeddedFontID(&fontFileID)) { - psName = filterPSName(font->getEmbeddedFontName()); - setupEmbeddedCIDType0Font(font, &fontFileID, psName); - - // check for embedded CID TrueType font - } else if (globalParams->getPSEmbedCIDTrueType() && - font->getType() == fontCIDType2 && - font->getEmbeddedFontID(&fontFileID)) { - psName = filterPSName(font->getEmbeddedFontName()); - //~ should check to see if font actually uses vertical mode - setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue); - - } else if (font->getType() == fontType3) { - sprintf(type3Name, "T3_%d_%d", - font->getID()->num, font->getID()->gen); - psName = new GString(type3Name); - setupType3Font(font, psName, parentResDict); - - // check for external CID TrueType font file - } else if (globalParams->getPSEmbedCIDTrueType() && - font->getType() == fontCIDType2 && - font->getExtFontFile()) { - psName = setupExternalCIDTrueTypeFont(font, font->getExtFontFile()); - - // do 8-bit font substitution - } else if (!font->isCIDFont()) { - subst = gTrue; - name = font->getName(); - psName = NULL; - if (name) { - for (i = 0; psFonts[i]; ++i) { - if (name->cmp(psFonts[i]) == 0) { - psName = new GString(psFonts[i]); - break; - } - } - } - if (!psName) { - if (font->isFixedWidth()) { - i = 8; - } else if (font->isSerif()) { - i = 4; - } else { - i = 0; - } - if (font->isBold()) { - i += 2; - } - if (font->isItalic()) { - i += 1; - } - psName = new GString(psSubstFonts[i].psName); - for (code = 0; code < 256; ++code) { - if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) && - charName[0] == 'm' && charName[1] == '\0') { - break; - } - } - if (code < 256) { - w1 = ((Gfx8BitFont *)font)->getWidth(code); - } else { - w1 = 0; - } - w2 = psSubstFonts[i].mWidth; - xs = w1 / w2; - if (xs < 0.1) { - xs = 1; - } - if (font->getType() == fontType3) { - // This is a hack which makes it possible to substitute for some - // Type 3 fonts. The problem is that it's impossible to know what - // the base coordinate system used in the font is without actually - // rendering the font. - ys = xs; - fm = font->getFontMatrix(); - if (fm[0] != 0) { - ys *= fm[3] / fm[0]; - } - } else { - ys = 1; - } - } - - // do 16-bit font substitution - } else if ((fontParam = globalParams-> - getPSFont16(font->getName(), - ((GfxCIDFont *)font)->getCollection(), - font->getWMode()))) { - subst = gTrue; - psName = fontParam->psFontName->copy(); - if (font16EncLen >= font16EncSize) { - font16EncSize += 16; - font16Enc = (PSFont16Enc *)greallocn(font16Enc, - font16EncSize, sizeof(PSFont16Enc)); - } - font16Enc[font16EncLen].fontID = *font->getID(); - font16Enc[font16EncLen].enc = fontParam->encoding->copy(); - if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) { - uMap->decRefCnt(); - ++font16EncLen; - } else { - error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'", - font16Enc[font16EncLen].enc->getCString()); - } - - // try the display font for embedding - } else if (globalParams->getPSEmbedCIDTrueType() && - ((GfxCIDFont *)font)->getCollection() && - (dfp = globalParams-> - getDisplayCIDFont(font->getName(), - ((GfxCIDFont *)font)->getCollection())) && - dfp->kind == displayFontTT) { - psName = setupExternalCIDTrueTypeFont(font, dfp->tt.fileName, dfp->tt.faceIndex); - - // give up - can't do anything with this font - } else { - error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)", - font->getName() ? font->getName()->getCString() : "(unnamed)", - ((GfxCIDFont *)font)->getCollection() - ? ((GfxCIDFont *)font)->getCollection()->getCString() - : "(unknown)"); - return; - } - - // generate PostScript code to set up the font - if (font->isCIDFont()) { - if (level == psLevel3 || level == psLevel3Sep) { - writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n", - font->getID()->num, font->getID()->gen, psName->getCString(), - font->getWMode()); - } else { - writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n", - font->getID()->num, font->getID()->gen, psName->getCString(), - font->getWMode()); - } - } else { - writePSFmt("/F%d_%d /%s %g %g\n", - font->getID()->num, font->getID()->gen, psName->getCString(), - xs, ys); - for (i = 0; i < 256; i += 8) { - writePSFmt((i == 0) ? "[ " : " "); - for (j = 0; j < 8; ++j) { - if (font->getType() == fontTrueType && - !subst && - !((Gfx8BitFont *)font)->getHasEncoding()) { - sprintf(buf, "c%02x", i+j); - charName = buf; - } else { - charName = ((Gfx8BitFont *)font)->getCharName(i+j); - // this is a kludge for broken PDF files that encode char 32 - // as .notdef - if (i+j == 32 && charName && !strcmp(charName, ".notdef")) { - charName = "space"; - } - } - writePS("/"); - writePSName(charName ? charName : (const char *)".notdef"); - // the empty name is legal in PDF and PostScript, but PostScript - // uses a double-slash (//...) for "immediately evaluated names", - // so we need to add a space character here - if (charName && !charName[0]) { - writePS(" "); - } - } - writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n"); - } - writePS("pdfMakeFont\n"); - } - - delete psName; -} - -void PSOutputDev::setupEmbeddedType1Font(Ref *id, GString *psName) { - static char hexChar[17] = "0123456789abcdef"; - Object refObj, strObj, obj1, obj2, obj3; - Dict *dict; - int length1, length2, length3; - int c; - int start[4]; - GBool binMode; - int i; - - // check if font is already embedded - for (i = 0; i < fontFileIDLen; ++i) { - if (fontFileIDs[i].num == id->num && - fontFileIDs[i].gen == id->gen) - return; - } - - // add entry to fontFileIDs list - if (fontFileIDLen >= fontFileIDSize) { - fontFileIDSize += 64; - fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); - } - fontFileIDs[fontFileIDLen++] = *id; - - // get the font stream and info - refObj.initRef(id->num, id->gen); - refObj.fetch(xref, &strObj); - refObj.free(); - if (!strObj.isStream()) { - error(-1, "Embedded font file object is not a stream"); - goto err1; - } - if (!(dict = strObj.streamGetDict())) { - error(-1, "Embedded font stream is missing its dictionary"); - goto err1; - } - dict->lookup("Length1", &obj1); - dict->lookup("Length2", &obj2); - dict->lookup("Length3", &obj3); - if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) { - error(-1, "Missing length fields in embedded font stream dictionary"); - obj1.free(); - obj2.free(); - obj3.free(); - goto err1; - } - length1 = obj1.getInt(); - length2 = obj2.getInt(); - length3 = obj3.getInt(); - obj1.free(); - obj2.free(); - obj3.free(); - - // beginning comment - writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); - embFontList->append("%%+ font "); - embFontList->append(psName->getCString()); - embFontList->append("\n"); - - // copy ASCII portion of font - strObj.streamReset(); - for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) { - writePSChar(c); - } - - // figure out if encrypted portion is binary or ASCII - binMode = gFalse; - for (i = 0; i < 4; ++i) { - start[i] = strObj.streamGetChar(); - if (start[i] == EOF) { - error(-1, "Unexpected end of file in embedded font stream"); - goto err1; - } - if (!((start[i] >= '0' && start[i] <= '9') || - (start[i] >= 'A' && start[i] <= 'F') || - (start[i] >= 'a' && start[i] <= 'f'))) - binMode = gTrue; - } - - // convert binary data to ASCII - if (binMode) { - for (i = 0; i < 4; ++i) { - writePSChar(hexChar[(start[i] >> 4) & 0x0f]); - writePSChar(hexChar[start[i] & 0x0f]); - } -#if 0 // this causes trouble for various PostScript printers - // if Length2 is incorrect (too small), font data gets chopped, so - // we take a few extra characters from the trailer just in case - length2 += length3 >= 8 ? 8 : length3; -#endif - while (i < length2) { - if ((c = strObj.streamGetChar()) == EOF) { - break; - } - writePSChar(hexChar[(c >> 4) & 0x0f]); - writePSChar(hexChar[c & 0x0f]); - if (++i % 32 == 0) { - writePSChar('\n'); - } - } - if (i % 32 > 0) { - writePSChar('\n'); - } - - // already in ASCII format -- just copy it - } else { - for (i = 0; i < 4; ++i) { - writePSChar(start[i]); - } - for (i = 4; i < length2; ++i) { - if ((c = strObj.streamGetChar()) == EOF) { - break; - } - writePSChar(c); - } - } - - // write padding and "cleartomark" - for (i = 0; i < 8; ++i) { - writePS("00000000000000000000000000000000" - "00000000000000000000000000000000\n"); - } - writePS("cleartomark\n"); - - // ending comment - writePS("%%EndResource\n"); - - err1: - strObj.streamClose(); - strObj.free(); -} - -//~ This doesn't handle .pfb files or binary eexec data (which only -//~ happens in pfb files?). -void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) { - FILE *fontFile; - int c; - int i; - - // check if font is already embedded - for (i = 0; i < fontFileNameLen; ++i) { - if (!fontFileNames[i]->cmp(fileName)) { - return; - } - } - - // add entry to fontFileNames list - if (fontFileNameLen >= fontFileNameSize) { - fontFileNameSize += 64; - fontFileNames = (GString **)greallocn(fontFileNames, - fontFileNameSize, sizeof(GString *)); - psFileNames = (GString **)greallocn(psFileNames, - fontFileNameSize, sizeof(GString *)); - } - fontFileNames[fontFileNameLen] = fileName->copy(); - psFileNames[fontFileNameLen] = psName->copy(); - fontFileNameLen++; - - // beginning comment - writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); - embFontList->append("%%+ font "); - embFontList->append(psName->getCString()); - embFontList->append("\n"); - - // copy the font file - if (!(fontFile = fopen(fileName->getCString(), "rb"))) { - error(-1, "Couldn't open external font file"); - return; - } - while ((c = fgetc(fontFile)) != EOF) { - writePSChar(c); - } - fclose(fontFile); - - // ending comment - writePS("%%EndResource\n"); -} - -void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, - GString *psName) { - char *fontBuf; - int fontLen; - FoFiType1C *ffT1C; - int i; - - // check if font is already embedded - for (i = 0; i < fontFileIDLen; ++i) { - if (fontFileIDs[i].num == id->num && - fontFileIDs[i].gen == id->gen) - return; - } - - // add entry to fontFileIDs list - if (fontFileIDLen >= fontFileIDSize) { - fontFileIDSize += 64; - fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); - } - fontFileIDs[fontFileIDLen++] = *id; - - // beginning comment - writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); - embFontList->append("%%+ font "); - embFontList->append(psName->getCString()); - embFontList->append("\n"); - - // convert it to a Type 1 font - fontBuf = font->readEmbFontFile(xref, &fontLen); - if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { - ffT1C->convertToType1(NULL, gTrue, outputFunc, outputStream); - delete ffT1C; - } - gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); -} - -void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, - GString *psName) { - char unique[32]; - char *fontBuf; - int fontLen; - FoFiTrueType *ffTT; - Gushort *codeToGID; - int i; - - // check if font is already embedded - for (i = 0; i < fontFileIDLen; ++i) { - if (fontFileIDs[i].num == id->num && - fontFileIDs[i].gen == id->gen) { - sprintf(unique, "_%d", nextTrueTypeNum++); - psName->append(unique); - break; - } - } - - // add entry to fontFileIDs list - if (i == fontFileIDLen) { - if (fontFileIDLen >= fontFileIDSize) { - fontFileIDSize += 64; - fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); - } - fontFileIDs[fontFileIDLen++] = *id; - } - - // beginning comment - writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); - embFontList->append("%%+ font "); - embFontList->append(psName->getCString()); - embFontList->append("\n"); - - // convert it to a Type 42 font - fontBuf = font->readEmbFontFile(xref, &fontLen); - if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { - codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); - ffTT->convertToType42(psName->getCString(), - ((Gfx8BitFont *)font)->getHasEncoding() - ? ((Gfx8BitFont *)font)->getEncoding() - : (const char **)NULL, - codeToGID, outputFunc, outputStream); - gfree(codeToGID); - delete ffTT; - } - gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); -} - -GString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) { - GString *fileName; - char *fontBuf; - int fontLen; - FoFiTrueType *ffTT; - Gushort *codeToGID; - GString *psName; - int i; - - // check if font is already embedded - fileName = font->getExtFontFile(); - for (i = 0; i < fontFileNameLen; ++i) { - if (!fontFileNames[i]->cmp(fileName)) { - return psFileNames[i]->copy(); - } - } - - psName = filterPSName(font->getName()); - // add entry to fontFileNames list - if (i == fontFileNameLen) { - if (fontFileNameLen >= fontFileNameSize) { - fontFileNameSize += 64; - fontFileNames = - (GString **)greallocn(fontFileNames, - fontFileNameSize, sizeof(GString *)); - psFileNames = - (GString **)greallocn(psFileNames, - fontFileNameSize, sizeof(GString *)); - } - } - fontFileNames[fontFileNameLen] = fileName->copy(); - psFileNames[fontFileNameLen] = psName->copy(); - fontFileNameLen++; - - // beginning comment - writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); - embFontList->append("%%+ font "); - embFontList->append(psName->getCString()); - embFontList->append("\n"); - - // convert it to a Type 42 font - fontBuf = font->readExtFontFile(&fontLen); - if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { - codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); - ffTT->convertToType42(psName->getCString(), - ((Gfx8BitFont *)font)->getHasEncoding() - ? ((Gfx8BitFont *)font)->getEncoding() - : (const char **)NULL, - codeToGID, outputFunc, outputStream); - delete ffTT; - } - gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); - return psName; -} - -GString *PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, int faceIndex) { -// char *fontBuf; -// int fontLen; - FoFiTrueType *ffTT; - Gushort *codeToGID; - GString *psName; - int i; - GString *myFileName; - - myFileName = fileName->copy(); - if (faceIndex > 0) { - char tmp[32]; - sprintf(tmp, ",%d", faceIndex); - myFileName->append(tmp); - } - // check if font is already embedded - for (i = 0; i < fontFileNameLen; ++i) { - if (!fontFileNames[i]->cmp(myFileName)) { - delete myFileName; - return psFileNames[i]->copy(); - } - } - - psName = filterPSName(font->getName()); - // add entry to fontFileNames list - if (i == fontFileNameLen) { - if (fontFileNameLen >= fontFileNameSize) { - fontFileNameSize += 64; - fontFileNames = - (GString **)grealloc(fontFileNames, - fontFileNameSize * sizeof(GString *)); - psFileNames = - (GString **)grealloc(psFileNames, - fontFileNameSize * sizeof(GString *)); - } - } - fontFileNames[fontFileNameLen] = myFileName; - psFileNames[fontFileNameLen] = psName->copy(); - fontFileNameLen++; - - // beginning comment - writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); - embFontList->append("%%+ font "); - embFontList->append(psName->getCString()); - embFontList->append("\n"); - - // convert it to a CID type2 font - if ((ffTT = FoFiTrueType::load(fileName->getCString(), faceIndex))) { - int n = ((GfxCIDFont *)font)->getCIDToGIDLen(); - if (n) { - codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort)); - memcpy(codeToGID, ((GfxCIDFont *)font)->getCIDToGID(), n * sizeof(Gushort)); - } else { - codeToGID = ((GfxCIDFont *)font)->getCodeToGIDMap(ffTT, &n); - } - if (globalParams->getPSLevel() >= psLevel3) { - // Level 3: use a CID font - ffTT->convertToCIDType2(psName->getCString(), - codeToGID, n, gTrue, - outputFunc, outputStream); - } else { - // otherwise: use a non-CID composite font - ffTT->convertToType0(psName->getCString(), - codeToGID, n, gTrue, - outputFunc, outputStream); - } - gfree(codeToGID); - delete ffTT; - } - - // ending comment - writePS("%%EndResource\n"); - return psName; -} - -void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, - GString *psName) { - char *fontBuf; - int fontLen; - FoFiType1C *ffT1C; - int i; - - // check if font is already embedded - for (i = 0; i < fontFileIDLen; ++i) { - if (fontFileIDs[i].num == id->num && - fontFileIDs[i].gen == id->gen) - return; - } - - // add entry to fontFileIDs list - if (fontFileIDLen >= fontFileIDSize) { - fontFileIDSize += 64; - fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); - } - fontFileIDs[fontFileIDLen++] = *id; - - // beginning comment - writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); - embFontList->append("%%+ font "); - embFontList->append(psName->getCString()); - embFontList->append("\n"); - - // convert it to a Type 0 font - fontBuf = font->readEmbFontFile(xref, &fontLen); - if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { - if (globalParams->getPSLevel() >= psLevel3) { - // Level 3: use a CID font - ffT1C->convertToCIDType0(psName->getCString(), outputFunc, outputStream); - } else { - // otherwise: use a non-CID composite font - ffT1C->convertToType0(psName->getCString(), outputFunc, outputStream); - } - delete ffT1C; - } - gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); -} - -void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, - GString *psName, - GBool needVerticalMetrics) { - char unique[32]; - char *fontBuf; - int fontLen; - FoFiTrueType *ffTT; - int i; - - // check if font is already embedded - for (i = 0; i < fontFileIDLen; ++i) { - if (fontFileIDs[i].num == id->num && - fontFileIDs[i].gen == id->gen) { - sprintf(unique, "_%d", nextTrueTypeNum++); - psName->append(unique); - break; - } - } - - // add entry to fontFileIDs list - if (fontFileIDLen >= fontFileIDSize) { - fontFileIDSize += 64; - fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); - } - fontFileIDs[fontFileIDLen++] = *id; - - // beginning comment - writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); - embFontList->append("%%+ font "); - embFontList->append(psName->getCString()); - embFontList->append("\n"); - - // convert it to a Type 0 font - fontBuf = font->readEmbFontFile(xref, &fontLen); - if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { - if (globalParams->getPSLevel() >= psLevel3) { - // Level 3: use a CID font - ffTT->convertToCIDType2(psName->getCString(), - ((GfxCIDFont *)font)->getCIDToGID(), - ((GfxCIDFont *)font)->getCIDToGIDLen(), - needVerticalMetrics, - outputFunc, outputStream); - } else { - // otherwise: use a non-CID composite font - ffTT->convertToType0(psName->getCString(), - ((GfxCIDFont *)font)->getCIDToGID(), - ((GfxCIDFont *)font)->getCIDToGIDLen(), - needVerticalMetrics, - outputFunc, outputStream); - } - delete ffTT; - } - gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); -} - -void PSOutputDev::setupType3Font(GfxFont *font, GString *psName, - Dict *parentResDict) { - Dict *resDict; - Dict *charProcs; - Object charProc; - Gfx *gfx; - PDFRectangle box; - double *m; - char buf[256]; - int i; - - // set up resources used by font - if ((resDict = ((Gfx8BitFont *)font)->getResources())) { - inType3Char = gTrue; - setupResources(resDict); - inType3Char = gFalse; - } else { - resDict = parentResDict; - } - - // beginning comment - writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); - embFontList->append("%%+ font "); - embFontList->append(psName->getCString()); - embFontList->append("\n"); - - // font dictionary - writePS("8 dict begin\n"); - writePS("/FontType 3 def\n"); - m = font->getFontMatrix(); - writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n", - m[0], m[1], m[2], m[3], m[4], m[5]); - m = font->getFontBBox(); - writePSFmt("/FontBBox [%g %g %g %g] def\n", - m[0], m[1], m[2], m[3]); - writePS("/Encoding 256 array def\n"); - writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); - writePS("/BuildGlyph {\n"); - writePS(" exch /CharProcs get exch\n"); - writePS(" 2 copy known not { pop /.notdef } if\n"); - writePS(" get exec\n"); - writePS("} bind def\n"); - writePS("/BuildChar {\n"); - writePS(" 1 index /Encoding get exch get\n"); - writePS(" 1 index /BuildGlyph get exec\n"); - writePS("} bind def\n"); - if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) { - writePSFmt("/CharProcs %d dict def\n", charProcs->getLength()); - writePS("CharProcs begin\n"); - box.x1 = m[0]; - box.y1 = m[1]; - box.x2 = m[2]; - box.y2 = m[3]; - gfx = new Gfx(xref, this, resDict, &box, NULL); - inType3Char = gTrue; - t3Cacheable = gFalse; - for (i = 0; i < charProcs->getLength(); ++i) { - writePS("/"); - const char *aux = charProcs->getKey(i)->getCString(); - writePSName(aux); - delete[] aux; - writePS(" {\n"); - gfx->display(charProcs->getVal(i, &charProc)); - charProc.free(); - if (t3String) { - if (t3Cacheable) { - sprintf(buf, "%g %g %g %g %g %g setcachedevice\n", - t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY); - } else { - sprintf(buf, "%g %g setcharwidth\n", t3WX, t3WY); - } - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, t3String->getCString(), - t3String->getLength()); - delete t3String; - t3String = NULL; - } - (*outputFunc)(outputStream, "Q\n", 2); - writePS("} def\n"); - } - inType3Char = gFalse; - delete gfx; - writePS("end\n"); - } - writePS("currentdict end\n"); - writePSFmt("/%s exch definefont pop\n", psName->getCString()); - - // ending comment - writePS("%%EndResource\n"); -} - -void PSOutputDev::setupImages(Dict *resDict) { - Object xObjDict, xObj, xObjRef, subtypeObj; - int i; - - if (!(mode == psModeForm || inType3Char)) { - return; - } - - resDict->lookup("XObject", &xObjDict); - if (xObjDict.isDict()) { - for (i = 0; i < xObjDict.dictGetLength(); ++i) { - xObjDict.dictGetValNF(i, &xObjRef); - xObjDict.dictGetVal(i, &xObj); - if (xObj.isStream()) { - xObj.streamGetDict()->lookup("Subtype", &subtypeObj); - if (subtypeObj.isName("Image")) { - if (xObjRef.isRef()) { - setupImage(xObjRef.getRef(), xObj.getStream()); - } else { - error(-1, "Image in resource dict is not an indirect reference"); - } - } - subtypeObj.free(); - } - xObj.free(); - xObjRef.free(); - } - } - xObjDict.free(); -} - -void PSOutputDev::setupImage(Ref id, Stream *str) { - GBool useASCIIHex; - int c; - int size, line, col, i; - - // construct an encoder stream - useASCIIHex = level == psLevel1 || level == psLevel1Sep || - globalParams->getPSASCIIHex(); - if (useASCIIHex) { - str = new ASCIIHexEncoder(str); - } else { - str = new ASCII85Encoder(str); - } - - // compute image data size - str->reset(); - col = size = 0; - do { - do { - c = str->getChar(); - } while (c == '\n' || c == '\r'); - if (c == (useASCIIHex ? '>' : '~') || c == EOF) { - break; - } - if (c == 'z') { - ++col; - } else { - ++col; - for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { - do { - c = str->getChar(); - } while (c == '\n' || c == '\r'); - if (c == (useASCIIHex ? '>' : '~') || c == EOF) { - break; - } - ++col; - } - } - if (col > 225) { - ++size; - col = 0; - } - } while (c != (useASCIIHex ? '>' : '~') && c != EOF); - ++size; - writePSFmt("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen); - str->close(); - - // write the data into the array - str->reset(); - line = col = 0; - writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~")); - do { - do { - c = str->getChar(); - } while (c == '\n' || c == '\r'); - if (c == (useASCIIHex ? '>' : '~') || c == EOF) { - break; - } - if (c == 'z') { - writePSChar(c); - ++col; - } else { - writePSChar(c); - ++col; - for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { - do { - c = str->getChar(); - } while (c == '\n' || c == '\r'); - if (c == (useASCIIHex ? '>' : '~') || c == EOF) { - break; - } - writePSChar(c); - ++col; - } - } - // each line is: "dup nnnnn <~...data...~> put" - // so max data length = 255 - 20 = 235 - // chunks are 1 or 4 bytes each, so we have to stop at 232 - // but make it 225 just to be safe - if (col > 225) { - writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n")); - ++line; - writePSFmt((char *)(useASCIIHex ? "dup %d <" : "dup %d <~"), line); - col = 0; - } - } while (c != (useASCIIHex ? '>' : '~') && c != EOF); - writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n")); - writePS("pop\n"); - str->close(); - - delete str; -} - -void PSOutputDev::startPage(int pageNum, GfxState *state) { - int x1, y1, x2, y2, width, height; - int imgWidth, imgHeight, imgWidth2, imgHeight2; - GBool landscape; - - - if (mode == psModePS) { - writePSFmt("%%%%Page: %d %d\n", pageNum, seqPage); - writePS("%%BeginPageSetup\n"); - } - - // underlays - if (underlayCbk) { - (*underlayCbk)(this, underlayCbkData); - } - if (overlayCbk) { - saveState(NULL); - } - - switch (mode) { - - case psModePS: - // rotate, translate, and scale page - imgWidth = imgURX - imgLLX; - imgHeight = imgURY - imgLLY; - x1 = (int)floor(state->getX1()); - y1 = (int)floor(state->getY1()); - x2 = (int)ceil(state->getX2()); - y2 = (int)ceil(state->getY2()); - width = x2 - x1; - height = y2 - y1; - tx = ty = 0; - // rotation and portrait/landscape mode - if (rotate0 >= 0) { - rotate = (360 - rotate0) % 360; - landscape = gFalse; - } else { - rotate = (360 - state->getRotate()) % 360; - if (rotate == 0 || rotate == 180) { - if (width > height && width > imgWidth) { - rotate += 90; - landscape = gTrue; - } else { - landscape = gFalse; - } - } else { // rotate == 90 || rotate == 270 - if (height > width && height > imgWidth) { - rotate = 270 - rotate; - landscape = gTrue; - } else { - landscape = gFalse; - } - } - } - writePSFmt("%%%%PageOrientation: %s\n", - landscape ? "Landscape" : "Portrait"); - writePS("pdfStartPage\n"); - if (rotate == 0) { - imgWidth2 = imgWidth; - imgHeight2 = imgHeight; - } else if (rotate == 90) { - writePS("90 rotate\n"); - ty = -imgWidth; - imgWidth2 = imgHeight; - imgHeight2 = imgWidth; - } else if (rotate == 180) { - writePS("180 rotate\n"); - imgWidth2 = imgWidth; - imgHeight2 = imgHeight; - tx = -imgWidth; - ty = -imgHeight; - } else { // rotate == 270 - writePS("270 rotate\n"); - tx = -imgHeight; - imgWidth2 = imgHeight; - imgHeight2 = imgWidth; - } - // shrink or expand - if (xScale0 > 0 && yScale0 > 0) { - xScale = xScale0; - yScale = yScale0; - } else if ((globalParams->getPSShrinkLarger() && - (width > imgWidth2 || height > imgHeight2)) || - (globalParams->getPSExpandSmaller() && - (width < imgWidth2 && height < imgHeight2))) { - xScale = (double)imgWidth2 / (double)width; - yScale = (double)imgHeight2 / (double)height; - if (yScale < xScale) { - xScale = yScale; - } else { - yScale = xScale; - } - } else { - xScale = yScale = 1; - } - // deal with odd bounding boxes or clipping - if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { - tx -= xScale * clipLLX0; - ty -= yScale * clipLLY0; - } else { - tx -= xScale * x1; - ty -= yScale * y1; - } - // center - if (globalParams->getPSCenter()) { - if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { - tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2; - ty += (imgHeight2 - yScale * (clipURY0 - clipLLY0)) / 2; - } else { - tx += (imgWidth2 - xScale * width) / 2; - ty += (imgHeight2 - yScale * height) / 2; - } - } - tx += rotate == 0 ? imgLLX + tx0 : imgLLY + ty0; - ty += rotate == 0 ? imgLLY + ty0 : -(imgLLX + tx0); - if (tx != 0 || ty != 0) { - writePSFmt("%g %g translate\n", tx, ty); - } - if (xScale != 1 || yScale != 1) { - writePSFmt("%0.4f %0.4f scale\n", xScale, xScale); - } - if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { - writePSFmt("%g %g %g %g re W\n", - clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0); - } else { - writePSFmt("%d %d %d %d re W\n", x1, y1, x2 - x1, y2 - y1); - } - - writePS("%%EndPageSetup\n"); - ++seqPage; - break; - - case psModeEPS: - writePS("pdfStartPage\n"); - tx = ty = 0; - rotate = (360 - state->getRotate()) % 360; - if (rotate == 0) { - } else if (rotate == 90) { - writePS("90 rotate\n"); - tx = -epsX1; - ty = -epsY2; - } else if (rotate == 180) { - writePS("180 rotate\n"); - tx = -(epsX1 + epsX2); - ty = -(epsY1 + epsY2); - } else { // rotate == 270 - writePS("270 rotate\n"); - tx = -epsX2; - ty = -epsY1; - } - if (tx != 0 || ty != 0) { - writePSFmt("%g %g translate\n", tx, ty); - } - xScale = yScale = 1; - break; - - case psModeForm: - writePS("/PaintProc {\n"); - writePS("begin xpdf begin\n"); - writePS("pdfStartPage\n"); - tx = ty = 0; - xScale = yScale = 1; - rotate = 0; - break; - } -} - -void PSOutputDev::endPage() { - if (overlayCbk) { - restoreState(NULL); - (*overlayCbk)(this, overlayCbkData); - } - - - if (mode == psModeForm) { - writePS("pdfEndPage\n"); - writePS("end end\n"); - writePS("} def\n"); - writePS("end end\n"); - } else { - if (!manualCtrl) { - writePS("showpage\n"); - } - writePS("%%PageTrailer\n"); - writePageTrailer(); - } -} - -void PSOutputDev::saveState(GfxState */*state*/) { - writePS("q\n"); - ++numSaves; -} - -void PSOutputDev::restoreState(GfxState */*state*/) { - writePS("Q\n"); - --numSaves; -} - -void PSOutputDev::updateCTM(GfxState */*state*/, double m11, double m12, - double m21, double m22, double m31, double m32) { - writePSFmt("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32); -} - -void PSOutputDev::updateLineDash(GfxState *state) { - double *dash; - double start; - int length, i; - - state->getLineDash(&dash, &length, &start); - writePS("["); - for (i = 0; i < length; ++i) { - writePSFmt("%g%s", - dash[i] == 0 ? 1 : dash[i], - (i == length-1) ? "" : " "); - } - writePSFmt("] %g d\n", start); -} - -void PSOutputDev::updateFlatness(GfxState *state) { - writePSFmt("%d i\n", state->getFlatness()); -} - -void PSOutputDev::updateLineJoin(GfxState *state) { - writePSFmt("%d j\n", state->getLineJoin()); -} - -void PSOutputDev::updateLineCap(GfxState *state) { - writePSFmt("%d J\n", state->getLineCap()); -} - -void PSOutputDev::updateMiterLimit(GfxState *state) { - writePSFmt("%g M\n", state->getMiterLimit()); -} - -void PSOutputDev::updateLineWidth(GfxState *state) { - writePSFmt("%g w\n", state->getLineWidth()); -} - -void PSOutputDev::updateFillColorSpace(GfxState *state) { - switch (level) { - case psLevel1: - case psLevel1Sep: - break; - case psLevel2: - case psLevel3: - if (state->getFillColorSpace()->getMode() != csPattern) { - dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse); - writePS(" cs\n"); - } - break; - case psLevel2Sep: - case psLevel3Sep: - break; - } -} - -void PSOutputDev::updateStrokeColorSpace(GfxState *state) { - switch (level) { - case psLevel1: - case psLevel1Sep: - break; - case psLevel2: - case psLevel3: - if (state->getStrokeColorSpace()->getMode() != csPattern) { - dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse); - writePS(" CS\n"); - } - break; - case psLevel2Sep: - case psLevel3Sep: - break; - } -} - -void PSOutputDev::updateFillColor(GfxState *state) { - GfxColor color; - GfxColor *colorPtr; - GfxGray gray; - GfxCMYK cmyk; - GfxSeparationColorSpace *sepCS; - double c, m, y, k; - int i; - - switch (level) { - case psLevel1: - state->getFillGray(&gray); - writePSFmt("%g g\n", colToDbl(gray)); - break; - case psLevel1Sep: - state->getFillCMYK(&cmyk); - c = colToDbl(cmyk.c); - m = colToDbl(cmyk.m); - y = colToDbl(cmyk.y); - k = colToDbl(cmyk.k); - writePSFmt("%g %g %g %g k\n", c, m, y, k); - addProcessColor(c, m, y, k); - break; - case psLevel2: - case psLevel3: - if (state->getFillColorSpace()->getMode() != csPattern) { - colorPtr = state->getFillColor(); - writePS("["); - for (i = 0; i < state->getFillColorSpace()->getNComps(); ++i) { - if (i > 0) { - writePS(" "); - } - writePSFmt("%g", colToDbl(colorPtr->c[i])); - } - writePS("] sc\n"); - } - break; - case psLevel2Sep: - case psLevel3Sep: - if (state->getFillColorSpace()->getMode() == csSeparation) { - sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace(); - color.c[0] = gfxColorComp1; - sepCS->getCMYK(&color, &cmyk); - writePSFmt("%g %g %g %g %g (%s) ck\n", - colToDbl(state->getFillColor()->c[0]), - colToDbl(cmyk.c), colToDbl(cmyk.m), - colToDbl(cmyk.y), colToDbl(cmyk.k), - sepCS->getName()->getCString()); - addCustomColor(sepCS); - } else { - state->getFillCMYK(&cmyk); - c = colToDbl(cmyk.c); - m = colToDbl(cmyk.m); - y = colToDbl(cmyk.y); - k = colToDbl(cmyk.k); - writePSFmt("%g %g %g %g k\n", c, m, y, k); - addProcessColor(c, m, y, k); - } - break; - } - t3Cacheable = gFalse; -} - -void PSOutputDev::updateStrokeColor(GfxState *state) { - GfxColor color; - GfxColor *colorPtr; - GfxGray gray; - GfxCMYK cmyk; - GfxSeparationColorSpace *sepCS; - double c, m, y, k; - int i; - - switch (level) { - case psLevel1: - state->getStrokeGray(&gray); - writePSFmt("%g G\n", colToDbl(gray)); - break; - case psLevel1Sep: - state->getStrokeCMYK(&cmyk); - c = colToDbl(cmyk.c); - m = colToDbl(cmyk.m); - y = colToDbl(cmyk.y); - k = colToDbl(cmyk.k); - writePSFmt("%g %g %g %g K\n", c, m, y, k); - addProcessColor(c, m, y, k); - break; - case psLevel2: - case psLevel3: - if (state->getStrokeColorSpace()->getMode() != csPattern) { - colorPtr = state->getStrokeColor(); - writePS("["); - for (i = 0; i < state->getStrokeColorSpace()->getNComps(); ++i) { - if (i > 0) { - writePS(" "); - } - writePSFmt("%g", colToDbl(colorPtr->c[i])); - } - writePS("] SC\n"); - } - break; - case psLevel2Sep: - case psLevel3Sep: - if (state->getStrokeColorSpace()->getMode() == csSeparation) { - sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace(); - color.c[0] = gfxColorComp1; - sepCS->getCMYK(&color, &cmyk); - writePSFmt("%g %g %g %g %g (%s) CK\n", - colToDbl(state->getStrokeColor()->c[0]), - colToDbl(cmyk.c), colToDbl(cmyk.m), - colToDbl(cmyk.y), colToDbl(cmyk.k), - sepCS->getName()->getCString()); - addCustomColor(sepCS); - } else { - state->getStrokeCMYK(&cmyk); - c = colToDbl(cmyk.c); - m = colToDbl(cmyk.m); - y = colToDbl(cmyk.y); - k = colToDbl(cmyk.k); - writePSFmt("%g %g %g %g K\n", c, m, y, k); - addProcessColor(c, m, y, k); - } - break; - } - t3Cacheable = gFalse; -} - -void PSOutputDev::addProcessColor(double c, double m, double y, double k) { - if (c > 0) { - processColors |= psProcessCyan; - } - if (m > 0) { - processColors |= psProcessMagenta; - } - if (y > 0) { - processColors |= psProcessYellow; - } - if (k > 0) { - processColors |= psProcessBlack; - } -} - -void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) { - PSOutCustomColor *cc; - GfxColor color; - GfxCMYK cmyk; - - for (cc = customColors; cc; cc = cc->next) { - if (!cc->name->cmp(sepCS->getName())) { - return; - } - } - color.c[0] = gfxColorComp1; - sepCS->getCMYK(&color, &cmyk); - cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m), - colToDbl(cmyk.y), colToDbl(cmyk.k), - sepCS->getName()->copy()); - cc->next = customColors; - customColors = cc; -} - -void PSOutputDev::updateFillOverprint(GfxState *state) { - if (level >= psLevel2) { - writePSFmt("%s op\n", state->getFillOverprint() ? "true" : "false"); - } -} - -void PSOutputDev::updateStrokeOverprint(GfxState *state) { - if (level >= psLevel2) { - writePSFmt("%s OP\n", state->getStrokeOverprint() ? "true" : "false"); - } -} - -void PSOutputDev::updateFont(GfxState *state) { - if (state->getFont()) { - writePSFmt("/F%d_%d %g Tf\n", - state->getFont()->getID()->num, state->getFont()->getID()->gen, - fabs(state->getFontSize()) < 0.00001 ? 0.00001 - : state->getFontSize()); - } -} - -void PSOutputDev::updateTextMat(GfxState *state) { - double *mat; - - mat = state->getTextMat(); - if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) { - // avoid a singular (or close-to-singular) matrix - writePSFmt("[0.00001 0 0 0.00001 %g %g] Tm\n", mat[4], mat[5]); - } else { - writePSFmt("[%g %g %g %g %g %g] Tm\n", - mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); - } -} - -void PSOutputDev::updateCharSpace(GfxState *state) { - writePSFmt("%g Tc\n", state->getCharSpace()); -} - -void PSOutputDev::updateRender(GfxState *state) { - int rm; - - rm = state->getRender(); - writePSFmt("%d Tr\n", rm); - rm &= 3; - if (rm != 0 && rm != 3) { - t3Cacheable = gFalse; - } -} - -void PSOutputDev::updateRise(GfxState *state) { - writePSFmt("%g Ts\n", state->getRise()); -} - -void PSOutputDev::updateWordSpace(GfxState *state) { - writePSFmt("%g Tw\n", state->getWordSpace()); -} - -void PSOutputDev::updateHorizScaling(GfxState *state) { - double h; - - h = state->getHorizScaling(); - if (fabs(h) < 0.01) { - h = 0.01; - } - writePSFmt("%g Tz\n", h); -} - -void PSOutputDev::updateTextPos(GfxState *state) { - writePSFmt("%g %g Td\n", state->getLineX(), state->getLineY()); -} - -void PSOutputDev::updateTextShift(GfxState *state, double shift) { - if (state->getFont()->getWMode()) { - writePSFmt("%g TJmV\n", shift); - } else { - writePSFmt("%g TJm\n", shift); - } -} - -void PSOutputDev::stroke(GfxState *state) { - doPath(state->getPath()); - if (t3String) { - // if we're construct a cacheable Type 3 glyph, we need to do - // everything in the fill color - writePS("Sf\n"); - } else { - writePS("S\n"); - } -} - -void PSOutputDev::fill(GfxState *state) { - doPath(state->getPath()); - writePS("f\n"); -} - -void PSOutputDev::eoFill(GfxState *state) { - doPath(state->getPath()); - writePS("f*\n"); -} - -void PSOutputDev::tilingPatternFill(GfxState */*state*/, Object *str, - int paintType, Dict *resDict, - double *mat, double *bbox, - int x0, int y0, int x1, int y1, - double xStep, double yStep) { - PDFRectangle box; - Gfx *gfx; - - // define a Type 3 font - writePS("8 dict begin\n"); - writePS("/FontType 3 def\n"); - writePS("/FontMatrix [1 0 0 1 0 0] def\n"); - writePSFmt("/FontBBox [%g %g %g %g] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - writePS("/Encoding 256 array def\n"); - writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); - writePS(" Encoding 120 /x put\n"); - writePS("/BuildGlyph {\n"); - writePS(" exch /CharProcs get exch\n"); - writePS(" 2 copy known not { pop /.notdef } if\n"); - writePS(" get exec\n"); - writePS("} bind def\n"); - writePS("/BuildChar {\n"); - writePS(" 1 index /Encoding get exch get\n"); - writePS(" 1 index /BuildGlyph get exec\n"); - writePS("} bind def\n"); - writePS("/CharProcs 1 dict def\n"); - writePS("CharProcs begin\n"); - box.x1 = bbox[0]; - box.y1 = bbox[1]; - box.x2 = bbox[2]; - box.y2 = bbox[3]; - gfx = new Gfx(xref, this, resDict, &box, NULL); - writePS("/x {\n"); - if (paintType == 2) { - writePSFmt("%g 0 %g %g %g %g setcachedevice\n", - xStep, bbox[0], bbox[1], bbox[2], bbox[3]); - } else { - writePSFmt("%g 0 setcharwidth\n", xStep); - } - inType3Char = gTrue; - ++numTilingPatterns; - gfx->display(str); - --numTilingPatterns; - inType3Char = gFalse; - writePS("} def\n"); - delete gfx; - writePS("end\n"); - writePS("currentdict end\n"); - writePSFmt("/xpdfTile%d exch definefont pop\n", numTilingPatterns); - - // draw the tiles - writePSFmt("/xpdfTile%d findfont setfont\n", numTilingPatterns); - writePSFmt("gsave [%g %g %g %g %g %g] concat\n", - mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); - writePSFmt("%d 1 %d { %g exch %g mul m %d 1 %d { pop (x) show } for } for\n", - y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1); - writePS("grestore\n"); -} - -void PSOutputDev::functionShadedFill(GfxState */*state*/, - GfxFunctionShading *shading) { - double x0, y0, x1, y1; - double *mat; - int i; - - shading->getDomain(&x0, &y0, &x1, &y1); - mat = shading->getMatrix(); - writePSFmt("/mat [%g %g %g %g %g %g] def\n", - mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); - writePSFmt("/n %d def\n", shading->getColorSpace()->getNComps()); - if (shading->getNFuncs() == 1) { - writePS("/func "); - cvtFunction(shading->getFunc(0)); - writePS("def\n"); - } else { - writePS("/func {\n"); - for (i = 0; i < shading->getNFuncs(); ++i) { - if (i < shading->getNFuncs() - 1) { - writePS("2 copy\n"); - } - cvtFunction(shading->getFunc(i)); - writePS("exec\n"); - if (i < shading->getNFuncs() - 1) { - writePS("3 1 roll\n"); - } - } - writePS("} def\n"); - } - writePSFmt("%g %g %g %g 0 funcSH\n", x0, y0, x1, y1); -} - -void PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) { - double xMin, yMin, xMax, yMax; - double x0, y0, x1, y1, dx, dy, mul; - double tMin, tMax, t, t0, t1; - int i; - - // get the clip region bbox - state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - - // compute min and max t values, based on the four corners of the - // clip region bbox - shading->getCoords(&x0, &y0, &x1, &y1); - dx = x1 - x0; - dy = y1 - y0; - mul = 1 / (dx * dx + dy * dy); - tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; - t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; - if (t < tMin) { - tMin = t; - } else if (t > tMax) { - tMax = t; - } - t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul; - if (t < tMin) { - tMin = t; - } else if (t > tMax) { - tMax = t; - } - t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul; - if (t < tMin) { - tMin = t; - } else if (t > tMax) { - tMax = t; - } - if (tMin < 0 && !shading->getExtend0()) { - tMin = 0; - } - if (tMax > 1 && !shading->getExtend1()) { - tMax = 1; - } - - // get the function domain - t0 = shading->getDomain0(); - t1 = shading->getDomain1(); - - // generate the PS code - writePSFmt("/t0 %g def\n", t0); - writePSFmt("/t1 %g def\n", t1); - writePSFmt("/dt %g def\n", t1 - t0); - writePSFmt("/x0 %g def\n", x0); - writePSFmt("/y0 %g def\n", y0); - writePSFmt("/dx %g def\n", x1 - x0); - writePSFmt("/x1 %g def\n", x1); - writePSFmt("/y1 %g def\n", y1); - writePSFmt("/dy %g def\n", y1 - y0); - writePSFmt("/xMin %g def\n", xMin); - writePSFmt("/yMin %g def\n", yMin); - writePSFmt("/xMax %g def\n", xMax); - writePSFmt("/yMax %g def\n", yMax); - writePSFmt("/n %d def\n", shading->getColorSpace()->getNComps()); - if (shading->getNFuncs() == 1) { - writePS("/func "); - cvtFunction(shading->getFunc(0)); - writePS("def\n"); - } else { - writePS("/func {\n"); - for (i = 0; i < shading->getNFuncs(); ++i) { - if (i < shading->getNFuncs() - 1) { - writePS("dup\n"); - } - cvtFunction(shading->getFunc(i)); - writePS("exec\n"); - if (i < shading->getNFuncs() - 1) { - writePS("exch\n"); - } - } - writePS("} def\n"); - } - writePSFmt("%g %g 0 axialSH\n", tMin, tMax); -} - -void PSOutputDev::radialShadedFill(GfxState *state, - GfxRadialShading *shading) { - double x0, y0, r0, x1, y1, r1, t0, t1, sMin, sMax; - double xMin, yMin, xMax, yMax; - double d0, d1; - int i; - - // get the shading info - shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); - t0 = shading->getDomain0(); - t1 = shading->getDomain1(); - - // compute the (possibly extended) s range - sMin = 0; - sMax = 1; - if (shading->getExtend0()) { - if (r0 < r1) { - // extend the smaller end - sMin = -r0 / (r1 - r0); - } else { - // extend the larger end - state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - d0 = (x0 - xMin) * (x0 - xMin); - d1 = (x0 - xMax) * (x0 - xMax); - sMin = d0 > d1 ? d0 : d1; - d0 = (y0 - yMin) * (y0 - yMin); - d1 = (y0 - yMax) * (y0 - yMax); - sMin += d0 > d1 ? d0 : d1; - sMin = (sqrt(sMin) - r0) / (r1 - r0); - if (sMin > 0) { - sMin = 0; - } else if (sMin < -20) { - // sanity check - sMin = -20; - } - } - } - if (shading->getExtend1()) { - if (r1 < r0) { - // extend the smaller end - sMax = -r0 / (r1 - r0); - } else if (r1 > r0) { - // extend the larger end - state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - d0 = (x1 - xMin) * (x1 - xMin); - d1 = (x1 - xMax) * (x1 - xMax); - sMax = d0 > d1 ? d0 : d1; - d0 = (y1 - yMin) * (y1 - yMin); - d1 = (y1 - yMax) * (y1 - yMax); - sMax += d0 > d1 ? d0 : d1; - sMax = (sqrt(sMax) - r0) / (r1 - r0); - if (sMax < 1) { - sMax = 1; - } else if (sMax > 20) { - // sanity check - sMax = 20; - } - } - } - - // generate the PS code - writePSFmt("/x0 %g def\n", x0); - writePSFmt("/x1 %g def\n", x1); - writePSFmt("/dx %g def\n", x1 - x0); - writePSFmt("/y0 %g def\n", y0); - writePSFmt("/y1 %g def\n", y1); - writePSFmt("/dy %g def\n", y1 - y0); - writePSFmt("/r0 %g def\n", r0); - writePSFmt("/r1 %g def\n", r1); - writePSFmt("/dr %g def\n", r1 - r0); - writePSFmt("/t0 %g def\n", t0); - writePSFmt("/t1 %g def\n", t1); - writePSFmt("/dt %g def\n", t1 - t0); - writePSFmt("/n %d def\n", shading->getColorSpace()->getNComps()); - if (shading->getNFuncs() == 1) { - writePS("/func "); - cvtFunction(shading->getFunc(0)); - writePS("def\n"); - } else { - writePS("/func {\n"); - for (i = 0; i < shading->getNFuncs(); ++i) { - if (i < shading->getNFuncs() - 1) { - writePS("dup\n"); - } - cvtFunction(shading->getFunc(i)); - writePS("exec\n"); - if (i < shading->getNFuncs() - 1) { - writePS("exch\n"); - } - } - writePS("} def\n"); - } - writePSFmt("%g %g 0 radialSH\n", sMin, sMax); -} - -void PSOutputDev::clip(GfxState *state) { - doPath(state->getPath()); - writePS("W\n"); -} - -void PSOutputDev::eoClip(GfxState *state) { - doPath(state->getPath()); - writePS("W*\n"); -} - -void PSOutputDev::doPath(GfxPath *path) { - GfxSubpath *subpath; - double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4; - int n, m, i, j; - - n = path->getNumSubpaths(); - - if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) { - subpath = path->getSubpath(0); - x0 = subpath->getX(0); - y0 = subpath->getY(0); - x4 = subpath->getX(4); - y4 = subpath->getY(4); - if (x4 == x0 && y4 == y0) { - x1 = subpath->getX(1); - y1 = subpath->getY(1); - x2 = subpath->getX(2); - y2 = subpath->getY(2); - x3 = subpath->getX(3); - y3 = subpath->getY(3); - if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) { - writePSFmt("%g %g %g %g re\n", - x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1, - fabs(x2 - x0), fabs(y1 - y0)); - return; - } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) { - writePSFmt("%g %g %g %g re\n", - x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2, - fabs(x1 - x0), fabs(y2 - y0)); - return; - } - } - } - - for (i = 0; i < n; ++i) { - subpath = path->getSubpath(i); - m = subpath->getNumPoints(); - writePSFmt("%g %g m\n", subpath->getX(0), subpath->getY(0)); - j = 1; - while (j < m) { - if (subpath->getCurve(j)) { - writePSFmt("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j), - subpath->getX(j+1), subpath->getY(j+1), - subpath->getX(j+2), subpath->getY(j+2)); - j += 3; - } else { - writePSFmt("%g %g l\n", subpath->getX(j), subpath->getY(j)); - ++j; - } - } - if (subpath->isClosed()) { - writePS("h\n"); - } - } -} - -void PSOutputDev::drawString(GfxState *state, GString *s) { - GfxFont *font; - int wMode; - GString *s2; - double dx, dy, dx2, dy2, originX, originY; - char *p; - UnicodeMap *uMap; - CharCode code; - Unicode u[8]; - char buf[8]; - int len, nChars, uLen, n, m, i, j; - - // check for invisible text -- this is used by Acrobat Capture - if (state->getRender() == 3) { - return; - } - - // ignore empty strings - if (s->getLength() == 0) { - return; - } - - // get the font - if (!(font = state->getFont())) { - return; - } - wMode = font->getWMode(); - - // check for a subtitute 16-bit font - uMap = NULL; - if (font->isCIDFont()) { - for (i = 0; i < font16EncLen; ++i) { - if (font->getID()->num == font16Enc[i].fontID.num && - font->getID()->gen == font16Enc[i].fontID.gen) { - uMap = globalParams->getUnicodeMap(font16Enc[i].enc); - break; - } - } - } - - // compute width of chars in string, ignoring char spacing and word - // spacing -- the Tj operator will adjust for the metrics of the - // font that's actually used - dx = dy = 0; - nChars = 0; - p = s->getCString(); - len = s->getLength(); - if (font->isCIDFont()) { - s2 = new GString(); - } else { - s2 = s; - } - while (len > 0) { - n = font->getNextChar(p, len, &code, - u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, - &dx2, &dy2, &originX, &originY); - if (font->isCIDFont()) { - if (uMap) { - for (i = 0; i < uLen; ++i) { - m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf)); - for (j = 0; j < m; ++j) { - s2->append(buf[j]); - } - } - //~ this really needs to get the number of chars in the target - //~ encoding - which may be more than the number of Unicode - //~ chars - nChars += uLen; - } else { - s2->append((char)((code >> 8) & 0xff)); - s2->append((char)(code & 0xff)); - ++nChars; - } - } - dx += dx2; - dy += dy2; - p += n; - len -= n; - } - dx *= state->getFontSize() * state->getHorizScaling(); - dy *= state->getFontSize(); - if (uMap) { - uMap->decRefCnt(); - } - - if (s2->getLength() > 0) { - writePSString(s2); - if (font->isCIDFont()) { - if (wMode) { - writePSFmt(" %d %g Tj16V\n", nChars, dy); - } else { - writePSFmt(" %d %g Tj16\n", nChars, dx); - } - } else { - writePSFmt(" %g Tj\n", dx); - } - } - if (font->isCIDFont()) { - delete s2; - } - - if (state->getRender() & 4) { - haveTextClip = gTrue; - } -} - -void PSOutputDev::endTextObject(GfxState */*state*/) { - if (haveTextClip) { - writePS("Tclip\n"); - haveTextClip = gFalse; - } -} - -void PSOutputDev::drawImageMask(GfxState */*state*/, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg) { - int len; - - len = height * ((width + 7) / 8); - if (level == psLevel1 || level == psLevel1Sep) { - doImageL1(ref, NULL, invert, inlineImg, str, width, height, len); - } else { - doImageL2(ref, NULL, invert, inlineImg, str, width, height, len, - NULL, NULL, 0, 0, gFalse); - } -} - -void PSOutputDev::drawImage(GfxState */*state*/, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - int *maskColors, GBool inlineImg) { - int len; - - len = height * ((width * colorMap->getNumPixelComps() * - colorMap->getBits() + 7) / 8); - switch (level) { - case psLevel1: - doImageL1(ref, colorMap, gFalse, inlineImg, str, width, height, len); - break; - case psLevel1Sep: - //~ handle indexed, separation, ... color spaces - doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len); - break; - case psLevel2: - case psLevel2Sep: - case psLevel3: - case psLevel3Sep: - doImageL2(ref, colorMap, gFalse, inlineImg, str, - width, height, len, maskColors, NULL, 0, 0, gFalse); - break; - } - t3Cacheable = gFalse; -} - -void PSOutputDev::drawMaskedImage(GfxState */*state*/, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - Stream *maskStr, - int maskWidth, int maskHeight, - GBool maskInvert) { - int len; - - len = height * ((width * colorMap->getNumPixelComps() * - colorMap->getBits() + 7) / 8); - switch (level) { - case psLevel1: - doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len); - break; - case psLevel1Sep: - //~ handle indexed, separation, ... color spaces - doImageL1Sep(colorMap, gFalse, gFalse, str, width, height, len); - break; - case psLevel2: - case psLevel2Sep: - case psLevel3: - case psLevel3Sep: - doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len, - NULL, maskStr, maskWidth, maskHeight, maskInvert); - break; - } - t3Cacheable = gFalse; -} - -void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap, - GBool invert, GBool inlineImg, - Stream *str, int width, int height, int len) { - ImageStream *imgStr; - Guchar pixBuf[gfxColorMaxComps]; - GfxGray gray; - int col, x, y, c, i; - - if (inType3Char && !colorMap) { - if (inlineImg) { - // create an array - str = new FixedLengthEncoder(str, len); - str = new ASCIIHexEncoder(str); - str->reset(); - col = 0; - writePS("[<"); - do { - do { - c = str->getChar(); - } while (c == '\n' || c == '\r'); - if (c == '>' || c == EOF) { - break; - } - writePSChar(c); - ++col; - // each line is: "<...data...>" - // so max data length = 255 - 4 = 251 - // but make it 240 just to be safe - // chunks are 2 bytes each, so we need to stop on an even col number - if (col == 240) { - writePS(">\n<"); - col = 0; - } - } while (c != '>' && c != EOF); - writePS(">]\n"); - writePS("0\n"); - str->close(); - delete str; - } else { - // set up to use the array already created by setupImages() - writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen()); - } - } - - // image/imagemask command - if (inType3Char && !colorMap) { - writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1a\n", - width, height, invert ? "true" : "false", - width, -height, height); - } else if (colorMap) { - writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n", - width, height, - width, -height, height); - } else { - writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n", - width, height, invert ? "true" : "false", - width, -height, height); - } - - // image data - if (!(inType3Char && !colorMap)) { - - if (colorMap) { - - // set up to process the data stream - imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), - colorMap->getBits()); - imgStr->reset(); - - // process the data stream - i = 0; - for (y = 0; y < height; ++y) { - - // write the line - for (x = 0; x < width; ++x) { - imgStr->getPixel(pixBuf); - colorMap->getGray(pixBuf, &gray); - writePSFmt("%02x", colToByte(gray)); - if (++i == 32) { - writePSChar('\n'); - i = 0; - } - } - } - if (i != 0) { - writePSChar('\n'); - } - delete imgStr; - - // imagemask - } else { - str->reset(); - i = 0; - for (y = 0; y < height; ++y) { - for (x = 0; x < width; x += 8) { - writePSFmt("%02x", str->getChar() & 0xff); - if (++i == 32) { - writePSChar('\n'); - i = 0; - } - } - } - if (i != 0) { - writePSChar('\n'); - } - str->close(); - } - } -} - -void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap, - GBool /*invert*/, GBool /*inlineImg*/, - Stream *str, int width, int height, int /*len*/) { - ImageStream *imgStr; - Guchar *lineBuf; - Guchar pixBuf[gfxColorMaxComps]; - GfxCMYK cmyk; - int x, y, i, comp; - - // width, height, matrix, bits per component - writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n", - width, height, - width, -height, height); - - // allocate a line buffer - lineBuf = (Guchar *)gmalloc(4 * width); - - // set up to process the data stream - imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), - colorMap->getBits()); - imgStr->reset(); - - // process the data stream - i = 0; - for (y = 0; y < height; ++y) { - - // read the line - for (x = 0; x < width; ++x) { - imgStr->getPixel(pixBuf); - colorMap->getCMYK(pixBuf, &cmyk); - lineBuf[4*x+0] = colToByte(cmyk.c); - lineBuf[4*x+1] = colToByte(cmyk.m); - lineBuf[4*x+2] = colToByte(cmyk.y); - lineBuf[4*x+3] = colToByte(cmyk.k); - addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), - colToDbl(cmyk.y), colToDbl(cmyk.k)); - } - - // write one line of each color component - for (comp = 0; comp < 4; ++comp) { - for (x = 0; x < width; ++x) { - writePSFmt("%02x", lineBuf[4*x + comp]); - if (++i == 32) { - writePSChar('\n'); - i = 0; - } - } - } - } - - if (i != 0) { - writePSChar('\n'); - } - - delete imgStr; - gfree(lineBuf); -} - -void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, - GBool invert, GBool inlineImg, - Stream *str, int width, int height, int len, - int *maskColors, Stream *maskStr, - int maskWidth, int maskHeight, GBool maskInvert) { - ImageStream *imgStr; - Guchar *line, *pix; - GString *s; - int n, numComps; - GBool useRLE, useASCII, useASCIIHex, useCompressed; - GfxSeparationColorSpace *sepCS; - GfxColor color; - GfxCMYK cmyk; - int c; - int col, i, x, x0, y, y0, maskXor; - - // color key masking - if (maskColors && colorMap && !inlineImg) { - // can't read the stream twice for inline images -- but masking - // isn't allowed with inline images anyway - writePS("[\n"); - numComps = colorMap->getNumPixelComps(); - imgStr = new ImageStream(str, width, numComps, colorMap->getBits()); - imgStr->reset(); - for (y = 0, y0 = 0; y < height; ++y) { - if (!(line = imgStr->getLine())) { - break; - } - for (x = 0, x0 = 0, pix = line; x < width; ++x, pix += numComps) { - for (i = 0; i < numComps; ++i) { - if (pix[i] < maskColors[2*i] || - pix[i] > maskColors[2*i+1]) { - break; - } - } - if (i == numComps) { - if (y0 < y) { - writePSFmt("0 %d %d %d\n", height - y, width, y - y0); - } - if (x0 < x) { - writePSFmt("%d %d %d 1\n", x0, height - y - 1, x - x0); - } - x0 = x + 1; - y0 = y + 1; - } - } - if (x0 > 0 && x0 < width) { - writePSFmt("%d %d %d 1\n", x0, height - y - 1, width - x0); - } - } - if (y0 < height) { - writePSFmt("0 0 %d %d\n", width, height - y0); - } - delete imgStr; - str->close(); - writePSFmt("] %d %d pdfImClip\n", width, height); - - // explicit masking - } else if (maskStr) { - writePS("[\n"); - imgStr = new ImageStream(maskStr, maskWidth, 1, 1); - imgStr->reset(); - maskXor = maskInvert ? 1 : 0; - for (y = 0, y0 = 0; y < maskHeight; ++y) { - if (!(line = imgStr->getLine())) { - break; - } - for (x = 0, x0 = 0, pix = line; x < maskWidth; ++x, ++pix) { - if (*pix ^ maskXor) { - if (y0 < y) { - writePSFmt("0 %d %d %d\n", maskHeight - y, maskWidth, y - y0); - } - if (x0 < x) { - writePSFmt("%d %d %d 1\n", x0, maskHeight - y - 1, x - x0); - } - x0 = x + 1; - y0 = y + 1; - } - } - if (x0 > 0 && x0 < maskWidth) { - writePSFmt("%d %d %d 1\n", x0, maskHeight - y - 1, maskWidth - x0); - } - } - if (y0 < maskHeight) { - writePSFmt("0 0 %d %d\n", maskWidth, maskHeight - y0); - } - delete imgStr; - maskStr->close(); - writePSFmt("] %d %d pdfImClip\n", maskWidth, maskHeight); - } - - // color space - if (colorMap) { - dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue); - writePS(" setcolorspace\n"); - } - - useASCIIHex = globalParams->getPSASCIIHex(); - - // set up the image data - if (mode == psModeForm || inType3Char) { - if (inlineImg) { - // create an array - str = new FixedLengthEncoder(str, len); - if (useASCIIHex) { - str = new ASCIIHexEncoder(str); - } else { - str = new ASCII85Encoder(str); - } - str->reset(); - col = 0; - writePS((char *)(useASCIIHex ? "[<" : "[<~")); - do { - do { - c = str->getChar(); - } while (c == '\n' || c == '\r'); - if (c == (useASCIIHex ? '>' : '~') || c == EOF) { - break; - } - if (c == 'z') { - writePSChar(c); - ++col; - } else { - writePSChar(c); - ++col; - for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { - do { - c = str->getChar(); - } while (c == '\n' || c == '\r'); - if (c == (useASCIIHex ? '>' : '~') || c == EOF) { - break; - } - writePSChar(c); - ++col; - } - } - // each line is: "<~...data...~>" - // so max data length = 255 - 6 = 249 - // chunks are 1 or 5 bytes each, so we have to stop at 245 - // but make it 240 just to be safe - if (col > 240) { - writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~")); - col = 0; - } - } while (c != (useASCIIHex ? '>' : '~') && c != EOF); - writePS((char *)(useASCIIHex ? ">]\n" : "~>]\n")); - writePS("0\n"); - str->close(); - delete str; - } else { - // set up to use the array already created by setupImages() - writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen()); - } - } - - // image dictionary - writePS("<<\n /ImageType 1\n"); - - // width, height, matrix, bits per component - writePSFmt(" /Width %d\n", width); - writePSFmt(" /Height %d\n", height); - writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height); - if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { - writePSFmt(" /BitsPerComponent 8\n"); - } else { - writePSFmt(" /BitsPerComponent %d\n", - colorMap ? colorMap->getBits() : 1); - } - - // decode - if (colorMap) { - writePS(" /Decode ["); - if ((level == psLevel2Sep || level == psLevel3Sep) && - colorMap->getColorSpace()->getMode() == csSeparation) { - // this matches up with the code in the pdfImSep operator - n = (1 << colorMap->getBits()) - 1; - writePSFmt("%g %g", colorMap->getDecodeLow(0) * n, - colorMap->getDecodeHigh(0) * n); - } else if (colorMap->getColorSpace()->getMode() == csDeviceN) { - numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> - getAlt()->getNComps(); - for (i = 0; i < numComps; ++i) { - if (i > 0) { - writePS(" "); - } - writePS("0 1"); - } - } else { - numComps = colorMap->getNumPixelComps(); - for (i = 0; i < numComps; ++i) { - if (i > 0) { - writePS(" "); - } - writePSFmt("%g %g", colorMap->getDecodeLow(i), - colorMap->getDecodeHigh(i)); - } - } - writePS("]\n"); - } else { - writePSFmt(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1); - } - - if (mode == psModeForm || inType3Char) { - - // data source - writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); - - // end of image dictionary - writePSFmt(">>\n%s\n", colorMap ? "image" : "imagemask"); - - // get rid of the array and index - writePS("pop pop\n"); - - } else { - - // data source - writePS(" /DataSource currentfile\n"); - s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, - " "); - if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || - inlineImg || !s) { - useRLE = gTrue; - useASCII = gTrue; - useCompressed = gFalse; - } else { - useRLE = gFalse; - useASCII = str->isBinary(); - useCompressed = gTrue; - } - if (useASCII) { - writePSFmt(" /ASCII%sDecode filter\n", - useASCIIHex ? "Hex" : "85"); - } - if (useRLE) { - writePS(" /RunLengthDecode filter\n"); - } - if (useCompressed) { - writePS(s->getCString()); - } - if (s) { - delete s; - } - - // cut off inline image streams at appropriate length - if (inlineImg) { - str = new FixedLengthEncoder(str, len); - } else if (useCompressed) { - str = str->getBaseStream(); - } - - // recode DeviceN data - if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { - str = new DeviceNRecoder(str, width, height, colorMap); - } - - // add RunLengthEncode and ASCIIHex/85 encode filters - if (useRLE) { - str = new RunLengthEncoder(str); - } - if (useASCII) { - if (useASCIIHex) { - str = new ASCIIHexEncoder(str); - } else { - str = new ASCII85Encoder(str); - } - } - - // end of image dictionary - writePS(">>\n"); -#if OPI_SUPPORT - if (opi13Nest) { - if (inlineImg) { - // this can't happen -- OPI dictionaries are in XObjects - error(-1, "Internal: OPI in inline image"); - n = 0; - } else { - // need to read the stream to count characters -- the length - // is data-dependent (because of ASCII and RLE filters) - str->reset(); - n = 0; - while ((c = str->getChar()) != EOF) { - ++n; - } - str->close(); - } - // +6/7 for "pdfIm\n" / "pdfImM\n" - // +8 for newline + trailer - n += colorMap ? 14 : 15; - writePSFmt("%%%%BeginData: %d Hex Bytes\n", n); - } -#endif - if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && - colorMap->getColorSpace()->getMode() == csSeparation) { - color.c[0] = gfxColorComp1; - sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); - sepCS->getCMYK(&color, &cmyk); - writePSFmt("%g %g %g %g (%s) pdfImSep\n", - colToDbl(cmyk.c), colToDbl(cmyk.m), - colToDbl(cmyk.y), colToDbl(cmyk.k), - sepCS->getName()->getCString()); - } else { - writePSFmt("%s\n", colorMap ? "pdfIm" : "pdfImM"); - } - - // copy the stream data - str->reset(); - while ((c = str->getChar()) != EOF) { - writePSChar(c); - } - str->close(); - - // add newline and trailer to the end - writePSChar('\n'); - writePS("%-EOD-\n"); -#if OPI_SUPPORT - if (opi13Nest) { - writePS("%%EndData\n"); - } -#endif - - // delete encoders - if (useRLE || useASCII || inlineImg) { - delete str; - } - } - - if ((maskColors && colorMap && !inlineImg) || maskStr) { - writePS("pdfImClipEnd\n"); - } -} - -void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace, - GBool genXform, GBool updateColors) { - GfxCalGrayColorSpace *calGrayCS; - GfxCalRGBColorSpace *calRGBCS; - GfxLabColorSpace *labCS; - GfxIndexedColorSpace *indexedCS; - GfxSeparationColorSpace *separationCS; - GfxDeviceNColorSpace *deviceNCS; - GfxColorSpace *baseCS; - Guchar *lookup, *p; - double x[gfxColorMaxComps], y[gfxColorMaxComps]; - GfxColor color; - GfxCMYK cmyk; - Function *func; - int n, numComps, numAltComps; - int byte; - int i, j, k; - - switch (colorSpace->getMode()) { - - case csDeviceGray: - writePS("/DeviceGray"); - if (genXform) { - writePS(" {}"); - } - if (updateColors) { - processColors |= psProcessBlack; - } - break; - - case csCalGray: - calGrayCS = (GfxCalGrayColorSpace *)colorSpace; - writePS("[/CIEBasedA <<\n"); - writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma()); - writePSFmt(" /MatrixA [%g %g %g]\n", - calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), - calGrayCS->getWhiteZ()); - writePSFmt(" /WhitePoint [%g %g %g]\n", - calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), - calGrayCS->getWhiteZ()); - writePSFmt(" /BlackPoint [%g %g %g]\n", - calGrayCS->getBlackX(), calGrayCS->getBlackY(), - calGrayCS->getBlackZ()); - writePS(">>]"); - if (genXform) { - writePS(" {}"); - } - if (updateColors) { - processColors |= psProcessBlack; - } - break; - - case csDeviceRGB: - writePS("/DeviceRGB"); - if (genXform) { - writePS(" {}"); - } - if (updateColors) { - processColors |= psProcessCMYK; - } - break; - - case csCalRGB: - calRGBCS = (GfxCalRGBColorSpace *)colorSpace; - writePS("[/CIEBasedABC <<\n"); - writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n", - calRGBCS->getGammaR(), calRGBCS->getGammaG(), - calRGBCS->getGammaB()); - writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n", - calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1], - calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3], - calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5], - calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7], - calRGBCS->getMatrix()[8]); - writePSFmt(" /WhitePoint [%g %g %g]\n", - calRGBCS->getWhiteX(), calRGBCS->getWhiteY(), - calRGBCS->getWhiteZ()); - writePSFmt(" /BlackPoint [%g %g %g]\n", - calRGBCS->getBlackX(), calRGBCS->getBlackY(), - calRGBCS->getBlackZ()); - writePS(">>]"); - if (genXform) { - writePS(" {}"); - } - if (updateColors) { - processColors |= psProcessCMYK; - } - break; - - case csDeviceCMYK: - writePS("/DeviceCMYK"); - if (genXform) { - writePS(" {}"); - } - if (updateColors) { - processColors |= psProcessCMYK; - } - break; - - case csLab: - labCS = (GfxLabColorSpace *)colorSpace; - writePS("[/CIEBasedABC <<\n"); - writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n", - labCS->getAMin(), labCS->getAMax(), - labCS->getBMin(), labCS->getBMax()); - writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n"); - writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n"); - writePS(" /DecodeLMN\n"); - writePS(" [{dup 6 29 div ge {dup dup mul mul}\n"); - writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n", - labCS->getWhiteX()); - writePS(" {dup 6 29 div ge {dup dup mul mul}\n"); - writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n", - labCS->getWhiteY()); - writePS(" {dup 6 29 div ge {dup dup mul mul}\n"); - writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n", - labCS->getWhiteZ()); - writePSFmt(" /WhitePoint [%g %g %g]\n", - labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ()); - writePSFmt(" /BlackPoint [%g %g %g]\n", - labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ()); - writePS(">>]"); - if (genXform) { - writePS(" {}"); - } - if (updateColors) { - processColors |= psProcessCMYK; - } - break; - - case csICCBased: - // there is no transform function to the alternate color space, so - // we can use it directly - dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(), - genXform, updateColors); - break; - - case csIndexed: - indexedCS = (GfxIndexedColorSpace *)colorSpace; - baseCS = indexedCS->getBase(); - writePS("[/Indexed "); - dumpColorSpaceL2(baseCS, gFalse, gFalse); - n = indexedCS->getIndexHigh(); - numComps = baseCS->getNComps(); - lookup = indexedCS->getLookup(); - writePSFmt(" %d <\n", n); - if (baseCS->getMode() == csDeviceN) { - func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc(); - numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps(); - p = lookup; - for (i = 0; i <= n; i += 8) { - writePS(" "); - for (j = i; j < i+8 && j <= n; ++j) { - for (k = 0; k < numComps; ++k) { - x[k] = *p++ / 255.0; - } - func->transform(x, y); - for (k = 0; k < numAltComps; ++k) { - byte = (int)(y[k] * 255 + 0.5); - if (byte < 0) { - byte = 0; - } else if (byte > 255) { - byte = 255; - } - writePSFmt("%02x", byte); - } - if (updateColors) { - color.c[0] = dblToCol(j); - indexedCS->getCMYK(&color, &cmyk); - addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), - colToDbl(cmyk.y), colToDbl(cmyk.k)); - } - } - writePS("\n"); - } - } else { - for (i = 0; i <= n; i += 8) { - writePS(" "); - for (j = i; j < i+8 && j <= n; ++j) { - for (k = 0; k < numComps; ++k) { - writePSFmt("%02x", lookup[j * numComps + k]); - } - if (updateColors) { - color.c[0] = dblToCol(j); - indexedCS->getCMYK(&color, &cmyk); - addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), - colToDbl(cmyk.y), colToDbl(cmyk.k)); - } - } - writePS("\n"); - } - } - writePS(">]"); - if (genXform) { - writePS(" {}"); - } - break; - - case csSeparation: - separationCS = (GfxSeparationColorSpace *)colorSpace; - writePS("[/Separation /"); - writePSName(separationCS->getName()->getCString()); - writePS(" "); - dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse); - writePS("\n"); - cvtFunction(separationCS->getFunc()); - writePS("]"); - if (genXform) { - writePS(" {}"); - } - if (updateColors) { - addCustomColor(separationCS); - } - break; - - case csDeviceN: - // DeviceN color spaces are a Level 3 PostScript feature. - deviceNCS = (GfxDeviceNColorSpace *)colorSpace; - dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors); - if (genXform) { - writePS(" "); - cvtFunction(deviceNCS->getTintTransformFunc()); - } - break; - - case csPattern: - //~ unimplemented - break; - } -} - -#if OPI_SUPPORT -void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) { - Object dict; - - if (globalParams->getPSOPI()) { - opiDict->lookup("2.0", &dict); - if (dict.isDict()) { - opiBegin20(state, dict.getDict()); - dict.free(); - } else { - dict.free(); - opiDict->lookup("1.3", &dict); - if (dict.isDict()) { - opiBegin13(state, dict.getDict()); - } - dict.free(); - } - } -} - -void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) { - Object obj1, obj2, obj3, obj4; - double width, height, left, right, top, bottom; - int w, h; - int i; - - writePS("%%BeginOPI: 2.0\n"); - writePS("%%Distilled\n"); - - dict->lookup("F", &obj1); - if (getFileSpec(&obj1, &obj2)) { - writePSFmt("%%%%ImageFileName: %s\n", - obj2.getString()->getCString()); - obj2.free(); - } - obj1.free(); - - dict->lookup("MainImage", &obj1); - if (obj1.isString()) { - writePSFmt("%%%%MainImage: %s\n", obj1.getString()->getCString()); - } - obj1.free(); - - //~ ignoring 'Tags' entry - //~ need to use writePSString() and deal with >255-char lines - - dict->lookup("Size", &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 2) { - obj1.arrayGet(0, &obj2); - width = obj2.getNum(); - obj2.free(); - obj1.arrayGet(1, &obj2); - height = obj2.getNum(); - obj2.free(); - writePSFmt("%%%%ImageDimensions: %g %g\n", width, height); - } - obj1.free(); - - dict->lookup("CropRect", &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 4) { - obj1.arrayGet(0, &obj2); - left = obj2.getNum(); - obj2.free(); - obj1.arrayGet(1, &obj2); - top = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2, &obj2); - right = obj2.getNum(); - obj2.free(); - obj1.arrayGet(3, &obj2); - bottom = obj2.getNum(); - obj2.free(); - writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom); - } - obj1.free(); - - dict->lookup("Overprint", &obj1); - if (obj1.isBool()) { - writePSFmt("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false"); - } - obj1.free(); - - dict->lookup("Inks", &obj1); - if (obj1.isName()) { - writePSFmt("%%%%ImageInks: %s\n", obj1.getName()); - } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) { - obj1.arrayGet(0, &obj2); - if (obj2.isName()) { - writePSFmt("%%%%ImageInks: %s %d", - obj2.getName(), (obj1.arrayGetLength() - 1) / 2); - for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) { - obj1.arrayGet(i, &obj3); - obj1.arrayGet(i+1, &obj4); - if (obj3.isString() && obj4.isNum()) { - writePS(" "); - writePSString(obj3.getString()); - writePSFmt(" %g", obj4.getNum()); - } - obj3.free(); - obj4.free(); - } - writePS("\n"); - } - obj2.free(); - } - obj1.free(); - - writePS("gsave\n"); - - writePS("%%BeginIncludedImage\n"); - - dict->lookup("IncludedImageDimensions", &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 2) { - obj1.arrayGet(0, &obj2); - w = obj2.getInt(); - obj2.free(); - obj1.arrayGet(1, &obj2); - h = obj2.getInt(); - obj2.free(); - writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w, h); - } - obj1.free(); - - dict->lookup("IncludedImageQuality", &obj1); - if (obj1.isNum()) { - writePSFmt("%%%%IncludedImageQuality: %g\n", obj1.getNum()); - } - obj1.free(); - - ++opi20Nest; -} - -void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { - Object obj1, obj2; - int left, right, top, bottom, samples, bits, width, height; - double c, m, y, k; - double llx, lly, ulx, uly, urx, ury, lrx, lry; - double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry; - double horiz, vert; - int i, j; - - writePS("save\n"); - writePS("/opiMatrix2 matrix currentmatrix def\n"); - writePS("opiMatrix setmatrix\n"); - - dict->lookup("F", &obj1); - if (getFileSpec(&obj1, &obj2)) { - writePSFmt("%%ALDImageFileName: %s\n", - obj2.getString()->getCString()); - obj2.free(); - } - obj1.free(); - - dict->lookup("CropRect", &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 4) { - obj1.arrayGet(0, &obj2); - left = obj2.getInt(); - obj2.free(); - obj1.arrayGet(1, &obj2); - top = obj2.getInt(); - obj2.free(); - obj1.arrayGet(2, &obj2); - right = obj2.getInt(); - obj2.free(); - obj1.arrayGet(3, &obj2); - bottom = obj2.getInt(); - obj2.free(); - writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom); - } - obj1.free(); - - dict->lookup("Color", &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 5) { - obj1.arrayGet(0, &obj2); - c = obj2.getNum(); - obj2.free(); - obj1.arrayGet(1, &obj2); - m = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2, &obj2); - y = obj2.getNum(); - obj2.free(); - obj1.arrayGet(3, &obj2); - k = obj2.getNum(); - obj2.free(); - obj1.arrayGet(4, &obj2); - if (obj2.isString()) { - writePSFmt("%%ALDImageColor: %g %g %g %g ", c, m, y, k); - writePSString(obj2.getString()); - writePS("\n"); - } - obj2.free(); - } - obj1.free(); - - dict->lookup("ColorType", &obj1); - if (obj1.isName()) { - writePSFmt("%%ALDImageColorType: %s\n", obj1.getName()); - } - obj1.free(); - - //~ ignores 'Comments' entry - //~ need to handle multiple lines - - dict->lookup("CropFixed", &obj1); - if (obj1.isArray()) { - obj1.arrayGet(0, &obj2); - ulx = obj2.getNum(); - obj2.free(); - obj1.arrayGet(1, &obj2); - uly = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2, &obj2); - lrx = obj2.getNum(); - obj2.free(); - obj1.arrayGet(3, &obj2); - lry = obj2.getNum(); - obj2.free(); - writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry); - } - obj1.free(); - - dict->lookup("GrayMap", &obj1); - if (obj1.isArray()) { - writePS("%ALDImageGrayMap:"); - for (i = 0; i < obj1.arrayGetLength(); i += 16) { - if (i > 0) { - writePS("\n%%+"); - } - for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) { - obj1.arrayGet(i+j, &obj2); - writePSFmt(" %d", obj2.getInt()); - obj2.free(); - } - } - writePS("\n"); - } - obj1.free(); - - dict->lookup("ID", &obj1); - if (obj1.isString()) { - writePSFmt("%%ALDImageID: %s\n", obj1.getString()->getCString()); - } - obj1.free(); - - dict->lookup("ImageType", &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 2) { - obj1.arrayGet(0, &obj2); - samples = obj2.getInt(); - obj2.free(); - obj1.arrayGet(1, &obj2); - bits = obj2.getInt(); - obj2.free(); - writePSFmt("%%ALDImageType: %d %d\n", samples, bits); - } - obj1.free(); - - dict->lookup("Overprint", &obj1); - if (obj1.isBool()) { - writePSFmt("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false"); - } - obj1.free(); - - dict->lookup("Position", &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 8) { - obj1.arrayGet(0, &obj2); - llx = obj2.getNum(); - obj2.free(); - obj1.arrayGet(1, &obj2); - lly = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2, &obj2); - ulx = obj2.getNum(); - obj2.free(); - obj1.arrayGet(3, &obj2); - uly = obj2.getNum(); - obj2.free(); - obj1.arrayGet(4, &obj2); - urx = obj2.getNum(); - obj2.free(); - obj1.arrayGet(5, &obj2); - ury = obj2.getNum(); - obj2.free(); - obj1.arrayGet(6, &obj2); - lrx = obj2.getNum(); - obj2.free(); - obj1.arrayGet(7, &obj2); - lry = obj2.getNum(); - obj2.free(); - opiTransform(state, llx, lly, &tllx, &tlly); - opiTransform(state, ulx, uly, &tulx, &tuly); - opiTransform(state, urx, ury, &turx, &tury); - opiTransform(state, lrx, lry, &tlrx, &tlry); - writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n", - tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry); - obj2.free(); - } - obj1.free(); - - dict->lookup("Resolution", &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 2) { - obj1.arrayGet(0, &obj2); - horiz = obj2.getNum(); - obj2.free(); - obj1.arrayGet(1, &obj2); - vert = obj2.getNum(); - obj2.free(); - writePSFmt("%%ALDImageResoution: %g %g\n", horiz, vert); - obj2.free(); - } - obj1.free(); - - dict->lookup("Size", &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 2) { - obj1.arrayGet(0, &obj2); - width = obj2.getInt(); - obj2.free(); - obj1.arrayGet(1, &obj2); - height = obj2.getInt(); - obj2.free(); - writePSFmt("%%ALDImageDimensions: %d %d\n", width, height); - } - obj1.free(); - - //~ ignoring 'Tags' entry - //~ need to use writePSString() and deal with >255-char lines - - dict->lookup("Tint", &obj1); - if (obj1.isNum()) { - writePSFmt("%%ALDImageTint: %g\n", obj1.getNum()); - } - obj1.free(); - - dict->lookup("Transparency", &obj1); - if (obj1.isBool()) { - writePSFmt("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false"); - } - obj1.free(); - - writePS("%%BeginObject: image\n"); - writePS("opiMatrix2 setmatrix\n"); - ++opi13Nest; -} - -// Convert PDF user space coordinates to PostScript default user space -// coordinates. This has to account for both the PDF CTM and the -// PSOutputDev page-fitting transform. -void PSOutputDev::opiTransform(GfxState *state, double x0, double y0, - double *x1, double *y1) { - double t; - - state->transform(x0, y0, x1, y1); - *x1 += tx; - *y1 += ty; - if (rotate == 90) { - t = *x1; - *x1 = -*y1; - *y1 = t; - } else if (rotate == 180) { - *x1 = -*x1; - *y1 = -*y1; - } else if (rotate == 270) { - t = *x1; - *x1 = *y1; - *y1 = -t; - } - *x1 *= xScale; - *y1 *= yScale; -} - -void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) { - Object dict; - - if (globalParams->getPSOPI()) { - opiDict->lookup("2.0", &dict); - if (dict.isDict()) { - writePS("%%EndIncludedImage\n"); - writePS("%%EndOPI\n"); - writePS("grestore\n"); - --opi20Nest; - dict.free(); - } else { - dict.free(); - opiDict->lookup("1.3", &dict); - if (dict.isDict()) { - writePS("%%EndObject\n"); - writePS("restore\n"); - --opi13Nest; - } - dict.free(); - } - } -} - -GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) { - if (fileSpec->isString()) { - fileSpec->copy(fileName); - return gTrue; - } - if (fileSpec->isDict()) { - fileSpec->dictLookup("DOS", fileName); - if (fileName->isString()) { - return gTrue; - } - fileName->free(); - fileSpec->dictLookup("Mac", fileName); - if (fileName->isString()) { - return gTrue; - } - fileName->free(); - fileSpec->dictLookup("Unix", fileName); - if (fileName->isString()) { - return gTrue; - } - fileName->free(); - fileSpec->dictLookup("F", fileName); - if (fileName->isString()) { - return gTrue; - } - fileName->free(); - } - return gFalse; -} -#endif // OPI_SUPPORT - -void PSOutputDev::type3D0(GfxState */*state*/, double wx, double wy) { - writePSFmt("%g %g setcharwidth\n", wx, wy); - writePS("q\n"); -} - -void PSOutputDev::type3D1(GfxState */*state*/, double wx, double wy, - double llx, double lly, double urx, double ury) { - t3WX = wx; - t3WY = wy; - t3LLX = llx; - t3LLY = lly; - t3URX = urx; - t3URY = ury; - t3String = new GString(); - writePS("q\n"); - t3Cacheable = gTrue; -} - -void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) { - Stream *str; - int c; - - if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) { - str = level1Stream; - } else { - str = psStream; - } - str->reset(); - while ((c = str->getChar()) != EOF) { - writePSChar(c); - } - str->close(); -} - -//~ can nextFunc be reset to 0 -- maybe at the start of each page? -//~ or maybe at the start of each color space / pattern? -void PSOutputDev::cvtFunction(Function *func) { - SampledFunction *func0; - ExponentialFunction *func2; - StitchingFunction *func3; - PostScriptFunction *func4; - int thisFunc, m, n, nSamples, i, j, k; - - switch (func->getType()) { - - case -1: // identity - writePS("{}\n"); - break; - - case 0: // sampled - func0 = (SampledFunction *)func; - thisFunc = nextFunc++; - m = func0->getInputSize(); - n = func0->getOutputSize(); - nSamples = n; - for (i = 0; i < m; ++i) { - nSamples *= func0->getSampleSize(i); - } - writePSFmt("/xpdfSamples%d [\n", thisFunc); - for (i = 0; i < nSamples; ++i) { - writePSFmt("%g\n", func0->getSamples()[i]); - } - writePS("] def\n"); - writePSFmt("{ %d array %d array %d 2 roll\n", 2*m, m, m+2); - // [e01] [efrac] x0 x1 ... xm-1 - for (i = m-1; i >= 0; --i) { - // [e01] [efrac] x0 x1 ... xi - writePSFmt("%g sub %g mul %g add\n", - func0->getDomainMin(i), - (func0->getEncodeMax(i) - func0->getEncodeMin(i)) / - (func0->getDomainMax(i) - func0->getDomainMin(i)), - func0->getEncodeMin(i)); - // [e01] [efrac] x0 x1 ... xi-1 xi' - writePSFmt("dup 0 lt { pop 0 } { dup %d gt { pop %d } if } ifelse\n", - func0->getSampleSize(i) - 1, func0->getSampleSize(i) - 1); - // [e01] [efrac] x0 x1 ... xi-1 xi' - writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n"); - // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi') - writePSFmt("%d index %d 3 2 roll put\n", i+3, i); - // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') - writePSFmt("%d index %d 3 2 roll put\n", i+3, 2*i+1); - // [e01] [efrac] x0 x1 ... xi-1 floor(xi') - writePSFmt("%d index %d 3 2 roll put\n", i+2, 2*i); - // [e01] [efrac] x0 x1 ... xi-1 - } - // [e01] [efrac] - for (i = 0; i < n; ++i) { - // [e01] [efrac] y(0) ... y(i-1) - for (j = 0; j < (1<> k) & 1)); - for (k = m - 2; k >= 0; --k) { - writePSFmt("%d mul %d index %d get add\n", - func0->getSampleSize(k), - i + j + 3, - 2 * k + ((j >> k) & 1)); - } - if (n > 1) { - writePSFmt("%d mul %d add ", n, i); - } - writePS("get\n"); - } - // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1) - for (j = 0; j < m; ++j) { - // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1) - for (k = 0; k < (1 << (m - j)); k += 2) { - // [e01] [efrac] y(0) ... y(i-1) <2^(m-j)-k s values> - writePSFmt("%d index %d get dup\n", i + k/2 + (1 << (m-j)) - k, j); - writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n"); - writePSFmt("%d 1 roll\n", k/2 + (1 << m-j) - k - 1); - } - // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1) - } - // [e01] [efrac] y(0) ... y(i-1) s - writePSFmt("%g mul %g add\n", - func0->getDecodeMax(i) - func0->getDecodeMin(i), - func0->getDecodeMin(i)); - writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", - func0->getRangeMin(i), func0->getRangeMin(i), - func0->getRangeMax(i), func0->getRangeMax(i)); - // [e01] [efrac] y(0) ... y(i-1) y(i) - } - // [e01] [efrac] y(0) ... y(n-1) - writePSFmt("%d %d roll pop pop }\n", n+2, n); - break; - - case 2: // exponential - func2 = (ExponentialFunction *)func; - n = func2->getOutputSize(); - writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", - func2->getDomainMin(0), func2->getDomainMin(0), - func2->getDomainMax(0), func2->getDomainMax(0)); - // x - for (i = 0; i < n; ++i) { - // x y(0) .. y(i-1) - writePSFmt("%d index %g exp %g mul %g add\n", - i, func2->getE(), func2->getC1()[i] - func2->getC0()[i], - func2->getC0()[i]); - if (func2->getHasRange()) { - writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", - func2->getRangeMin(i), func2->getRangeMin(i), - func2->getRangeMax(i), func2->getRangeMax(i)); - } - } - // x y(0) .. y(n-1) - writePSFmt("%d %d roll pop }\n", n+1, n); - break; - - case 3: // stitching - func3 = (StitchingFunction *)func; - thisFunc = nextFunc++; - for (i = 0; i < func3->getNumFuncs(); ++i) { - cvtFunction(func3->getFunc(i)); - writePSFmt("/xpdfFunc%d_%d exch def\n", thisFunc, i); - } - writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", - func3->getDomainMin(0), func3->getDomainMin(0), - func3->getDomainMax(0), func3->getDomainMax(0)); - for (i = 0; i < func3->getNumFuncs() - 1; ++i) { - writePSFmt("dup %g lt { %g sub %g mul %g add xpdfFunc%d_%d } {\n", - func3->getBounds()[i+1], - func3->getBounds()[i], - (func3->getEncode()[2*i+1] - func3->getEncode()[2*i]) / - (func3->getBounds()[i+1] - func3->getBounds()[i]), - func3->getEncode()[2*i], - thisFunc, i); - } - writePSFmt("%g sub %g mul %g add xpdfFunc%d_%d\n", - func3->getBounds()[i], - (func3->getEncode()[2*i+1] - func3->getEncode()[2*i]) / - (func3->getBounds()[i+1] - func3->getBounds()[i]), - func3->getEncode()[2*i], - thisFunc, i); - for (i = 0; i < func3->getNumFuncs() - 1; ++i) { - writePS("} ifelse\n"); - } - writePS("}\n"); - break; - - case 4: // PostScript - func4 = (PostScriptFunction *)func; - writePS(func4->getCodeString()->getCString()); - writePS("\n"); - break; - } -} - -void PSOutputDev::writePSChar(char c) { - if (t3String) { - t3String->append(c); - } else { - (*outputFunc)(outputStream, &c, 1); - } -} - -void PSOutputDev::writePS(const char *s) { - if (t3String) { - t3String->append(s); - } else { - (*outputFunc)(outputStream, s, strlen(s)); - } -} - -void PSOutputDev::writePSFmt(const char *fmt, ...) { - va_list args; - char buf[512]; - - va_start(args, fmt); - vsprintf(buf, fmt, args); - va_end(args); - if (t3String) { - t3String->append(buf); - } else { - (*outputFunc)(outputStream, buf, strlen(buf)); - } -} - -void PSOutputDev::writePSString(GString *s) { - Guchar *p; - int n, line; - char buf[8]; - - writePSChar('('); - line = 1; - for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) { - if (line >= 64) { - writePSChar('\\'); - writePSChar('\n'); - line = 0; - } - if (*p == '(' || *p == ')' || *p == '\\') { - writePSChar('\\'); - writePSChar((char)*p); - line += 2; - } else if (*p < 0x20 || *p >= 0x80) { - sprintf(buf, "\\%03o", *p); - writePS(buf); - line += 4; - } else { - writePSChar((char)*p); - ++line; - } - } - writePSChar(')'); -} - -void PSOutputDev::writePSName(const char *s) { - const char *p; - char c; - - p = s; - while ((c = *p++)) { - if (c <= (char)0x20 || c >= (char)0x7f || - c == '(' || c == ')' || c == '<' || c == '>' || - c == '[' || c == ']' || c == '{' || c == '}' || - c == '/' || c == '%') { - writePSFmt("#%02x", c & 0xff); - } else { - writePSChar(c); - } - } -} - -GString *PSOutputDev::filterPSName(GString *name) { - GString *name2; - char buf[8]; - int i; - char c; - - name2 = new GString(); - - // ghostscript chokes on names that begin with out-of-limits - // numbers, e.g., 1e4foo is handled correctly (as a name), but - // 1e999foo generates a limitcheck error - c = name->getChar(0); - if (c >= '0' && c <= '9') { - name2->append('f'); - } - - for (i = 0; i < name->getLength(); ++i) { - c = name->getChar(i); - if (c <= (char)0x20 || c >= (char)0x7f || - c == '(' || c == ')' || c == '<' || c == '>' || - c == '[' || c == ']' || c == '{' || c == '}' || - c == '/' || c == '%') { - sprintf(buf, "#%02x", c & 0xff); - name2->append(buf); - } else { - name2->append(c); - } - } - return name2; -} diff --git a/xpdf/xpdf/PSOutputDev.h b/xpdf/xpdf/PSOutputDev.h deleted file mode 100644 index d2f3b5518..000000000 --- a/xpdf/xpdf/PSOutputDev.h +++ /dev/null @@ -1,353 +0,0 @@ -//======================================================================== -// -// PSOutputDev.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef PSOUTPUTDEV_H -#define PSOUTPUTDEV_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include "config.h" -#include "Object.h" -#include "GlobalParams.h" -#include "OutputDev.h" - -class Function; -class GfxPath; -class GfxFont; -class GfxColorSpace; -class GfxSeparationColorSpace; -class PDFRectangle; -struct PSFont16Enc; -class PSOutCustomColor; - -//------------------------------------------------------------------------ -// PSOutputDev -//------------------------------------------------------------------------ - -enum PSOutMode { - psModePS, - psModeEPS, - psModeForm -}; - -enum PSFileType { - psFile, // write to file - psPipe, // write to pipe - psStdout, // write to stdout - psGeneric // write to a generic stream -}; - -typedef void (*PSOutputFunc)(void *stream, const char *data, int len); - -class PSOutputDev: public OutputDev { -public: - - // Open a PostScript output file, and write the prolog. - PSOutputDev(const char *fileName, XRef *xrefA, Catalog *catalog, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA = 0, int imgLLYA = 0, - int imgURXA = 0, int imgURYA = 0, - GBool manualCtrlA = gFalse); - - // Open a PSOutputDev that will write to a generic stream. - PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, - XRef *xrefA, Catalog *catalog, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA = 0, int imgLLYA = 0, - int imgURXA = 0, int imgURYA = 0, - GBool manualCtrlA = gFalse); - - // Destructor -- writes the trailer and closes the file. - virtual ~PSOutputDev(); - - // Check if file was successfully created. - virtual GBool isOk() { return ok; } - - //---- get info about output device - - // Does this device use upside-down coordinates? - // (Upside-down means (0,0) is the top left corner of the page.) - virtual GBool upsideDown() { return gFalse; } - - // Does this device use drawChar() or drawString()? - virtual GBool useDrawChar() { return gFalse; } - - // Does this device use tilingPatternFill()? If this returns false, - // tiling pattern fills will be reduced to a series of other drawing - // operations. - virtual GBool useTilingPatternFill() { return gTrue; } - - // Does this device use functionShadedFill(), axialShadedFill(), and - // radialShadedFill()? If this returns false, these shaded fills - // will be reduced to a series of other drawing operations. - virtual GBool useShadedFills() - { return level == psLevel2 || level == psLevel3; } - - // Does this device use beginType3Char/endType3Char? Otherwise, - // text in Type 3 fonts will be drawn with drawChar/drawString. - virtual GBool interpretType3Chars() { return gFalse; } - - //----- header/trailer (used only if manualCtrl is true) - - // Write the document-level header. - void writeHeader(int firstPage, int lastPage, - PDFRectangle *mediaBox, PDFRectangle *cropBox, - int pageRotate); - - // Write the Xpdf procset. - void writeXpdfProcset(); - - // Write the document-level setup. - void writeDocSetup(Catalog *catalog, int firstPage, int lastPage); - - // Write the trailer for the current page. - void writePageTrailer(); - - // Write the document trailer. - void writeTrailer(); - - //----- initialization and control - - // Start a page. - virtual void startPage(int pageNum, GfxState *state); - - // End a page. - virtual void endPage(); - - //----- save/restore graphics state - virtual void saveState(GfxState *state); - virtual void restoreState(GfxState *state); - - //----- update graphics state - virtual void updateCTM(GfxState *state, double m11, double m12, - double m21, double m22, double m31, double m32); - virtual void updateLineDash(GfxState *state); - virtual void updateFlatness(GfxState *state); - virtual void updateLineJoin(GfxState *state); - virtual void updateLineCap(GfxState *state); - virtual void updateMiterLimit(GfxState *state); - virtual void updateLineWidth(GfxState *state); - virtual void updateFillColorSpace(GfxState *state); - virtual void updateStrokeColorSpace(GfxState *state); - virtual void updateFillColor(GfxState *state); - virtual void updateStrokeColor(GfxState *state); - virtual void updateFillOverprint(GfxState *state); - virtual void updateStrokeOverprint(GfxState *state); - - //----- update text state - virtual void updateFont(GfxState *state); - virtual void updateTextMat(GfxState *state); - virtual void updateCharSpace(GfxState *state); - virtual void updateRender(GfxState *state); - virtual void updateRise(GfxState *state); - virtual void updateWordSpace(GfxState *state); - virtual void updateHorizScaling(GfxState *state); - virtual void updateTextPos(GfxState *state); - virtual void updateTextShift(GfxState *state, double shift); - - //----- path painting - virtual void stroke(GfxState *state); - virtual void fill(GfxState *state); - virtual void eoFill(GfxState *state); - virtual void tilingPatternFill(GfxState *state, Object *str, - int paintType, Dict *resDict, - double *mat, double *bbox, - int x0, int y0, int x1, int y1, - double xStep, double yStep); - virtual void functionShadedFill(GfxState *state, - GfxFunctionShading *shading); - virtual void axialShadedFill(GfxState *state, GfxAxialShading *shading); - virtual void radialShadedFill(GfxState *state, GfxRadialShading *shading); - - //----- path clipping - virtual void clip(GfxState *state); - virtual void eoClip(GfxState *state); - - //----- text drawing - virtual void drawString(GfxState *state, GString *s); - virtual void endTextObject(GfxState *state); - - //----- image drawing - virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg); - virtual void drawImage(GfxState *state, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - int *maskColors, GBool inlineImg); - virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - Stream *maskStr, int maskWidth, int maskHeight, - GBool maskInvert); - -#if OPI_SUPPORT - //----- OPI functions - virtual void opiBegin(GfxState *state, Dict *opiDict); - virtual void opiEnd(GfxState *state, Dict *opiDict); -#endif - - //----- Type 3 font operators - virtual void type3D0(GfxState *state, double wx, double wy); - virtual void type3D1(GfxState *state, double wx, double wy, - double llx, double lly, double urx, double ury); - - //----- PostScript XObjects - virtual void psXObject(Stream *psStream, Stream *level1Stream); - - //----- miscellaneous - void setOffset(double x, double y) - { tx0 = x; ty0 = y; } - void setScale(double x, double y) - { xScale0 = x; yScale0 = y; } - void setRotate(int rotateA) - { rotate0 = rotateA; } - void setClip(double llx, double lly, double urx, double ury) - { clipLLX0 = llx; clipLLY0 = lly; clipURX0 = urx; clipURY0 = ury; } - void setUnderlayCbk(void (*cbk)(PSOutputDev *psOut, void *data), - void *data) - { underlayCbk = cbk; underlayCbkData = data; } - void setOverlayCbk(void (*cbk)(PSOutputDev *psOut, void *data), - void *data) - { overlayCbk = cbk; overlayCbkData = data; } - -private: - - void init(PSOutputFunc outputFuncA, void *outputStreamA, - PSFileType fileTypeA, XRef *xrefA, Catalog *catalog, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, - GBool manualCtrlA); - void setupResources(Dict *resDict); - void setupFonts(Dict *resDict); - void setupFont(GfxFont *font, Dict *parentResDict); - void setupEmbeddedType1Font(Ref *id, GString *psName); - void setupExternalType1Font(GString *fileName, GString *psName); - void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName); - void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName); - GString *setupExternalTrueTypeFont(GfxFont *font); - void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName); - void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName, - GBool needsVerticalMetrics); - GString *setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, int faceIndex=0); - void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict); - void setupImages(Dict *resDict); - void setupImage(Ref id, Stream *str); - void addProcessColor(double c, double m, double y, double k); - void addCustomColor(GfxSeparationColorSpace *sepCS); - void doPath(GfxPath *path); - void doImageL1(Object *ref, GfxImageColorMap *colorMap, - GBool invert, GBool inlineImg, - Stream *str, int width, int height, int len); - void doImageL1Sep(GfxImageColorMap *colorMap, - GBool invert, GBool inlineImg, - Stream *str, int width, int height, int len); - void doImageL2(Object *ref, GfxImageColorMap *colorMap, - GBool invert, GBool inlineImg, - Stream *str, int width, int height, int len, - int *maskColors, Stream *maskStr, - int maskWidth, int maskHeight, GBool maskInvert); - void dumpColorSpaceL2(GfxColorSpace *colorSpace, - GBool genXform, GBool updateColors); -#if OPI_SUPPORT - void opiBegin20(GfxState *state, Dict *dict); - void opiBegin13(GfxState *state, Dict *dict); - void opiTransform(GfxState *state, double x0, double y0, - double *x1, double *y1); - GBool getFileSpec(Object *fileSpec, Object *fileName); -#endif - void cvtFunction(Function *func); - void writePSChar(char c); - void writePS(const char *s); - void writePSFmt(const char *fmt, ...); - void writePSString(GString *s); - void writePSName(const char *s); - GString *filterPSName(GString *name); - - PSLevel level; // PostScript level (1, 2, separation) - PSOutMode mode; // PostScript mode (PS, EPS, form) - int paperWidth; // width of paper, in pts - int paperHeight; // height of paper, in pts - int imgLLX, imgLLY, // imageable area, in pts - imgURX, imgURY; - - PSOutputFunc outputFunc; - void *outputStream; - PSFileType fileType; // file / pipe / stdout - GBool manualCtrl; - int seqPage; // current sequential page number - void (*underlayCbk)(PSOutputDev *psOut, void *data); - void *underlayCbkData; - void (*overlayCbk)(PSOutputDev *psOut, void *data); - void *overlayCbkData; - - XRef *xref; // the xref table for this PDF file - - Ref *fontIDs; // list of object IDs of all used fonts - int fontIDLen; // number of entries in fontIDs array - int fontIDSize; // size of fontIDs array - Ref *fontFileIDs; // list of object IDs of all embedded fonts - int fontFileIDLen; // number of entries in fontFileIDs array - int fontFileIDSize; // size of fontFileIDs array - GString **fontFileNames; // list of names of all embedded external fonts - GString **psFileNames; // list of names of all embedded external ps names - int fontFileNameLen; // number of entries in fontFileNames array - int fontFileNameSize; // size of fontFileNames array - int nextTrueTypeNum; // next unique number to append to a TrueType - // font name - PSFont16Enc *font16Enc; // encodings for substitute 16-bit fonts - int font16EncLen; // number of entries in font16Enc array - int font16EncSize; // size of font16Enc array - GList *xobjStack; // stack of XObject dicts currently being - // processed - int numSaves; // current number of gsaves - int numTilingPatterns; // current number of nested tiling patterns - int nextFunc; // next unique number to use for a function - - double tx0, ty0; // global translation - double xScale0, yScale0; // global scaling - int rotate0; // rotation angle (0, 90, 180, 270) - double clipLLX0, clipLLY0, - clipURX0, clipURY0; - double tx, ty; // global translation for current page - double xScale, yScale; // global scaling for current page - int rotate; // rotation angle for current page - double epsX1, epsY1, // EPS bounding box (unrotated) - epsX2, epsY2; - - GString *embFontList; // resource comments for embedded fonts - - int processColors; // used process colors - PSOutCustomColor // used custom colors - *customColors; - - GBool haveTextClip; // set if text has been drawn with a - // clipping render mode - - GBool inType3Char; // inside a Type 3 CharProc - GString *t3String; // Type 3 content string - double t3WX, t3WY, // Type 3 character parameters - t3LLX, t3LLY, t3URX, t3URY; - GBool t3Cacheable; // cleared if char is not cacheable - -#if OPI_SUPPORT - int opi13Nest; // nesting level of OPI 1.3 objects - int opi20Nest; // nesting level of OPI 2.0 objects -#endif - - GBool ok; // set up ok? - - - friend class WinPDFPrinter; -}; - -#endif diff --git a/xpdf/xpdf/PSTokenizer.cc b/xpdf/xpdf/PSTokenizer.cc deleted file mode 100644 index 8a6938527..000000000 --- a/xpdf/xpdf/PSTokenizer.cc +++ /dev/null @@ -1,135 +0,0 @@ -//======================================================================== -// -// PSTokenizer.cc -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "PSTokenizer.h" - -//------------------------------------------------------------------------ - -// A '1' in this array means the character is white space. A '1' or -// '2' means the character ends a name or command. -static char PSTokenizer_specialChars[256] = { - 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x - 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx -}; - -//------------------------------------------------------------------------ - -PSTokenizer::PSTokenizer(int (*getCharFuncA)(void *), void *dataA) { - getCharFunc = getCharFuncA; - data = dataA; - charBuf = -1; -} - -PSTokenizer::~PSTokenizer() { -} - -GBool PSTokenizer::getToken(char *buf, int size, int *length) { - GBool comment, backslash; - int c; - int i; - - // skip whitespace and comments - comment = gFalse; - while (1) { - if ((c = getChar()) == EOF) { - buf[0] = '\0'; - *length = 0; - return gFalse; - } - if (comment) { - if (c == '\x0a' || c == '\x0d') { - comment = gFalse; - } - } else if (c == '%') { - comment = gTrue; - } else if (PSTokenizer_specialChars[c] != 1) { - break; - } - } - - // read a token - i = 0; - buf[i++] = c; - if (c == '(') { - backslash = gFalse; - while ((c = lookChar()) != EOF) { - if (i < size - 1) { - buf[i++] = c; - } - getChar(); - if (c == '\\') { - backslash = gTrue; - } else if (!backslash && c == ')') { - break; - } else { - backslash = gFalse; - } - } - } else if (c == '<') { - while ((c = lookChar()) != EOF) { - getChar(); - if (i < size - 1) { - buf[i++] = c; - } - if (c == '>') { - break; - } - } - } else if (c != '[' && c != ']') { - while ((c = lookChar()) != EOF && !PSTokenizer_specialChars[c]) { - getChar(); - if (i < size - 1) { - buf[i++] = c; - } - } - } - buf[i] = '\0'; - *length = i; - - return gTrue; -} - -int PSTokenizer::lookChar() { - if (charBuf < 0) { - charBuf = (*getCharFunc)(data); - } - return charBuf; -} - -int PSTokenizer::getChar() { - int c; - - if (charBuf < 0) { - charBuf = (*getCharFunc)(data); - } - c = charBuf; - charBuf = -1; - return c; -} diff --git a/xpdf/xpdf/PSTokenizer.h b/xpdf/xpdf/PSTokenizer.h deleted file mode 100644 index 4d5ee97f4..000000000 --- a/xpdf/xpdf/PSTokenizer.h +++ /dev/null @@ -1,41 +0,0 @@ -//======================================================================== -// -// PSTokenizer.h -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef PSTOKENIZER_H -#define PSTOKENIZER_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" - -//------------------------------------------------------------------------ - -class PSTokenizer { -public: - - PSTokenizer(int (*getCharFuncA)(void *), void *dataA); - ~PSTokenizer(); - - // Get the next PostScript token. Returns false at end-of-stream. - GBool getToken(char *buf, int size, int *length); - -private: - - int lookChar(); - int getChar(); - - int (*getCharFunc)(void *); - void *data; - int charBuf; -}; - -#endif diff --git a/xpdf/xpdf/Page.cc b/xpdf/xpdf/Page.cc deleted file mode 100644 index 0d7ce873c..000000000 --- a/xpdf/xpdf/Page.cc +++ /dev/null @@ -1,485 +0,0 @@ -//======================================================================== -// -// Page.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "GlobalParams.h" -#include "Object.h" -#include "Array.h" -#include "Dict.h" -#include "XRef.h" -#include "Link.h" -#include "OutputDev.h" -#ifndef PDF_PARSER_ONLY -#include "Gfx.h" -#include "GfxState.h" -#include "Annot.h" -#endif -#include "Error.h" -#include "UGString.h" -#include "Page.h" - -//------------------------------------------------------------------------ -// PageAttrs -//------------------------------------------------------------------------ - -PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { - Object obj1; - - // get old/default values - if (attrs) { - mediaBox = attrs->mediaBox; - cropBox = attrs->cropBox; - haveCropBox = attrs->haveCropBox; - rotate = attrs->rotate; - attrs->resources.copy(&resources); - } else { - // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary - // but some (non-compliant) PDF files don't specify a MediaBox - mediaBox.x1 = 0; - mediaBox.y1 = 0; - mediaBox.x2 = 612; - mediaBox.y2 = 792; - cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0; - haveCropBox = gFalse; - rotate = 0; - resources.initNull(); - } - - // media box - readBox(dict, "MediaBox", &mediaBox); - - // crop box - if (readBox(dict, "CropBox", &cropBox)) { - haveCropBox = gTrue; - } - if (!haveCropBox) { - cropBox = mediaBox; - } - else - { - // cropBox can not be bigger than mediaBox - if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1) - { - cropBox.x1 = mediaBox.x1; - cropBox.x2 = mediaBox.x2; - } - if (cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1) - { - cropBox.y1 = mediaBox.y1; - cropBox.y2 = mediaBox.y2; - } - } - - // other boxes - bleedBox = cropBox; - readBox(dict, "BleedBox", &bleedBox); - trimBox = cropBox; - readBox(dict, "TrimBox", &trimBox); - artBox = cropBox; - readBox(dict, "ArtBox", &artBox); - - // rotate - dict->lookup("Rotate", &obj1); - if (obj1.isInt()) { - rotate = obj1.getInt(); - } - obj1.free(); - while (rotate < 0) { - rotate += 360; - } - while (rotate >= 360) { - rotate -= 360; - } - - // misc attributes - dict->lookup("LastModified", &lastModified); - dict->lookup("BoxColorInfo", &boxColorInfo); - dict->lookup("Group", &group); - dict->lookup("Metadata", &metadata); - dict->lookup("PieceInfo", &pieceInfo); - dict->lookup("SeparationInfo", &separationInfo); - - // resource dictionary - dict->lookup("Resources", &obj1); - if (obj1.isDict()) { - resources.free(); - obj1.copy(&resources); - } - obj1.free(); -} - -PageAttrs::~PageAttrs() { - lastModified.free(); - boxColorInfo.free(); - group.free(); - metadata.free(); - pieceInfo.free(); - separationInfo.free(); - resources.free(); -} - -GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) { - PDFRectangle tmp; - double t; - Object obj1, obj2; - GBool ok; - - dict->lookup(key, &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 4) { - ok = gTrue; - obj1.arrayGet(0, &obj2); - if (obj2.isNum()) { - tmp.x1 = obj2.getNum(); - } else { - ok = gFalse; - } - obj2.free(); - obj1.arrayGet(1, &obj2); - if (obj2.isNum()) { - tmp.y1 = obj2.getNum(); - } else { - ok = gFalse; - } - obj2.free(); - obj1.arrayGet(2, &obj2); - if (obj2.isNum()) { - tmp.x2 = obj2.getNum(); - } else { - ok = gFalse; - } - obj2.free(); - obj1.arrayGet(3, &obj2); - if (obj2.isNum()) { - tmp.y2 = obj2.getNum(); - } else { - ok = gFalse; - } - obj2.free(); - if (ok) { - if (tmp.x1 > tmp.x2) { - t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t; - } - if (tmp.y1 > tmp.y2) { - t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t; - } - *box = tmp; - } - } else { - ok = gFalse; - } - obj1.free(); - return ok; -} - -//------------------------------------------------------------------------ -// PageTransition -//------------------------------------------------------------------------ - -PageTransition::PageTransition(Dict *dict) - : type(Replace), - duration(1), - alignment(Horizontal), - direction(Inward), - angle(0), - scale(1.0), - rectangular(false) -{ - Object dictObj; - Object obj; - - dict->lookup("Trans", &dictObj); - if (dictObj.isDict()) { - Dict *transDict = dictObj.getDict(); - - if (transDict->lookup("S", &obj)->isName()) { - const char *s = obj.getName(); - if (strcmp("R", s) == 0) - type = Replace; - else if (strcmp("Split", s) == 0) - type = Split; - else if (strcmp("Blinds", s) == 0) - type = Blinds; - else if (strcmp("Box", s) == 0) - type = Box; - else if (strcmp("Wipe", s) == 0) - type = Wipe; - else if (strcmp("Dissolve", s) == 0) - type = Dissolve; - else if (strcmp("Glitter", s) == 0) - type = Glitter; - else if (strcmp("Fly", s) == 0) - type = Fly; - else if (strcmp("Push", s) == 0) - type = Push; - else if (strcmp("Cover", s) == 0) - type = Cover; - else if (strcmp("Uncover", s) == 0) - type = Push; - else if (strcmp("Fade", s) == 0) - type = Cover; - } - obj.free(); - - if (transDict->lookup("D", &obj)->isInt()) { - duration = obj.getInt(); - } - obj.free(); - - if (transDict->lookup("Dm", &obj)->isName()) { - const char *dm = obj.getName(); - if ( strcmp( "H", dm ) == 0 ) - alignment = Horizontal; - else if ( strcmp( "V", dm ) == 0 ) - alignment = Vertical; - } - obj.free(); - - if (transDict->lookup("M", &obj)->isName()) { - const char *m = obj.getName(); - if ( strcmp( "I", m ) == 0 ) - direction = Inward; - else if ( strcmp( "O", m ) == 0 ) - direction = Outward; - } - obj.free(); - - if (transDict->lookup("Di", &obj)->isInt()) { - angle = obj.getInt(); - } - obj.free(); - - if (transDict->lookup("Di", &obj)->isName()) { - if ( strcmp( "None", obj.getName() ) == 0 ) - angle = 0; - } - obj.free(); - - if (transDict->lookup("SS", &obj)->isReal()) { - scale = obj.getReal(); - } - obj.free(); - - if (transDict->lookup("B", &obj)->isBool()) { - rectangular = obj.getBool(); - } - obj.free(); - } - dictObj.free(); -} - -PageTransition::~PageTransition() { -} - -//------------------------------------------------------------------------ -// Page -//------------------------------------------------------------------------ - -Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA) { - ok = gTrue; - xref = xrefA; - num = numA; - - // get attributes - attrs = attrsA; - - // get transition - transition = new PageTransition( pageDict ); - - // annotations - pageDict->lookupNF("Annots", &annots); - if (!(annots.isRef() || annots.isArray() || annots.isNull())) { - error(-1, "Page annotations object (page %d) is wrong type (%s)", - num, annots.getTypeName()); - annots.free(); - goto err2; - } - - // contents - pageDict->lookupNF("Contents", &contents); - if (!(contents.isRef() || contents.isArray() || - contents.isNull())) { - error(-1, "Page contents object (page %d) is wrong type (%s)", - num, contents.getTypeName()); - contents.free(); - goto err1; - } - - return; - - err2: - annots.initNull(); - err1: - contents.initNull(); - ok = gFalse; -} - -Page::~Page() { - delete attrs; - delete transition; - annots.free(); - contents.free(); -} - -void Page::display(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool useMediaBox, GBool crop, - Links *links, Catalog *catalog, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { - displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, - -1, -1, -1, -1, links, catalog, - abortCheckCbk, abortCheckCbkData); -} - -void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool useMediaBox, GBool crop, - int sliceX, int sliceY, int sliceW, int sliceH, - Links *links, Catalog *catalog, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { -#ifndef PDF_PARSER_ONLY - PDFRectangle *mediaBox, *cropBox, *baseBox; - PDFRectangle box; - Gfx *gfx; - Object obj; - Link *link; - Annots *annotList; - double kx, ky; - int i; - - rotate += getRotate(); - if (rotate >= 360) { - rotate -= 360; - } else if (rotate < 0) { - rotate += 360; - } - - mediaBox = getMediaBox(); - cropBox = getCropBox(); - if (sliceW >= 0 && sliceH >= 0) { - baseBox = useMediaBox ? mediaBox : cropBox; - kx = 72.0 / hDPI; - ky = 72.0 / vDPI; - if (rotate == 90) { - if (out->upsideDown()) { - box.x1 = baseBox->x1 + ky * sliceY; - box.x2 = baseBox->x1 + ky * (sliceY + sliceH); - } else { - box.x1 = baseBox->x2 - ky * (sliceY + sliceH); - box.x2 = baseBox->x2 - ky * sliceY; - } - box.y1 = baseBox->y1 + kx * sliceX; - box.y2 = baseBox->y1 + kx * (sliceX + sliceW); - } else if (rotate == 180) { - box.x1 = baseBox->x2 - kx * (sliceX + sliceW); - box.x2 = baseBox->x2 - kx * sliceX; - if (out->upsideDown()) { - box.y1 = baseBox->y1 + ky * sliceY; - box.y2 = baseBox->y1 + ky * (sliceY + sliceH); - } else { - box.y1 = baseBox->y2 - ky * (sliceY + sliceH); - box.y2 = baseBox->y2 - ky * sliceY; - } - } else if (rotate == 270) { - if (out->upsideDown()) { - box.x1 = baseBox->x2 - ky * (sliceY + sliceH); - box.x2 = baseBox->x2 - ky * sliceY; - } else { - box.x1 = baseBox->x1 + ky * sliceY; - box.x2 = baseBox->x1 + ky * (sliceY + sliceH); - } - box.y1 = baseBox->y2 - kx * (sliceX + sliceW); - box.y2 = baseBox->y2 - kx * sliceX; - } else { - box.x1 = baseBox->x1 + kx * sliceX; - box.x2 = baseBox->x1 + kx * (sliceX + sliceW); - if (out->upsideDown()) { - box.y1 = baseBox->y2 - ky * (sliceY + sliceH); - box.y2 = baseBox->y2 - ky * sliceY; - } else { - box.y1 = baseBox->y1 + ky * sliceY; - box.y2 = baseBox->y1 + ky * (sliceY + sliceH); - } - } - } else if (useMediaBox) { - box = *mediaBox; - } else { - box = *cropBox; - crop = gFalse; - } - - if (globalParams->getPrintCommands()) { - printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", - mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2); - printf("***** CropBox = ll:%g,%g ur:%g,%g\n", - cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); - printf("***** Rotate = %d\n", attrs->getRotate()); - } - - gfx = new Gfx(xref, out, num, attrs->getResourceDict(), - hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL, - rotate, abortCheckCbk, abortCheckCbkData); - contents.fetch(xref, &obj); - if (!obj.isNull()) { - gfx->saveState(); - gfx->display(&obj); - gfx->restoreState(); - } - obj.free(); - - // draw links - if (links) { - gfx->saveState(); - for (i = 0; i < links->getNumLinks(); ++i) { - link = links->getLink(i); - out->drawLink(link, catalog); - } - gfx->restoreState(); - out->dump(); - } - - // draw non-link annotations - annotList = new Annots(xref, catalog, annots.fetch(xref, &obj)); - obj.free(); - if (annotList->getNumAnnots() > 0) { - if (globalParams->getPrintCommands()) { - printf("***** Annotations\n"); - } - for (i = 0; i < annotList->getNumAnnots(); ++i) { - annotList->getAnnot(i)->draw(gfx); - } - out->dump(); - } - delete annotList; - - delete gfx; -#endif -} - -void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI, - int rotate, GBool upsideDown) { - GfxState *state; - int i; - - rotate += getRotate(); - if (rotate >= 360) { - rotate -= 360; - } else if (rotate < 0) { - rotate += 360; - } - state = new GfxState(hDPI, vDPI, getMediaBox(), rotate, upsideDown); - for (i = 0; i < 6; ++i) { - ctm[i] = state->getCTM()[i]; - } - delete state; -} diff --git a/xpdf/xpdf/Page.h b/xpdf/xpdf/Page.h deleted file mode 100644 index 8dcb8ef1a..000000000 --- a/xpdf/xpdf/Page.h +++ /dev/null @@ -1,247 +0,0 @@ -//======================================================================== -// -// Page.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef PAGE_H -#define PAGE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" - -class Dict; -class XRef; -class OutputDev; -class Links; -class Catalog; - -//------------------------------------------------------------------------ - -class PDFRectangle { -public: - double x1, y1, x2, y2; - - PDFRectangle() { x1 = y1 = x2 = y2 = 0; } - PDFRectangle(double x1A, double y1A, double x2A, double y2A) - { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; } - GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; } -}; - -//------------------------------------------------------------------------ -// PageAttrs -//------------------------------------------------------------------------ - -class PageAttrs { -public: - - // Construct a new PageAttrs object by merging a dictionary - // (of type Pages or Page) into another PageAttrs object. If - // is NULL, uses defaults. - PageAttrs(PageAttrs *attrs, Dict *dict); - - // Destructor. - ~PageAttrs(); - - // Accessors. - PDFRectangle *getMediaBox() { return &mediaBox; } - PDFRectangle *getCropBox() { return &cropBox; } - GBool isCropped() { return haveCropBox; } - PDFRectangle *getBleedBox() { return &bleedBox; } - PDFRectangle *getTrimBox() { return &trimBox; } - PDFRectangle *getArtBox() { return &artBox; } - int getRotate() { return rotate; } - GString *getLastModified() - { return lastModified.isString() - ? lastModified.getString() : (GString *)NULL; } - Dict *getBoxColorInfo() - { return boxColorInfo.isDict() ? boxColorInfo.getDict() : (Dict *)NULL; } - Dict *getGroup() - { return group.isDict() ? group.getDict() : (Dict *)NULL; } - Stream *getMetadata() - { return metadata.isStream() ? metadata.getStream() : (Stream *)NULL; } - Dict *getPieceInfo() - { return pieceInfo.isDict() ? pieceInfo.getDict() : (Dict *)NULL; } - Dict *getSeparationInfo() - { return separationInfo.isDict() - ? separationInfo.getDict() : (Dict *)NULL; } - Dict *getResourceDict() - { return resources.isDict() ? resources.getDict() : (Dict *)NULL; } - -private: - - GBool readBox(Dict *dict, const char *key, PDFRectangle *box); - - PDFRectangle mediaBox; - PDFRectangle cropBox; - GBool haveCropBox; - PDFRectangle bleedBox; - PDFRectangle trimBox; - PDFRectangle artBox; - int rotate; - Object lastModified; - Object boxColorInfo; - Object group; - Object metadata; - Object pieceInfo; - Object separationInfo; - Object resources; -}; - -//------------------------------------------------------------------------ -// PageTransition -//------------------------------------------------------------------------ -class PageTransition { -public: - enum Type { - Replace, - Split, - Blinds, - Box, - Wipe, - Dissolve, - Glitter, - Fly, - Push, - Cover, - Uncover, - Fade - }; - - enum Alignment { - Horizontal, - Vertical - }; - - enum Direction { - Inward, - Outward - }; - - // Construct a new PageTransition object from a page dictionary. - PageTransition( Dict *dict ); - - // Destructor - ~PageTransition(); - - // Get type of the transition. - Type getType() const { return type; } - - // Get duration of the transition in seconds. - int getDuration() const { return duration; } - - // Get dimension in which the transition effect - // occurs. - Alignment getAlignment() const { return alignment; } - - // Get direction of motion of the transition effect. - Direction getDirection() const { return direction; } - - // Get direction in which the transition effect moves. - int getAngle() const { return angle; } - - // Get starting or ending scale. - double getScale() const { return scale; } - - // Returns true if the area to be flown is rectangular and - // opaque. - GBool isRectangular() const { return rectangular; } -private: - Type type; - int duration; - Alignment alignment; - Direction direction; - int angle; - double scale; - GBool rectangular; -}; - -//------------------------------------------------------------------------ -// Page -//------------------------------------------------------------------------ - -class Page { -public: - - // Constructor. - Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA); - - // Destructor. - ~Page(); - - // Is page valid? - GBool isOk() { return ok; } - - // Get page parameters. - PDFRectangle *getMediaBox() { return attrs->getMediaBox(); } - PDFRectangle *getCropBox() { return attrs->getCropBox(); } - GBool isCropped() { return attrs->isCropped(); } - double getMediaWidth() - { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; } - double getMediaHeight() - { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; } - double getCropWidth() - { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; } - double getCropHeight() - { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; } - PDFRectangle *getBleedBox() { return attrs->getBleedBox(); } - PDFRectangle *getTrimBox() { return attrs->getTrimBox(); } - PDFRectangle *getArtBox() { return attrs->getArtBox(); } - int getRotate() { return attrs->getRotate(); } - GString *getLastModified() { return attrs->getLastModified(); } - Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); } - Dict *getGroup() { return attrs->getGroup(); } - Stream *getMetadata() { return attrs->getMetadata(); } - Dict *getPieceInfo() { return attrs->getPieceInfo(); } - Dict *getSeparationInfo() { return attrs->getSeparationInfo(); } - - // Get resource dictionary. - Dict *getResourceDict() { return attrs->getResourceDict(); } - - // Get annotations array. - Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); } - - // Get contents. - Object *getContents(Object *obj) { return contents.fetch(xref, obj); } - - // Get transition information. - PageTransition *getTransition() const { return transition; } - - // Display a page. - void display(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool useMediaBox, GBool crop, - Links *links, Catalog *catalog, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - - // Display part of a page. - void displaySlice(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool useMediaBox, GBool crop, - int sliceX, int sliceY, int sliceW, int sliceH, - Links *links, Catalog *catalog, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - - // Get the page's default CTM. - void getDefaultCTM(double *ctm, double hDPI, double vDPI, - int rotate, GBool upsideDown); - -private: - - XRef *xref; // the xref table for this PDF file - int num; // page number - PageAttrs *attrs; // page attributes - PageTransition *transition; // page transition - Object annots; // annotations array - Object contents; // page contents - GBool ok; // true if page is valid -}; - -#endif diff --git a/xpdf/xpdf/Parser.cc b/xpdf/xpdf/Parser.cc deleted file mode 100644 index d6732fcd6..000000000 --- a/xpdf/xpdf/Parser.cc +++ /dev/null @@ -1,217 +0,0 @@ -//======================================================================== -// -// Parser.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "Object.h" -#include "Array.h" -#include "Dict.h" -#include "Parser.h" -#include "XRef.h" -#include "Error.h" -#include "Decrypt.h" -#include "UGString.h" - -Parser::Parser(XRef *xrefA, Lexer *lexerA) { - xref = xrefA; - lexer = lexerA; - inlineImg = 0; - lexer->getObj(&buf1); - lexer->getObj(&buf2); -} - -Parser::~Parser() { - buf1.free(); - buf2.free(); - delete lexer; -} - -Object *Parser::getObj(Object *obj, - Guchar *fileKey, int keyLength, - int objNum, int objGen) { - const char *key; - Stream *str; - Object obj2; - int num; - Decrypt *decrypt; - GString *s; - char *p; - int i; - - // refill buffer after inline image data - if (inlineImg == 2) { - buf1.free(); - buf2.free(); - lexer->getObj(&buf1); - lexer->getObj(&buf2); - inlineImg = 0; - } - - // array - if (buf1.isCmd("[")) { - shift(); - obj->initArray(xref); - while (!buf1.isCmd("]") && !buf1.isEOF()) - obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen)); - if (buf1.isEOF()) - error(getPos(), "End of file inside array"); - shift(); - - // dictionary or stream - } else if (buf1.isCmd("<<")) { - shift(objNum); - obj->initDict(xref); - while (!buf1.isCmd(">>") && !buf1.isEOF()) { - if (!buf1.isName()) { - error(getPos(), "Dictionary key must be a name object"); - shift(); - } else { - // this copyString is necessary if not the shift changes the value of key - key = copyString(buf1.getName()); - shift(); - if (buf1.isEOF() || buf1.isError()) { - gfree((void*)key); - break; - } - obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); - gfree((void*)key); - } - } - if (buf1.isEOF()) - error(getPos(), "End of file inside dictionary"); - if (buf2.isCmd("stream")) { - if ((str = makeStream(obj))) { - obj->initStream(str); - if (fileKey) { - str->getBaseStream()->doDecryption(fileKey, keyLength, - objNum, objGen); - } - } else { - obj->free(); - obj->initError(); - } - } else { - shift(); - } - - // indirect reference or integer - } else if (buf1.isInt()) { - num = buf1.getInt(); - shift(); - if (buf1.isInt() && buf2.isCmd("R")) { - obj->initRef(num, buf1.getInt()); - shift(); - shift(); - } else { - obj->initInt(num); - } - - // string - } else if (buf1.isString() && fileKey) { - buf1.copy(obj); - s = obj->getString(); - decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); - for (i = 0, p = obj->getString()->getCString(); - i < s->getLength(); - ++i, ++p) { - *p = decrypt->decryptByte(*p); - } - delete decrypt; - shift(); - - // simple object - } else { - buf1.copy(obj); - shift(); - } - - return obj; -} - -Stream *Parser::makeStream(Object *dict) { - Object obj; - BaseStream *baseStr; - Stream *str; - Guint pos, endPos, length; - - // get stream start position - lexer->skipToNextLine(); - pos = lexer->getPos(); - - // get length - dict->dictLookup("Length", &obj); - if (obj.isInt()) { - length = (Guint)obj.getInt(); - obj.free(); - } else { - error(getPos(), "Bad 'Length' attribute in stream"); - obj.free(); - return NULL; - } - - // check for length in damaged file - if (xref && xref->getStreamEnd(pos, &endPos)) { - length = endPos - pos; - } - - // in badly damaged PDF files, we can run off the end of the input - // stream immediately after the "stream" token - if (!lexer->getStream()) { - return NULL; - } - baseStr = lexer->getStream()->getBaseStream(); - - // skip over stream data - lexer->setPos(pos + length); - - // refill token buffers and check for 'endstream' - shift(); // kill '>>' - shift(); // kill 'stream' - if (buf1.isCmd("endstream")) { - shift(); - } else { - error(getPos(), "Missing 'endstream'"); - // kludge for broken PDF files: just add 5k to the length, and - // hope its enough - length += 5000; - } - - // make base stream - str = baseStr->makeSubStream(pos, gTrue, length, dict); - - // get filters - str = str->addFilters(dict); - - return str; -} - -void Parser::shift(int objNum) { - if (inlineImg > 0) { - if (inlineImg < 2) { - ++inlineImg; - } else { - // in a damaged content stream, if 'ID' shows up in the middle - // of a dictionary, we need to reset - inlineImg = 0; - } - } else if (buf2.isCmd("ID")) { - lexer->skipChar(); // skip char after 'ID' command - inlineImg = 1; - } - buf1.free(); - buf1 = buf2; - if (inlineImg > 0) // don't buffer inline image data - buf2.initNull(); - else - lexer->getObj(&buf2, objNum); -} diff --git a/xpdf/xpdf/Parser.h b/xpdf/xpdf/Parser.h deleted file mode 100644 index fd23a0a35..000000000 --- a/xpdf/xpdf/Parser.h +++ /dev/null @@ -1,56 +0,0 @@ -//======================================================================== -// -// Parser.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef PARSER_H -#define PARSER_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Lexer.h" - -//------------------------------------------------------------------------ -// Parser -//------------------------------------------------------------------------ - -class Parser { -public: - - // Constructor. - Parser(XRef *xrefA, Lexer *lexerA); - - // Destructor. - ~Parser(); - - // Get the next object from the input stream. - Object *getObj(Object *obj, - Guchar *fileKey = NULL, int keyLength = 0, - int objNum = 0, int objGen = 0); - - // Get stream. - Stream *getStream() { return lexer->getStream(); } - - // Get current position in file. - int getPos() { return lexer->getPos(); } - -private: - - XRef *xref; // the xref table for this PDF file - Lexer *lexer; // input stream - Object buf1, buf2; // next two tokens - int inlineImg; // set when inline image data is encountered - - Stream *makeStream(Object *dict); - void shift(int objNum = -1); -}; - -#endif - diff --git a/xpdf/xpdf/SecurityHandler.cc b/xpdf/xpdf/SecurityHandler.cc deleted file mode 100644 index 31bd86718..000000000 --- a/xpdf/xpdf/SecurityHandler.cc +++ /dev/null @@ -1,377 +0,0 @@ -//======================================================================== -// -// SecurityHandler.cc -// -// Copyright 2004 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "GString.h" -#include "PDFDoc.h" -#include "Decrypt.h" -#include "Error.h" -#include "GlobalParams.h" -#if HAVE_XPDFCORE -# include "XPDFCore.h" -#elif HAVE_WINPDFCORE -# include "WinPDFCore.h" -#endif -#ifdef ENABLE_PLUGINS -# include "XpdfPluginAPI.h" -#endif -#include "UGString.h" -#include "SecurityHandler.h" - -//------------------------------------------------------------------------ -// SecurityHandler -//------------------------------------------------------------------------ - -SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) { - Object filterObj; - SecurityHandler *secHdlr; - XpdfSecurityHandler *xsh; - - encryptDictA->dictLookup("Filter", &filterObj); - if (filterObj.isName("Standard")) { - secHdlr = new StandardSecurityHandler(docA, encryptDictA); - } else if (filterObj.isName()) { -#ifdef ENABLE_PLUGINS - if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) { - secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh); - } else { -#endif - error(-1, "Couldn't find the '%s' security handler", - filterObj.getName()); - secHdlr = NULL; -#ifdef ENABLE_PLUGINS - } -#endif - } else { - error(-1, "Missing or invalid 'Filter' entry in encryption dictionary"); - secHdlr = NULL; - } - filterObj.free(); - return secHdlr; -} - -SecurityHandler::SecurityHandler(PDFDoc *docA) { - doc = docA; -} - -SecurityHandler::~SecurityHandler() { -} - -GBool SecurityHandler::checkEncryption(GString *ownerPassword, - GString *userPassword) { - void *authData; - GBool ok; - int i; - - if (ownerPassword || userPassword) { - authData = makeAuthData(ownerPassword, userPassword); - } else { - authData = NULL; - } - ok = authorize(authData); - if (authData) { - freeAuthData(authData); - } - for (i = 0; !ok && i < 3; ++i) { - if (!(authData = getAuthData())) { - break; - } - ok = authorize(authData); - if (authData) { - freeAuthData(authData); - } - } - if (!ok) { - error(-1, "Incorrect password"); - } - return ok; -} - -//------------------------------------------------------------------------ -// StandardSecurityHandler -//------------------------------------------------------------------------ - -class StandardAuthData { -public: - - StandardAuthData(GString *ownerPasswordA, GString *userPasswordA) { - ownerPassword = ownerPasswordA; - userPassword = userPasswordA; - } - - ~StandardAuthData() { - if (ownerPassword) { - delete ownerPassword; - } - if (userPassword) { - delete userPassword; - } - } - - GString *ownerPassword; - GString *userPassword; -}; - -StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA, - Object *encryptDictA): - SecurityHandler(docA) -{ - Object versionObj, revisionObj, lengthObj; - Object ownerKeyObj, userKeyObj, permObj, fileIDObj; - Object fileIDObj1; - Object cryptFiltersObj, streamFilterObj, stringFilterObj; - Object cryptFilterObj, cfmObj, cfLengthObj; - Object encryptMetadataObj; - - ok = gFalse; - fileID = NULL; - ownerKey = NULL; - userKey = NULL; - - encryptDictA->dictLookup("V", &versionObj); - encryptDictA->dictLookup("R", &revisionObj); - encryptDictA->dictLookup("Length", &lengthObj); - encryptDictA->dictLookup("O", &ownerKeyObj); - encryptDictA->dictLookup("U", &userKeyObj); - encryptDictA->dictLookup("P", &permObj); - doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj); - if (versionObj.isInt() && - revisionObj.isInt() && - ownerKeyObj.isString() && ownerKeyObj.getString()->getLength() == 32 && - userKeyObj.isString() && userKeyObj.getString()->getLength() == 32 && - permObj.isInt()) { - encVersion = versionObj.getInt(); - encRevision = revisionObj.getInt(); - // revision 2 forces a 40-bit key - some buggy PDF generators - // set the Length value incorrectly - if (encRevision == 2 || !lengthObj.isInt()) { - fileKeyLength = 5; - } else { - fileKeyLength = lengthObj.getInt() / 8; - } - encryptMetadata = gTrue; - //~ this currently only handles a subset of crypt filter functionality - if (encVersion == 4 && encRevision == 4) { - encryptDictA->dictLookup("CF", &cryptFiltersObj); - encryptDictA->dictLookup("StmF", &streamFilterObj); - encryptDictA->dictLookup("StrF", &stringFilterObj); - if (cryptFiltersObj.isDict() && - streamFilterObj.isName() && - stringFilterObj.isName() && - !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) { - if (cryptFiltersObj.dictLookup(streamFilterObj.getName(), - &cryptFilterObj)->isDict()) { - if (cryptFilterObj.dictLookup("CFM", &cfmObj)->isName("V2")) { - encVersion = 2; - encRevision = 3; - if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { - //~ according to the spec, this should be cfLengthObj / 8 - fileKeyLength = cfLengthObj.getInt(); - } - cfLengthObj.free(); - } - cfmObj.free(); - } - cryptFilterObj.free(); - } - stringFilterObj.free(); - streamFilterObj.free(); - cryptFiltersObj.free(); - if (encryptDictA->dictLookup("EncryptMetadata", - &encryptMetadataObj)->isBool()) { - encryptMetadata = encryptMetadataObj.getBool(); - } - encryptMetadataObj.free(); - } - permFlags = permObj.getInt(); - ownerKey = ownerKeyObj.getString()->copy(); - userKey = userKeyObj.getString()->copy(); - if (encVersion >= 1 && encVersion <= 2 && - encRevision >= 2 && encRevision <= 3) { - if (fileIDObj.isArray()) { - if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) { - fileID = fileIDObj1.getString()->copy(); - } else { - fileID = new GString(); - } - fileIDObj1.free(); - } else { - fileID = new GString(); - } - ok = gTrue; - } else { - error(-1, "Unsupported version/revision (%d/%d) of Standard security handler", - encVersion, encRevision); - } - } else { - error(-1, "Weird encryption info"); - } - if (fileKeyLength > 16) { - fileKeyLength = 16; - } - fileIDObj.free(); - permObj.free(); - userKeyObj.free(); - ownerKeyObj.free(); - lengthObj.free(); - revisionObj.free(); - versionObj.free(); -} - -StandardSecurityHandler::~StandardSecurityHandler() { - if (fileID) { - delete fileID; - } - if (ownerKey) { - delete ownerKey; - } - if (userKey) { - delete userKey; - } -} - -void *StandardSecurityHandler::makeAuthData(GString *ownerPassword, - GString *userPassword) { - return new StandardAuthData(ownerPassword ? ownerPassword->copy() - : (GString *)NULL, - userPassword ? userPassword->copy() - : (GString *)NULL); -} - -void *StandardSecurityHandler::getAuthData() { -#if HAVE_XPDFCORE - XPDFCore *core; - GString *password; - - if (!(core = (XPDFCore *)doc->getGUIData()) || - !(password = core->getPassword())) { - return NULL; - } - return new StandardAuthData(password, password->copy()); -#elif HAVE_WINPDFCORE - WinPDFCore *core; - GString *password; - - if (!(core = (WinPDFCore *)doc->getGUIData()) || - !(password = core->getPassword())) { - return NULL; - } - return new StandardAuthData(password, password->copy()); -#else - return NULL; -#endif -} - -void StandardSecurityHandler::freeAuthData(void *authData) { - delete (StandardAuthData *)authData; -} - -GBool StandardSecurityHandler::authorize(void *authData) { - GString *ownerPassword, *userPassword; - - if (!ok) { - return gFalse; - } - if (authData) { - ownerPassword = ((StandardAuthData *)authData)->ownerPassword; - userPassword = ((StandardAuthData *)authData)->userPassword; - } else { - ownerPassword = NULL; - userPassword = NULL; - } - if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength, - ownerKey, userKey, permFlags, fileID, - ownerPassword, userPassword, fileKey, - encryptMetadata, &ownerPasswordOk)) { - return gFalse; - } - return gTrue; -} - -#ifdef ENABLE_PLUGINS - -//------------------------------------------------------------------------ -// ExternalSecurityHandler -//------------------------------------------------------------------------ - -ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA, - Object *encryptDictA, - XpdfSecurityHandler *xshA): - SecurityHandler(docA) -{ - encryptDictA->copy(&encryptDict); - xsh = xshA; - ok = gFalse; - - if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA, - (XpdfObject)encryptDictA, &docData)) { - return; - } - - ok = gTrue; -} - -ExternalSecurityHandler::~ExternalSecurityHandler() { - (*xsh->freeDoc)(xsh->handlerData, docData); - encryptDict.free(); -} - -void *ExternalSecurityHandler::makeAuthData(GString *ownerPassword, - GString *userPassword) { - char *opw, *upw; - void *authData; - - opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL; - upw = userPassword ? userPassword->getCString() : (char *)NULL; - if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) { - return NULL; - } - return authData; -} - -void *ExternalSecurityHandler::getAuthData() { - void *authData; - - if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) { - return NULL; - } - return authData; -} - -void ExternalSecurityHandler::freeAuthData(void *authData) { - (*xsh->freeAuthData)(xsh->handlerData, docData, authData); -} - -GBool ExternalSecurityHandler::authorize(void *authData) { - char *key; - int length; - - if (!ok) { - return gFalse; - } - permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData); - if (!(permFlags & xpdfPermissionOpen)) { - return gFalse; - } - if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion)) { - return gFalse; - } - if ((fileKeyLength = length) > 16) { - fileKeyLength = 16; - } - memcpy(fileKey, key, fileKeyLength); - (*xsh->freeKey)(xsh->handlerData, docData, key, length); - return gTrue; -} - -#endif // ENABLE_PLUGINS diff --git a/xpdf/xpdf/SecurityHandler.h b/xpdf/xpdf/SecurityHandler.h deleted file mode 100644 index 127acb769..000000000 --- a/xpdf/xpdf/SecurityHandler.h +++ /dev/null @@ -1,155 +0,0 @@ -//======================================================================== -// -// SecurityHandler.h -// -// Copyright 2004 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef SECURITYHANDLER_H -#define SECURITYHANDLER_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "Object.h" - -class GString; -class PDFDoc; -struct XpdfSecurityHandler; - -//------------------------------------------------------------------------ -// SecurityHandler -//------------------------------------------------------------------------ - -class SecurityHandler { -public: - - static SecurityHandler *make(PDFDoc *docA, Object *encryptDictA); - - SecurityHandler(PDFDoc *docA); - virtual ~SecurityHandler(); - - // Check the document's encryption. If the document is encrypted, - // this will first try and (in - // "batch" mode), and if those fail, it will attempt to request a - // password from the user. This is the high-level function that - // calls the lower level functions for the specific security handler - // (requesting a password three times, etc.). Returns true if the - // document can be opened (if it's unencrypted, or if a correct - // password is obtained); false otherwise (encrypted and no correct - // password). - GBool checkEncryption(GString *ownerPassword, - GString *userPassword); - - // Create authorization data for the specified owner and user - // passwords. If the security handler doesn't support "batch" mode, - // this function should return NULL. - virtual void *makeAuthData(GString *ownerPassword, - GString *userPassword) = 0; - - // Construct authorization data, typically by prompting the user for - // a password. Returns an authorization data object, or NULL to - // cancel. - virtual void *getAuthData() = 0; - - // Free the authorization data returned by makeAuthData or - // getAuthData. - virtual void freeAuthData(void *authData) = 0; - - // Attempt to authorize the document, using the supplied - // authorization data (which may be NULL). Returns true if - // successful (i.e., if at least the right to open the document was - // granted). - virtual GBool authorize(void *authData) = 0; - - // Return the various authorization parameters. These are only - // valid after authorize has returned true. - virtual int getPermissionFlags() = 0; - virtual GBool getOwnerPasswordOk() = 0; - virtual Guchar *getFileKey() = 0; - virtual int getFileKeyLength() = 0; - virtual int getEncVersion() = 0; - -protected: - - PDFDoc *doc; -}; - -//------------------------------------------------------------------------ -// StandardSecurityHandler -//------------------------------------------------------------------------ - -class StandardSecurityHandler: public SecurityHandler { -public: - - StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA); - virtual ~StandardSecurityHandler(); - - virtual void *makeAuthData(GString *ownerPassword, - GString *userPassword); - virtual void *getAuthData(); - virtual void freeAuthData(void *authData); - virtual GBool authorize(void *authData); - virtual int getPermissionFlags() { return permFlags; } - virtual GBool getOwnerPasswordOk() { return ownerPasswordOk; } - virtual Guchar *getFileKey() { return fileKey; } - virtual int getFileKeyLength() { return fileKeyLength; } - virtual int getEncVersion() { return encVersion; } - -private: - - int permFlags; - GBool ownerPasswordOk; - Guchar fileKey[16]; - int fileKeyLength; - int encVersion; - int encRevision; - GBool encryptMetadata; - - GString *ownerKey, *userKey; - GString *fileID; - GBool ok; -}; - -#ifdef ENABLE_PLUGINS -//------------------------------------------------------------------------ -// ExternalSecurityHandler -//------------------------------------------------------------------------ - -class ExternalSecurityHandler: public SecurityHandler { -public: - - ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA, - XpdfSecurityHandler *xshA); - virtual ~ExternalSecurityHandler(); - - virtual void *makeAuthData(GString *ownerPassword, - GString *userPassword); - virtual void *getAuthData(); - virtual void freeAuthData(void *authData); - virtual GBool authorize(void *authData); - virtual int getPermissionFlags() { return permFlags; } - virtual GBool getOwnerPasswordOk() { return gFalse; } - virtual Guchar *getFileKey() { return fileKey; } - virtual int getFileKeyLength() { return fileKeyLength; } - virtual int getEncVersion() { return encVersion; } - -private: - - Object encryptDict; - XpdfSecurityHandler *xsh; - void *docData; - int permFlags; - Guchar fileKey[16]; - int fileKeyLength; - int encVersion; - GBool ok; -}; -#endif // ENABLE_PLUGINS - -#endif diff --git a/xpdf/xpdf/SplashOutputDev.cc b/xpdf/xpdf/SplashOutputDev.cc deleted file mode 100644 index 35050044a..000000000 --- a/xpdf/xpdf/SplashOutputDev.cc +++ /dev/null @@ -1,2628 +0,0 @@ -//======================================================================== -// -// SplashOutputDev.cc -// -// Copyright 2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gfile.h" -#include "GlobalParams.h" -#include "Error.h" -#include "Object.h" -#include "GfxFont.h" -#include "Link.h" -#include "CharCodeToUnicode.h" -#include "FontEncodingTables.h" -#include "FoFiTrueType.h" -#include "SplashBitmap.h" -#include "SplashGlyphBitmap.h" -#include "SplashPattern.h" -#include "SplashScreen.h" -#include "SplashPath.h" -#include "SplashState.h" -#include "SplashErrorCodes.h" -#include "SplashFontEngine.h" -#include "SplashFont.h" -#include "SplashFontFile.h" -#include "SplashFontFileID.h" -#include "Splash.h" -#include "SplashOutputDev.h" - -//------------------------------------------------------------------------ -// Blend functions -//------------------------------------------------------------------------ - -static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i; - - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - // note: floor(x / 255) = x >> 8 (for 16-bit x) - blend[i] = (dest[i] * src[i]) >> 8; - } -} - -static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i; - - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - // note: floor(x / 255) = x >> 8 (for 16-bit x) - blend[i] = dest[i] + src[i] - ((dest[i] * src[i]) >> 8); - } -} - -static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i; - - //~ not sure if this is right - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - // note: floor(x / 255) = x >> 8 (for 16-bit x) - blend[i] = dest[i] < 0x80 ? ((dest[i] * src[i]) >> 8) - : dest[i] + src[i] - ((dest[i] * src[i]) >> 8); - } -} - -static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i; - - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = dest[i] < src[i] ? dest[i] : src[i]; - } -} - -static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i; - - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = dest[i] > src[i] ? dest[i] : src[i]; - } -} - -static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, - SplashColorMode cm) { - int i, x; - - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - x = dest[i] + src[i]; - blend[i] = x <= 255 ? x : 255; - } -} - -static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i, x; - - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - x = dest[i] - (255 - src[i]); - blend[i] = x >= 0 ? x : 0; - } -} - -static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i; - - //~ not sure if this is right - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - // note: floor(x / 255) = x >> 8 (for 16-bit x) - blend[i] = src[i] < 0x80 - ? ((dest[i] * (src[i] * 2)) >> 8) - : 0xff - (((0xff - dest[i]) * (0x1ff - src[i] * 2)) >> 8); - } -} - -static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i, x; - - //~ not sure if this is right - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - if (src[i] < 0x80) { - x = dest[i] - (0x80 - src[i]); - blend[i] = x >= 0 ? x : 0; - } else { - x = dest[i] + (src[i] - 0x80); - blend[i] = x <= 255 ? x : 255; - } - } -} - -static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, - SplashColorMode cm) { - int i; - - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i]; - } -} - -static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int i; - - //~ not sure what this is supposed to do - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i]; - } -} - -static void cvtRGBToHSV(Guchar r, Guchar g, Guchar b, int *h, int *s, int *v) { - int cmax, cmid, cmin, x; - - if (r >= g) { - if (g >= b) { x = 0; cmax = r; cmid = g; cmin = b; } - else if (b >= r) { x = 4; cmax = b; cmid = r; cmin = g; } - else { x = 5; cmax = r; cmid = b; cmin = g; } - } else { - if (r >= b) { x = 1; cmax = g; cmid = r; cmin = b; } - else if (g >= b) { x = 2; cmax = g; cmid = b; cmin = r; } - else { x = 3; cmax = b; cmid = g; cmin = r; } - } - if (cmax == cmin) { - *h = *s = 0; - } else { - *h = x * 60; - if (x & 1) { - *h += ((cmax - cmid) * 60) / (cmax - cmin); - } else { - *h += ((cmid - cmin) * 60) / (cmax - cmin); - } - *s = (255 * (cmax - cmin)) / cmax; - } - *v = cmax; -} - -static void cvtHSVToRGB(int h, int s, int v, Guchar *r, Guchar *g, Guchar *b) { - int x, f, cmax, cmid, cmin; - - if (s == 0) { - *r = *g = *b = v; - } else { - x = h / 60; - f = h % 60; - cmax = v; - if (x & 1) { - cmid = (v * 255 - ((s * f) / 60)) >> 8; - } else { - cmid = (v * (255 - ((s * (60 - f)) / 60))) >> 8; - } - // note: floor(x / 255) = x >> 8 (for 16-bit x) - cmin = (v * (255 - s)) >> 8; - switch (x) { - case 0: *r = cmax; *g = cmid; *b = cmin; break; - case 1: *g = cmax; *r = cmid; *b = cmin; break; - case 2: *g = cmax; *b = cmid; *r = cmin; break; - case 3: *b = cmax; *g = cmid; *r = cmin; break; - case 4: *b = cmax; *r = cmid; *g = cmin; break; - case 5: *r = cmax; *b = cmid; *g = cmin; break; - } - } -} - -static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int hs, ss, vs, hd, sd, vd; -#if SPLASH_CMYK - Guchar r, g, b; -#endif - - switch (cm) { - case splashModeMono1: - case splashModeMono8: - blend[0] = dest[0]; - break; - case splashModeRGB8: - cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); - cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); - cvtHSVToRGB(hs, sd, vd, &blend[0], &blend[1], &blend[2]); - break; - case splashModeBGR8: - cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); - cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); - cvtHSVToRGB(hs, sd, vd, &blend[2], &blend[1], &blend[0]); - break; -#if SPLASH_CMYK - case splashModeCMYK8: - //~ (0xff - ...) should be clipped - cvtRGBToHSV(0xff - (src[0] + src[3]), - 0xff - (src[1] + src[3]), - 0xff - (src[2] + src[3]), &hs, &ss, &vs); - cvtRGBToHSV(0xff - (dest[0] + dest[3]), - 0xff - (dest[1] + dest[3]), - 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); - cvtHSVToRGB(hs, sd, vd, &r, &g, &b); - //~ should do black generation - blend[0] = 0xff - r; - blend[0] = 0xff - g; - blend[0] = 0xff - b; - blend[3] = 0; - break; -#endif - default: - //~ unimplemented - break; - } -} - -static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, - SplashColorMode cm) { - int hs, ss, vs, hd, sd, vd; -#if SPLASH_CMYK - Guchar r, g, b; -#endif - - switch (cm) { - case splashModeMono1: - case splashModeMono8: - blend[0] = dest[0]; - break; - case splashModeRGB8: - cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); - cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); - cvtHSVToRGB(hd, ss, vd, &blend[0], &blend[1], &blend[2]); - break; - case splashModeBGR8: - cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); - cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); - cvtHSVToRGB(hd, ss, vd, &blend[2], &blend[1], &blend[0]); - break; -#if SPLASH_CMYK - case splashModeCMYK8: - //~ (0xff - ...) should be clipped - cvtRGBToHSV(0xff - (src[0] + src[3]), - 0xff - (src[1] + src[3]), - 0xff - (src[2] + src[3]), &hs, &ss, &vs); - cvtRGBToHSV(0xff - (dest[0] + dest[3]), - 0xff - (dest[1] + dest[3]), - 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); - cvtHSVToRGB(hd, ss, vd, &r, &g, &b); - //~ should do black generation - blend[0] = 0xff - r; - blend[0] = 0xff - g; - blend[0] = 0xff - b; - blend[3] = 0; - break; -#endif - default: - //~ unimplemented - break; - } -} - -static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, SplashColorMode cm) { - int hs, ss, vs, hd, sd, vd; -#if SPLASH_CMYK - Guchar r, g, b; -#endif - - switch (cm) { - case splashModeMono1: - case splashModeMono8: - blend[0] = dest[0]; - break; - case splashModeRGB8: - cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); - cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); - cvtHSVToRGB(hs, ss, vd, &blend[0], &blend[1], &blend[2]); - break; - case splashModeBGR8: - cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); - cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); - cvtHSVToRGB(hs, ss, vd, &blend[2], &blend[1], &blend[0]); - break; -#if SPLASH_CMYK - case splashModeCMYK8: - //~ (0xff - ...) should be clipped - cvtRGBToHSV(0xff - (src[0] + src[3]), - 0xff - (src[1] + src[3]), - 0xff - (src[2] + src[3]), &hs, &ss, &vs); - cvtRGBToHSV(0xff - (dest[0] + dest[3]), - 0xff - (dest[1] + dest[3]), - 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); - cvtHSVToRGB(hs, ss, vd, &r, &g, &b); - //~ should do black generation - blend[0] = 0xff - r; - blend[0] = 0xff - g; - blend[0] = 0xff - b; - blend[3] = 0; - break; -#endif - default: - //~ unimplemented - break; - } -} - -static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest, - SplashColorPtr blend, - SplashColorMode cm) { - int hs, ss, vs, hd, sd, vd; -#if SPLASH_CMYK - Guchar r, g, b; -#endif - - switch (cm) { - case splashModeMono1: - case splashModeMono8: - blend[0] = dest[0]; - break; - case splashModeRGB8: - cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); - cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); - cvtHSVToRGB(hd, sd, vs, &blend[0], &blend[1], &blend[2]); - break; - case splashModeBGR8: - cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); - cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); - cvtHSVToRGB(hd, sd, vs, &blend[2], &blend[1], &blend[0]); - break; -#if SPLASH_CMYK - case splashModeCMYK8: - //~ (0xff - ...) should be clipped - cvtRGBToHSV(0xff - (src[0] + src[3]), - 0xff - (src[1] + src[3]), - 0xff - (src[2] + src[3]), &hs, &ss, &vs); - cvtRGBToHSV(0xff - (dest[0] + dest[3]), - 0xff - (dest[1] + dest[3]), - 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); - cvtHSVToRGB(hd, sd, vs, &r, &g, &b); - //~ should do black generation - blend[0] = 0xff - r; - blend[0] = 0xff - g; - blend[0] = 0xff - b; - blend[3] = 0; - break; -#endif - default: - //~ unimplemented - break; - } -} - -// NB: This must match the GfxBlendMode enum defined in GfxState.h. -SplashBlendFunc splashOutBlendFuncs[] = { - NULL, - &splashOutBlendMultiply, - &splashOutBlendScreen, - &splashOutBlendOverlay, - &splashOutBlendDarken, - &splashOutBlendLighten, - &splashOutBlendColorDodge, - &splashOutBlendColorBurn, - &splashOutBlendHardLight, - &splashOutBlendSoftLight, - &splashOutBlendDifference, - &splashOutBlendExclusion, - &splashOutBlendHue, - &splashOutBlendSaturation, - &splashOutBlendColor, - &splashOutBlendLuminosity -}; - -//------------------------------------------------------------------------ -// Font substitutions -//------------------------------------------------------------------------ - -struct SplashOutFontSubst { - const char *name; - double mWidth; -}; - -// index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic -static SplashOutFontSubst splashOutSubstFonts[16] = { - {"Helvetica", 0.833}, - {"Helvetica-Oblique", 0.833}, - {"Helvetica-Bold", 0.889}, - {"Helvetica-BoldOblique", 0.889}, - {"Times-Roman", 0.788}, - {"Times-Italic", 0.722}, - {"Times-Bold", 0.833}, - {"Times-BoldItalic", 0.778}, - {"Courier", 0.600}, - {"Courier-Oblique", 0.600}, - {"Courier-Bold", 0.600}, - {"Courier-BoldOblique", 0.600}, - {"Symbol", 0.576}, - {"Symbol", 0.576}, - {"Symbol", 0.576}, - {"Symbol", 0.576} -}; - -//------------------------------------------------------------------------ -// SplashOutFontFileID -//------------------------------------------------------------------------ - -class SplashOutFontFileID: public SplashFontFileID { -public: - - SplashOutFontFileID(Ref *rA) { r = *rA; substIdx = -1; } - - ~SplashOutFontFileID() {} - - GBool matches(SplashFontFileID *id) { - return ((SplashOutFontFileID *)id)->r.num == r.num && - ((SplashOutFontFileID *)id)->r.gen == r.gen; - } - - void setSubstIdx(int substIdxA) { substIdx = substIdxA; } - int getSubstIdx() { return substIdx; } - -private: - - Ref r; - int substIdx; -}; - -//------------------------------------------------------------------------ -// T3FontCache -//------------------------------------------------------------------------ - -struct T3FontCacheTag { - Gushort code; - Gushort mru; // valid bit (0x8000) and MRU index -}; - -class T3FontCache { -public: - - T3FontCache(Ref *fontID, double m11A, double m12A, - double m21A, double m22A, - int glyphXA, int glyphYA, int glyphWA, int glyphHA, - GBool aa); - ~T3FontCache(); - GBool matches(Ref *idA, double m11A, double m12A, - double m21A, double m22A) - { return fontID.num == idA->num && fontID.gen == idA->gen && - m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; } - - Ref fontID; // PDF font ID - double m11, m12, m21, m22; // transform matrix - int glyphX, glyphY; // pixel offset of glyph bitmaps - int glyphW, glyphH; // size of glyph bitmaps, in pixels - int glyphSize; // size of glyph bitmaps, in bytes - int cacheSets; // number of sets in cache - int cacheAssoc; // cache associativity (glyphs per set) - Guchar *cacheData; // glyph pixmap cache - T3FontCacheTag *cacheTags; // cache tags, i.e., char codes -}; - -T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A, - double m21A, double m22A, - int glyphXA, int glyphYA, int glyphWA, int glyphHA, - GBool aa) { - int i; - - fontID = *fontIDA; - m11 = m11A; - m12 = m12A; - m21 = m21A; - m22 = m22A; - glyphX = glyphXA; - glyphY = glyphYA; - glyphW = glyphWA; - glyphH = glyphHA; - if (aa) { - glyphSize = glyphW * glyphH; - } else { - glyphSize = ((glyphW + 7) >> 3) * glyphH; - } - cacheAssoc = 8; - if (glyphSize <= 256) { - cacheSets = 8; - } else if (glyphSize <= 512) { - cacheSets = 4; - } else if (glyphSize <= 1024) { - cacheSets = 2; - } else { - cacheSets = 1; - } - cacheData = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize); - cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc, - sizeof(T3FontCacheTag)); - for (i = 0; i < cacheSets * cacheAssoc; ++i) { - cacheTags[i].mru = i & (cacheAssoc - 1); - } -} - -T3FontCache::~T3FontCache() { - gfree(cacheData); - gfree(cacheTags); -} - -struct T3GlyphStack { - Gushort code; // character code - double x, y; // position to draw the glyph - - //----- cache info - T3FontCache *cache; // font cache for the current font - T3FontCacheTag *cacheTag; // pointer to cache tag for the glyph - Guchar *cacheData; // pointer to cache data for the glyph - - //----- saved state - SplashBitmap *origBitmap; - Splash *origSplash; - double origCTM4, origCTM5; - - T3GlyphStack *next; // next object on stack -}; - -//------------------------------------------------------------------------ -// SplashOutputDev -//------------------------------------------------------------------------ - -SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, - int bitmapRowPadA, - GBool reverseVideoA, - SplashColorPtr paperColorA, - GBool bitmapTopDownA, - GBool allowAntialiasA) { - colorMode = colorModeA; - bitmapRowPad = bitmapRowPadA; - bitmapTopDown = bitmapTopDownA; - allowAntialias = allowAntialiasA; - reverseVideo = reverseVideoA; - splashColorCopy(paperColor, paperColorA); - - xref = NULL; - - bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, bitmapTopDown); - splash = new Splash(bitmap); - splash->clear(paperColor); - - fontEngine = NULL; - - nT3Fonts = 0; - t3GlyphStack = NULL; - - font = NULL; - needFontUpdate = gFalse; - textClipPath = NULL; -} - -SplashOutputDev::~SplashOutputDev() { - int i; - - for (i = 0; i < nT3Fonts; ++i) { - delete t3FontCache[i]; - } - if (fontEngine) { - delete fontEngine; - } - if (splash) { - delete splash; - } - if (bitmap) { - delete bitmap; - } -} - -void SplashOutputDev::startDoc(XRef *xrefA) { - int i; - - xref = xrefA; - if (fontEngine) { - delete fontEngine; - } - fontEngine = new SplashFontEngine( -#if HAVE_T1LIB_H - globalParams->getEnableT1lib(), -#endif -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - globalParams->getEnableFreeType(), -#endif - allowAntialias && - globalParams->getAntialias() && - colorMode != splashModeMono1); - for (i = 0; i < nT3Fonts; ++i) { - delete t3FontCache[i]; - } - nT3Fonts = 0; -} - -void SplashOutputDev::startPage(int /*pageNum*/, GfxState *state) { - int w, h; - SplashColor color; - - w = state ? (int)(state->getPageWidth() + 0.5) : 1; - h = state ? (int)(state->getPageHeight() + 0.5) : 1; - if (splash) { - delete splash; - } - if (!bitmap || w != bitmap->getWidth() || h != bitmap->getHeight()) { - if (bitmap) { - delete bitmap; - } - bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, bitmapTopDown); - } - splash = new Splash(bitmap); - switch (colorMode) { - case splashModeMono1: - case splashModeMono8: - color[0] = 0; - break; - case splashModeRGB8: - case splashModeBGR8: - color[0] = color[1] = color[2] = 0; - break; - case splashModeAMono8: - color[0] = 0xff; - color[1] = 0; - break; - case splashModeARGB8: - color[0] = 255; - color[1] = color[2] = color[3] = 0; - break; - case splashModeBGRA8: - color[0] = color[1] = color[2] = 0; - color[3] = 255; - break; -#if SPLASH_CMYK - case splashModeCMYK8: - color[0] = color[1] = color[2] = color[3] = 0; - break; - case splashModeACMYK8: - color[0] = 255; - color[1] = color[2] = color[3] = color[4] = 0; - break; -#endif - } - splash->setStrokePattern(new SplashSolidColor(color)); - splash->setFillPattern(new SplashSolidColor(color)); - splash->setLineCap(splashLineCapButt); - splash->setLineJoin(splashLineJoinMiter); - splash->setLineDash(NULL, 0, 0); - splash->setMiterLimit(10); - splash->setFlatness(1); - splash->clear(paperColor); -} - -void SplashOutputDev::endPage() { -} - -void SplashOutputDev::drawLink(Link *link, Catalog */*catalog*/) { - double x1, y1, x2, y2; - LinkBorderStyle *borderStyle; - double r, g, b; - GfxRGB rgb; - GfxGray gray; -#if SPLASH_CMYK - GfxCMYK cmyk; -#endif - double *dash; - int dashLength; - SplashCoord dashList[20]; - SplashPath *path; - int x, y, i; - - link->getRect(&x1, &y1, &x2, &y2); - borderStyle = link->getBorderStyle(); - if (borderStyle->getWidth() > 0) { - borderStyle->getColor(&r, &g, &b); - rgb.r = dblToCol(r); - rgb.g = dblToCol(g); - rgb.b = dblToCol(b); - gray = dblToCol(0.299 * r + 0.587 * g + 0.114 * b); - if (gray > gfxColorComp1) { - gray = gfxColorComp1; - } -#if SPLASH_CMYK - cmyk.c = gfxColorComp1 - rgb.r; - cmyk.m = gfxColorComp1 - rgb.g; - cmyk.y = gfxColorComp1 - rgb.b; - cmyk.k = 0; - splash->setStrokePattern(getColor(gray, &rgb, &cmyk)); -#else - splash->setStrokePattern(getColor(gray, &rgb)); -#endif - splash->setLineWidth((SplashCoord)borderStyle->getWidth()); - borderStyle->getDash(&dash, &dashLength); - if (borderStyle->getType() == linkBorderDashed && dashLength > 0) { - if (dashLength > 20) { - dashLength = 20; - } - for (i = 0; i < dashLength; ++i) { - dashList[i] = (SplashCoord)dash[i]; - } - splash->setLineDash(dashList, dashLength, 0); - } - path = new SplashPath(); - if (borderStyle->getType() == linkBorderUnderlined) { - cvtUserToDev(x1, y1, &x, &y); - path->moveTo((SplashCoord)x, (SplashCoord)y); - cvtUserToDev(x2, y1, &x, &y); - path->lineTo((SplashCoord)x, (SplashCoord)y); - } else { - cvtUserToDev(x1, y1, &x, &y); - path->moveTo((SplashCoord)x, (SplashCoord)y); - cvtUserToDev(x2, y1, &x, &y); - path->lineTo((SplashCoord)x, (SplashCoord)y); - cvtUserToDev(x2, y2, &x, &y); - path->lineTo((SplashCoord)x, (SplashCoord)y); - cvtUserToDev(x1, y2, &x, &y); - path->lineTo((SplashCoord)x, (SplashCoord)y); - path->close(); - } - splash->stroke(path); - delete path; - } -} - -void SplashOutputDev::saveState(GfxState */*state*/) { - splash->saveState(); -} - -void SplashOutputDev::restoreState(GfxState */*state*/) { - splash->restoreState(); - needFontUpdate = gTrue; -} - -void SplashOutputDev::updateAll(GfxState *state) { - updateLineDash(state); - updateLineJoin(state); - updateLineCap(state); - updateLineWidth(state); - updateFlatness(state); - updateMiterLimit(state); - updateFillColor(state); - updateStrokeColor(state); - needFontUpdate = gTrue; -} - -void SplashOutputDev::updateCTM(GfxState *state, double /*m11*/, double /*m12*/, - double /*m21*/, double /*m22*/, - double /*m31*/, double /*m32*/) { - updateLineDash(state); - updateLineJoin(state); - updateLineCap(state); - updateLineWidth(state); -} - -void SplashOutputDev::updateLineDash(GfxState *state) { - double *dashPattern; - int dashLength; - double dashStart; - SplashCoord dash[20]; - SplashCoord phase; - int i; - - state->getLineDash(&dashPattern, &dashLength, &dashStart); - if (dashLength > 20) { - dashLength = 20; - } - for (i = 0; i < dashLength; ++i) { - dash[i] = (SplashCoord)state->transformWidth(dashPattern[i]); - if (dash[i] < 1) { - dash[i] = 1; - } - } - phase = (SplashCoord)state->transformWidth(dashStart); - splash->setLineDash(dash, dashLength, phase); -} - -void SplashOutputDev::updateFlatness(GfxState *state) { - splash->setFlatness(state->getFlatness()); -} - -void SplashOutputDev::updateLineJoin(GfxState *state) { - splash->setLineJoin(state->getLineJoin()); -} - -void SplashOutputDev::updateLineCap(GfxState *state) { - splash->setLineCap(state->getLineCap()); -} - -void SplashOutputDev::updateMiterLimit(GfxState *state) { - splash->setMiterLimit(state->getMiterLimit()); -} - -void SplashOutputDev::updateLineWidth(GfxState *state) { - splash->setLineWidth(state->getTransformedLineWidth()); -} - -void SplashOutputDev::updateFillColor(GfxState *state) { - GfxGray gray; - GfxRGB rgb; -#if SPLASH_CMYK - GfxCMYK cmyk; -#endif - - state->getFillGray(&gray); - state->getFillRGB(&rgb); -#if SPLASH_CMYK - state->getFillCMYK(&cmyk); - splash->setFillPattern(getColor(gray, &rgb, &cmyk)); -#else - splash->setFillPattern(getColor(gray, &rgb)); -#endif -} - -void SplashOutputDev::updateStrokeColor(GfxState *state) { - GfxGray gray; - GfxRGB rgb; -#if SPLASH_CMYK - GfxCMYK cmyk; -#endif - - state->getStrokeGray(&gray); - state->getStrokeRGB(&rgb); -#if SPLASH_CMYK - state->getStrokeCMYK(&cmyk); - splash->setStrokePattern(getColor(gray, &rgb, &cmyk)); -#else - splash->setStrokePattern(getColor(gray, &rgb)); -#endif -} - -#if SPLASH_CMYK -SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb, - GfxCMYK *cmyk) { -#else -SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) { -#endif - SplashPattern *pattern; - SplashColor color0, color1; - GfxColorComp r, g, b; - - if (reverseVideo) { - gray = gfxColorComp1 - gray; - r = gfxColorComp1 - rgb->r; - g = gfxColorComp1 - rgb->g; - b = gfxColorComp1 - rgb->b; - } else { - r = rgb->r; - g = rgb->g; - b = rgb->b; - } - - pattern = NULL; // make gcc happy - switch (colorMode) { - case splashModeMono1: - color0[0] = 0; - color1[0] = 1; - pattern = new SplashHalftone(color0, color1, - splash->getScreen()->copy(), - (SplashCoord)colToDbl(gray)); - break; - case splashModeMono8: - color1[0] = colToByte(gray); - pattern = new SplashSolidColor(color1); - break; - case splashModeAMono8: - color1[0] = 255; - color1[1] = colToByte(gray); - pattern = new SplashSolidColor(color1); - break; - case splashModeRGB8: - color1[0] = colToByte(r); - color1[1] = colToByte(g); - color1[2] = colToByte(b); - pattern = new SplashSolidColor(color1); - break; - case splashModeBGR8: - color1[2] = colToByte(r); - color1[1] = colToByte(g); - color1[0] = colToByte(b); - pattern = new SplashSolidColor(color1); - break; - case splashModeARGB8: - color1[0] = 255; - color1[1] = colToByte(r); - color1[2] = colToByte(g); - color1[3] = colToByte(b); - pattern = new SplashSolidColor(color1); - break; - case splashModeBGRA8: - color1[3] = 255; - color1[2] = colToByte(r); - color1[1] = colToByte(g); - color1[0] = colToByte(b); - pattern = new SplashSolidColor(color1); - break; -#if SPLASH_CMYK - case splashModeCMYK8: - color1[0] = colToByte(cmyk->c); - color1[1] = colToByte(cmyk->m); - color1[2] = colToByte(cmyk->y); - color1[3] = colToByte(cmyk->k); - pattern = new SplashSolidColor(color1); - break; - case splashModeACMYK8: - color1[0] = 255; - color1[1] = colToByte(cmyk->c); - color1[2] = colToByte(cmyk->m); - color1[3] = colToByte(cmyk->y); - color1[4] = colToByte(cmyk->k); - pattern = new SplashSolidColor(color1); - break; -#endif - } - - return pattern; -} - -void SplashOutputDev::updateBlendMode(GfxState *state) { - splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]); -} - -void SplashOutputDev::updateFillOpacity(GfxState *state) { - splash->setFillAlpha((SplashCoord)state->getFillOpacity()); -} - -void SplashOutputDev::updateStrokeOpacity(GfxState *state) { - splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity()); -} - -void SplashOutputDev::updateFont(GfxState *state) { - GfxFont *gfxFont; - GfxFontType fontType; - SplashOutFontFileID *id; - SplashFontFile *fontFile; - SplashFontSrc *fontsrc; - FoFiTrueType *ff; - Ref embRef; - Object refObj, strObj; - GString *fileName, *substName; - char *tmpBuf; - int tmpBufLen; - Gushort *codeToGID; - DisplayFontParam *dfp; - CharCodeToUnicode *ctu; - double m11, m12, m21, m22, w1, w2; - SplashCoord mat[4]; - const char *name; - Unicode uBuf[8]; - int substIdx, n, code, cmap; - int faceIndex = 0; - - needFontUpdate = gFalse; - font = NULL; - fileName = NULL; - tmpBuf = NULL; - substIdx = -1; - dfp = NULL; - - if (!(gfxFont = state->getFont())) { - goto err1; - } - fontType = gfxFont->getType(); - if (fontType == fontType3) { - goto err1; - } - - // check the font file cache - id = new SplashOutFontFileID(gfxFont->getID()); - if ((fontFile = fontEngine->getFontFile(id))) { - delete id; - - } else { - - // if there is an embedded font, write it to disk - if (gfxFont->getEmbeddedFontID(&embRef)) { - tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen); - if (! tmpBuf) - goto err2; - // if there is an external font file, use it - } else if (!(fileName = gfxFont->getExtFontFile())) { - - // look for a display font mapping or a substitute font - if (gfxFont->isCIDFont()) { - if (((GfxCIDFont *)gfxFont)->getCollection()) { - dfp = globalParams-> - getDisplayCIDFont(gfxFont->getName(), - ((GfxCIDFont *)gfxFont)->getCollection()); - } - } else { - if (gfxFont->getName()) { - dfp = globalParams->getDisplayFont(gfxFont->getName()); - } - if (!dfp) { - // 8-bit font substitution - if (gfxFont->isFixedWidth()) { - substIdx = 8; - } else if (gfxFont->isSerif()) { - substIdx = 4; - } else { - substIdx = 0; - } - if (gfxFont->isBold()) { - substIdx += 2; - } - if (gfxFont->isItalic()) { - substIdx += 1; - } - substName = new GString(splashOutSubstFonts[substIdx].name); - dfp = globalParams->getDisplayFont(substName); - delete substName; - id->setSubstIdx(substIdx); - } - } - if (!dfp) { - error(-1, "Couldn't find a font for '%s'", - gfxFont->getName() ? gfxFont->getName()->getCString() - : "(unnamed)"); - goto err2; - } - switch (dfp->kind) { - case displayFontT1: - fileName = dfp->t1.fileName; - fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1; - faceIndex = dfp->tt.faceIndex; - break; - case displayFontTT: - fileName = dfp->tt.fileName; - fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType; - break; - } - } - - fontsrc = new SplashFontSrc; - if (fileName) - fontsrc->setFile(fileName, gFalse); - else - fontsrc->setBuf(tmpBuf, tmpBufLen, gFalse); - - // load the font file - switch (fontType) { - case fontType1: - fontFile = fontEngine->loadType1Font(id, fontsrc, - ((Gfx8BitFont *)gfxFont)->getEncoding()); - if (! fontFile) { - error(-1, "Couldn't create a font for '%s'", - gfxFont->getName() ? gfxFont->getName()->getCString() - : "(unnamed)"); - goto err2; - } - break; - case fontType1C: - fontFile = fontEngine->loadType1CFont(id, fontsrc, - ((Gfx8BitFont *)gfxFont)->getEncoding()); - if (! fontFile) { - error(-1, "Couldn't create a font for '%s'", - gfxFont->getName() ? gfxFont->getName()->getCString() - : "(unnamed)"); - goto err2; - } - break; - case fontTrueType: - if (fileName) - ff = FoFiTrueType::load(fileName->getCString()); - else - ff = new FoFiTrueType(tmpBuf, tmpBufLen, gFalse); - if (! ff) - goto err2; - codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff); - delete ff; - fontFile = fontEngine->loadTrueTypeFont(id, fontsrc, codeToGID, 256); - if (! fontFile) { - error(-1, "Couldn't create a font for '%s'", - gfxFont->getName() ? gfxFont->getName()->getCString() - : "(unnamed)"); - goto err2; - } - break; - case fontCIDType0: - case fontCIDType0C: - fontFile = fontEngine->loadCIDFont(id, fontsrc); - if (! fontFile) { - error(-1, "Couldn't create a font for '%s'", - gfxFont->getName() ? gfxFont->getName()->getCString() - : "(unnamed)"); - goto err2; - } - break; - case fontCIDType2: - codeToGID = NULL; - n = 0; - if (dfp) { - // create a CID-to-GID mapping, via Unicode - if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) { - if ((ff = FoFiTrueType::load(fileName->getCString()))) { - // look for a Unicode cmap - for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { - if ((ff->getCmapPlatform(cmap) == 3 && - ff->getCmapEncoding(cmap) == 1) || - ff->getCmapPlatform(cmap) == 0) { - break; - } - } - if (cmap < ff->getNumCmaps()) { - // map CID -> Unicode -> GID - n = ctu->getLength(); - codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); - for (code = 0; code < n; ++code) { - if (ctu->mapToUnicode(code, uBuf, 8) > 0) { - codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]); - } else { - codeToGID[code] = 0; - } - } - } - delete ff; - } - ctu->decRefCnt(); - } else { - error(-1, "Couldn't find a mapping to Unicode for font '%s'", - gfxFont->getName() ? gfxFont->getName()->getCString() - : "(unnamed)"); - } - } else { - if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { - n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); - codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); - memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), - n * sizeof(Gushort)); - } else { - if (fileName) - ff = FoFiTrueType::load(fileName->getCString()); - else - ff = new FoFiTrueType(tmpBuf, tmpBufLen, gFalse); - if (! ff) - goto err2; - codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n); - delete ff; - } - } - fontFile = fontEngine->loadTrueTypeFont(id, fontsrc, codeToGID, n, faceIndex); - if (!fontFile) { - error(-1, "Couldn't create a font for '%s'", - gfxFont->getName() ? gfxFont->getName()->getCString() - : "(unnamed)"); - goto err2; - } - break; - default: - // this shouldn't happen - goto err2; - } - } - - // get the font matrix - state->getFontTransMat(&m11, &m12, &m21, &m22); - m11 *= state->getHorizScaling(); - m12 *= state->getHorizScaling(); - - // for substituted fonts: adjust the font matrix -- compare the - // width of 'm' in the original font and the substituted font - substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx(); - if (substIdx >= 0) { - for (code = 0; code < 256; ++code) { - if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) && - name[0] == 'm' && name[1] == '\0') { - break; - } - } - if (code < 256) { - w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code); - w2 = splashOutSubstFonts[substIdx].mWidth; - if (!gfxFont->isSymbolic()) { - // if real font is substantially narrower than substituted - // font, reduce the font size accordingly - if (w1 > 0.01 && w1 < 0.9 * w2) { - w1 /= w2; - m11 *= w1; - m21 *= w1; - } - } - } - } - - // create the scaled font - mat[0] = m11; mat[1] = -m12; - mat[2] = m21; mat[3] = -m22; - if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.01) { - // avoid a singular (or close-to-singular) matrix - mat[0] = 0.01; mat[1] = 0; - mat[2] = 0; mat[3] = 0.01; - } - font = fontEngine->getFont(fontFile, mat); - - return; - - err2: - delete id; - err1: - return; -} - -void SplashOutputDev::stroke(GfxState *state) { - SplashPath *path; - - path = convertPath(state, state->getPath()); - splash->stroke(path); - delete path; -} - -void SplashOutputDev::fill(GfxState *state) { - SplashPath *path; - - path = convertPath(state, state->getPath()); - splash->fill(path, gFalse); - delete path; -} - -void SplashOutputDev::eoFill(GfxState *state) { - SplashPath *path; - - path = convertPath(state, state->getPath()); - splash->fill(path, gTrue); - delete path; -} - -void SplashOutputDev::clip(GfxState *state) { - SplashPath *path; - - path = convertPath(state, state->getPath()); - splash->clipToPath(path, gFalse); - delete path; -} - -void SplashOutputDev::eoClip(GfxState *state) { - SplashPath *path; - - path = convertPath(state, state->getPath()); - splash->clipToPath(path, gTrue); - delete path; -} - -SplashPath *SplashOutputDev::convertPath(GfxState *state, GfxPath *path) { - SplashPath *sPath; - GfxSubpath *subpath; - double x1, y1, x2, y2, x3, y3; - int i, j; - - sPath = new SplashPath(); - for (i = 0; i < path->getNumSubpaths(); ++i) { - subpath = path->getSubpath(i); - if (subpath->getNumPoints() > 0) { - state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1); - sPath->moveTo((SplashCoord)x1, (SplashCoord)y1); - j = 1; - while (j < subpath->getNumPoints()) { - if (subpath->getCurve(j)) { - state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1); - state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2); - state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3); - sPath->curveTo((SplashCoord)x1, (SplashCoord)y1, - (SplashCoord)x2, (SplashCoord)y2, - (SplashCoord)x3, (SplashCoord)y3); - j += 3; - } else { - state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1); - sPath->lineTo((SplashCoord)x1, (SplashCoord)y1); - ++j; - } - } - if (subpath->isClosed()) { - sPath->close(); - } - } - } - return sPath; -} - -void SplashOutputDev::drawChar(GfxState *state, double x, double y, - double /*dx*/, double /*dy*/, - double originX, double originY, - CharCode code, int /*nBytes*/, - Unicode */*u*/, int /*uLen*/) { - double x1, y1; - SplashPath *path; - int render; - - if (needFontUpdate) { - updateFont(state); - } - if (!font) { - return; - } - - // check for invisible text -- this is used by Acrobat Capture - render = state->getRender(); - if (render == 3) { - return; - } - - x -= originX; - y -= originY; - state->transform(x, y, &x1, &y1); - - // fill - if (!(render & 1)) { - splash->fillChar((SplashCoord)x1, (SplashCoord)y1, code, font); - } - - // stroke - if ((render & 3) == 1 || (render & 3) == 2) { - if ((path = font->getGlyphPath(code))) { - path->offset((SplashCoord)x1, (SplashCoord)y1); - splash->stroke(path); - delete path; - } - } - - // clip - if (render & 4) { - path = font->getGlyphPath(code); - path->offset((SplashCoord)x1, (SplashCoord)y1); - if (textClipPath) { - textClipPath->append(path); - delete path; - } else { - textClipPath = path; - } - } -} - -GBool SplashOutputDev::beginType3Char(GfxState *state, double /*x*/, double /*y*/, - double /*dx*/, double /*dy*/, - CharCode code, Unicode */*u*/, int /*uLen*/) { - GfxFont *gfxFont; - Ref *fontID; - double *ctm, *bbox; - T3FontCache *t3Font; - T3GlyphStack *t3gs; - double x1, y1, xMin, yMin, xMax, yMax, xt, yt; - int i, j; - - if (!(gfxFont = state->getFont())) { - return gFalse; - } - fontID = gfxFont->getID(); - ctm = state->getCTM(); - state->transform(0, 0, &xt, &yt); - - // is it the first (MRU) font in the cache? - if (!(nT3Fonts > 0 && - t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) { - - // is the font elsewhere in the cache? - for (i = 1; i < nT3Fonts; ++i) { - if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) { - t3Font = t3FontCache[i]; - for (j = i; j > 0; --j) { - t3FontCache[j] = t3FontCache[j - 1]; - } - t3FontCache[0] = t3Font; - break; - } - } - if (i >= nT3Fonts) { - - // create new entry in the font cache - if (nT3Fonts == splashOutT3FontCacheSize) { - delete t3FontCache[nT3Fonts - 1]; - --nT3Fonts; - } - for (j = nT3Fonts; j > 0; --j) { - t3FontCache[j] = t3FontCache[j - 1]; - } - ++nT3Fonts; - bbox = gfxFont->getFontBBox(); - if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) { - // broken bounding box -- just take a guess - xMin = xt - 5; - xMax = xMin + 30; - yMax = yt + 15; - yMin = yMax - 45; - } else { - state->transform(bbox[0], bbox[1], &x1, &y1); - xMin = xMax = x1; - yMin = yMax = y1; - state->transform(bbox[0], bbox[3], &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(bbox[2], bbox[1], &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(bbox[2], bbox[3], &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - } - t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3], - (int)floor(xMin - xt), - (int)floor(yMin - yt), - (int)ceil(xMax) - (int)floor(xMin) + 3, - (int)ceil(yMax) - (int)floor(yMin) + 3, - colorMode != splashModeMono1); - } - } - t3Font = t3FontCache[0]; - - // is the glyph in the cache? - i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; - for (j = 0; j < t3Font->cacheAssoc; ++j) { - if ((t3Font->cacheTags[i+j].mru & 0x8000) && - t3Font->cacheTags[i+j].code == code) { - drawType3Glyph(t3Font, &t3Font->cacheTags[i+j], - t3Font->cacheData + (i+j) * t3Font->glyphSize, - xt, yt); - return gTrue; - } - } - - // push a new Type 3 glyph record - t3gs = new T3GlyphStack(); - t3gs->next = t3GlyphStack; - t3GlyphStack = t3gs; - t3GlyphStack->code = code; - t3GlyphStack->x = xt; - t3GlyphStack->y = yt; - t3GlyphStack->cache = t3Font; - t3GlyphStack->cacheTag = NULL; - t3GlyphStack->cacheData = NULL; - - return gFalse; -} - -void SplashOutputDev::endType3Char(GfxState *state) { - T3GlyphStack *t3gs; - double *ctm; - - if (t3GlyphStack->cacheTag) { - memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(), - t3GlyphStack->cache->glyphSize); - delete bitmap; - delete splash; - bitmap = t3GlyphStack->origBitmap; - splash = t3GlyphStack->origSplash; - ctm = state->getCTM(); - state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], - t3GlyphStack->origCTM4, t3GlyphStack->origCTM5); - drawType3Glyph(t3GlyphStack->cache, - t3GlyphStack->cacheTag, t3GlyphStack->cacheData, - t3GlyphStack->x, t3GlyphStack->y); - } - t3gs = t3GlyphStack; - t3GlyphStack = t3gs->next; - delete t3gs; -} - -void SplashOutputDev::type3D0(GfxState */*state*/, double /*wx*/, double /*wy*/) { -} - -void SplashOutputDev::type3D1(GfxState *state, double /*wx*/, double /*wy*/, - double llx, double lly, double urx, double ury) { - double *ctm; - T3FontCache *t3Font; - SplashColor color; - double xt, yt, xMin, xMax, yMin, yMax, x1, y1; - int i, j; - - t3Font = t3GlyphStack->cache; - - // check for a valid bbox - state->transform(0, 0, &xt, &yt); - state->transform(llx, lly, &x1, &y1); - xMin = xMax = x1; - yMin = yMax = y1; - state->transform(llx, ury, &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(urx, lly, &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(urx, ury, &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - if (xMin - xt < t3Font->glyphX || - yMin - yt < t3Font->glyphY || - xMax - xt > t3Font->glyphX + t3Font->glyphW || - yMax - yt > t3Font->glyphY + t3Font->glyphH) { - error(-1, "Bad bounding box in Type 3 glyph"); - return; - } - - // allocate a cache entry - i = (t3GlyphStack->code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; - for (j = 0; j < t3Font->cacheAssoc; ++j) { - if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) { - t3Font->cacheTags[i+j].mru = 0x8000; - t3Font->cacheTags[i+j].code = t3GlyphStack->code; - t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j]; - t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize; - } else { - ++t3Font->cacheTags[i+j].mru; - } - } - - // save state - t3GlyphStack->origBitmap = bitmap; - t3GlyphStack->origSplash = splash; - ctm = state->getCTM(); - t3GlyphStack->origCTM4 = ctm[4]; - t3GlyphStack->origCTM5 = ctm[5]; - - // create the temporary bitmap - if (colorMode == splashModeMono1) { - bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, - splashModeMono1); - splash = new Splash(bitmap); - color[0] = 0; - splash->clear(color); - color[0] = 1; - } else { - bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, - splashModeMono8); - splash = new Splash(bitmap); - color[0] = 0x00; - splash->clear(color); - color[0] = 0xff; - } - splash->setFillPattern(new SplashSolidColor(color)); - splash->setStrokePattern(new SplashSolidColor(color)); - //~ this should copy other state from t3GlyphStack->origSplash? - state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], - -t3Font->glyphX, -t3Font->glyphY); -} - -void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font, - T3FontCacheTag */*tag*/, Guchar *data, - double x, double y) { - SplashGlyphBitmap glyph; - - glyph.x = -t3Font->glyphX; - glyph.y = -t3Font->glyphY; - glyph.w = t3Font->glyphW; - glyph.h = t3Font->glyphH; - glyph.aa = colorMode != splashModeMono1; - glyph.data = data; - glyph.freeData = gFalse; - splash->fillGlyph((SplashCoord)x, (SplashCoord)y, &glyph); -} - -void SplashOutputDev::endTextObject(GfxState */*state*/) { - if (textClipPath) { - splash->clipToPath(textClipPath, gFalse); - delete textClipPath; - textClipPath = NULL; - } -} - -struct SplashOutImageMaskData { - ImageStream *imgStr; - GBool invert; - int width, height, y; -}; - -GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) { - SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data; - Guchar *p; - SplashColorPtr q; - int x; - - if (imgMaskData->y == imgMaskData->height) { - return gFalse; - } - for (x = 0, p = imgMaskData->imgStr->getLine(), q = line; - x < imgMaskData->width; - ++x) { - *q++ = *p++ ^ imgMaskData->invert; - } - ++imgMaskData->y; - return gTrue; -} - -void SplashOutputDev::drawImageMask(GfxState *state, Object */*ref*/, Stream *str, - int width, int height, GBool invert, - GBool inlineImg) { - double *ctm; - SplashCoord mat[6]; - SplashOutImageMaskData imgMaskData; - - ctm = state->getCTM(); - mat[0] = ctm[0]; - mat[1] = ctm[1]; - mat[2] = -ctm[2]; - mat[3] = -ctm[3]; - mat[4] = ctm[2] + ctm[4]; - mat[5] = ctm[3] + ctm[5]; - - imgMaskData.imgStr = new ImageStream(str, width, 1, 1); - imgMaskData.imgStr->reset(); - imgMaskData.invert = invert ? 0 : 1; - imgMaskData.width = width; - imgMaskData.height = height; - imgMaskData.y = 0; - - splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat); - if (inlineImg) { - while (imgMaskData.y < height) { - imgMaskData.imgStr->getLine(); - ++imgMaskData.y; - } - } - - delete imgMaskData.imgStr; - str->close(); -} - -struct SplashOutImageData { - ImageStream *imgStr; - GfxImageColorMap *colorMap; - SplashColorPtr lookup; - int *maskColors; - SplashColorMode colorMode; - int width, height, y; -}; - -GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr line) { - SplashOutImageData *imgData = (SplashOutImageData *)data; - Guchar *p; - SplashColorPtr q, col; - GfxRGB rgb; - GfxGray gray; -#if SPLASH_CMYK - GfxCMYK cmyk; -#endif - int nComps, x; - - if (imgData->y == imgData->height) { - return gFalse; - } - - nComps = imgData->colorMap->getNumPixelComps(); - - if (imgData->lookup) { - switch (imgData->colorMode) { - case splashModeMono1: - case splashModeMono8: - for (x = 0, p = imgData->imgStr->getLine(), q = line; - x < imgData->width; - ++x, ++p) { - *q++ = imgData->lookup[*p]; - } - break; - case splashModeRGB8: - case splashModeBGR8: - for (x = 0, p = imgData->imgStr->getLine(), q = line; - x < imgData->width; - ++x, ++p) { - col = &imgData->lookup[3 * *p]; - *q++ = col[0]; - *q++ = col[1]; - *q++ = col[2]; - } - break; -#if SPLASH_CMYK - case splashModeCMYK8: - for (x = 0, p = imgData->imgStr->getLine(), q = line; - x < imgData->width; - ++x, ++p) { - col = &imgData->lookup[4 * *p]; - *q++ = col[0]; - *q++ = col[1]; - *q++ = col[2]; - *q++ = col[3]; - } - break; -#endif - case splashModeAMono8: - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeACMYK8: -#endif - //~ unimplemented - break; - } - } else { - switch (imgData->colorMode) { - case splashModeMono1: - case splashModeMono8: - for (x = 0, p = imgData->imgStr->getLine(), q = line; - x < imgData->width; - ++x, p += nComps) { - imgData->colorMap->getGray(p, &gray); - *q++ = colToByte(gray); - } - break; - case splashModeRGB8: - for (x = 0, p = imgData->imgStr->getLine(), q = line; - x < imgData->width; - ++x, p += nComps) { - imgData->colorMap->getRGB(p, &rgb); - *q++ = colToByte(rgb.r); - *q++ = colToByte(rgb.g); - *q++ = colToByte(rgb.b); - } - break; - case splashModeBGR8: - for (x = 0, p = imgData->imgStr->getLine(), q = line; - x < imgData->width; - ++x, p += nComps) { - imgData->colorMap->getRGB(p, &rgb); - *q++ = colToByte(rgb.b); - *q++ = colToByte(rgb.g); - *q++ = colToByte(rgb.r); - } - break; -#if SPLASH_CMYK - case splashModeCMYK8: - for (x = 0, p = imgData->imgStr->getLine(), q = line; - x < imgData->width; - ++x, p += nComps) { - imgData->colorMap->getCMYK(p, &cmyk); - *q++ = colToByte(cmyk.c); - *q++ = colToByte(cmyk.m); - *q++ = colToByte(cmyk.y); - *q++ = colToByte(cmyk.k); - } - break; -#endif - case splashModeAMono8: - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeACMYK8: -#endif - //~ unimplemented - break; - } - } - - ++imgData->y; - return gTrue; -} - -GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr line) { - SplashOutImageData *imgData = (SplashOutImageData *)data; - Guchar *p; - SplashColorPtr q, col; - GfxRGB rgb; - GfxGray gray; -#if SPLASH_CMYK - GfxCMYK cmyk; -#endif - Guchar alpha; - int nComps, x, i; - - if (imgData->y == imgData->height) { - return gFalse; - } - - nComps = imgData->colorMap->getNumPixelComps(); - - for (x = 0, p = imgData->imgStr->getLine(), q = line; - x < imgData->width; - ++x, p += nComps) { - alpha = 0; - for (i = 0; i < nComps; ++i) { - if (p[i] < imgData->maskColors[2*i] || - p[i] > imgData->maskColors[2*i+1]) { - alpha = 0xff; - break; - } - } - if (imgData->lookup) { - switch (imgData->colorMode) { - case splashModeMono1: - case splashModeMono8: - *q++ = alpha; - *q++ = imgData->lookup[*p]; - break; - case splashModeRGB8: - *q++ = alpha; - col = &imgData->lookup[3 * *p]; - *q++ = col[0]; - *q++ = col[1]; - *q++ = col[2]; - break; - case splashModeBGR8: - col = &imgData->lookup[3 * *p]; - *q++ = col[0]; - *q++ = col[1]; - *q++ = col[2]; - *q++ = alpha; - break; -#if SPLASH_CMYK - case splashModeCMYK8: - *q++ = alpha; - col = &imgData->lookup[4 * *p]; - *q++ = col[0]; - *q++ = col[1]; - *q++ = col[2]; - *q++ = col[3]; - break; -#endif - case splashModeAMono8: - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeACMYK8: -#endif - //~ unimplemented - break; - } - } else { - switch (imgData->colorMode) { - case splashModeMono1: - case splashModeMono8: - imgData->colorMap->getGray(p, &gray); - *q++ = alpha; - *q++ = colToByte(gray); - break; - case splashModeRGB8: - imgData->colorMap->getRGB(p, &rgb); - *q++ = alpha; - *q++ = colToByte(rgb.r); - *q++ = colToByte(rgb.g); - *q++ = colToByte(rgb.b); - break; - case splashModeBGR8: - imgData->colorMap->getRGB(p, &rgb); - *q++ = colToByte(rgb.b); - *q++ = colToByte(rgb.g); - *q++ = colToByte(rgb.r); - *q++ = alpha; - break; -#if SPLASH_CMYK - case splashModeCMYK8: - imgData->colorMap->getCMYK(p, &cmyk); - *q++ = alpha; - *q++ = colToByte(cmyk.c); - *q++ = colToByte(cmyk.m); - *q++ = colToByte(cmyk.y); - *q++ = colToByte(cmyk.k); - break; -#endif - case splashModeAMono8: - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeACMYK8: -#endif - //~ unimplemented - break; - } - } - } - - ++imgData->y; - return gTrue; -} - -void SplashOutputDev::drawImage(GfxState *state, Object */*ref*/, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - int *maskColors, GBool inlineImg) { - double *ctm; - SplashCoord mat[6]; - SplashOutImageData imgData; - SplashColorMode srcMode; - SplashImageSource src; - GfxGray gray; - GfxRGB rgb; -#if SPLASH_CMYK - GfxCMYK cmyk; -#endif - Guchar pix; - int n, i; - - ctm = state->getCTM(); - mat[0] = ctm[0]; - mat[1] = ctm[1]; - mat[2] = -ctm[2]; - mat[3] = -ctm[3]; - mat[4] = ctm[2] + ctm[4]; - mat[5] = ctm[3] + ctm[5]; - - imgData.imgStr = new ImageStream(str, width, - colorMap->getNumPixelComps(), - colorMap->getBits()); - imgData.imgStr->reset(); - imgData.colorMap = colorMap; - imgData.maskColors = maskColors; - imgData.colorMode = colorMode; - imgData.width = width; - imgData.height = height; - imgData.y = 0; - - // special case for one-channel (monochrome/gray/separation) images: - // build a lookup table here - imgData.lookup = NULL; - if (colorMap->getNumPixelComps() == 1) { - n = 1 << colorMap->getBits(); - switch (colorMode) { - case splashModeMono1: - case splashModeMono8: - imgData.lookup = (SplashColorPtr)gmalloc(n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getGray(&pix, &gray); - imgData.lookup[i] = colToByte(gray); - } - break; - case splashModeRGB8: - imgData.lookup = (SplashColorPtr)gmalloc(3 * n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getRGB(&pix, &rgb); - imgData.lookup[3*i] = colToByte(rgb.r); - imgData.lookup[3*i+1] = colToByte(rgb.g); - imgData.lookup[3*i+2] = colToByte(rgb.b); - } - break; - case splashModeBGR8: - imgData.lookup = (SplashColorPtr)gmalloc(3 * n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getRGB(&pix, &rgb); - imgData.lookup[3*i] = colToByte(rgb.b); - imgData.lookup[3*i+1] = colToByte(rgb.g); - imgData.lookup[3*i+2] = colToByte(rgb.r); - } - break; -#if SPLASH_CMYK - case splashModeCMYK8: - imgData.lookup = (SplashColorPtr)gmalloc(4 * n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getCMYK(&pix, &cmyk); - imgData.lookup[4*i] = colToByte(cmyk.c); - imgData.lookup[4*i+1] = colToByte(cmyk.m); - imgData.lookup[4*i+2] = colToByte(cmyk.y); - imgData.lookup[4*i+3] = colToByte(cmyk.k); - } - break; -#endif - default: - //~ unimplemented - break; - } - } - - switch (colorMode) { - case splashModeMono1: - case splashModeMono8: - srcMode = maskColors ? splashModeAMono8 : splashModeMono8; - break; - case splashModeRGB8: - srcMode = maskColors ? splashModeARGB8 : splashModeRGB8; - break; - case splashModeBGR8: - srcMode = maskColors ? splashModeBGRA8 : splashModeBGR8; - break; -#if SPLASH_CMYK - case splashModeCMYK8: - srcMode = maskColors ? splashModeACMYK8 : splashModeCMYK8; - break; -#endif - default: - //~ unimplemented - srcMode = splashModeRGB8; - break; - } - src = maskColors ? &alphaImageSrc : &imageSrc; - splash->drawImage(src, &imgData, srcMode, width, height, mat); - if (inlineImg) { - while (imgData.y < height) { - imgData.imgStr->getLine(); - ++imgData.y; - } - } - - gfree(imgData.lookup); - delete imgData.imgStr; - str->close(); -} - -struct SplashOutMaskedImageData { - ImageStream *imgStr; - GfxImageColorMap *colorMap; - SplashBitmap *mask; - SplashColorPtr lookup; - SplashColorMode colorMode; - int width, height, y; -}; - -GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr line) { - SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data; - Guchar *p; - SplashColor maskColor; - SplashColorPtr q, col; - GfxRGB rgb; - GfxGray gray; -#if SPLASH_CMYK - GfxCMYK cmyk; -#endif - Guchar alpha; - int nComps, x; - - if (imgData->y == imgData->height) { - return gFalse; - } - - nComps = imgData->colorMap->getNumPixelComps(); - - for (x = 0, p = imgData->imgStr->getLine(), q = line; - x < imgData->width; - ++x, p += nComps) { - imgData->mask->getPixel(x, imgData->y, maskColor); - alpha = maskColor[0] ? 0xff : 0x00; - if (imgData->lookup) { - switch (imgData->colorMode) { - case splashModeMono1: - case splashModeMono8: - *q++ = alpha; - *q++ = imgData->lookup[*p]; - break; - case splashModeRGB8: - *q++ = alpha; - col = &imgData->lookup[3 * *p]; - *q++ = col[0]; - *q++ = col[1]; - *q++ = col[2]; - break; - case splashModeBGR8: - col = &imgData->lookup[3 * *p]; - *q++ = col[0]; - *q++ = col[1]; - *q++ = col[2]; - *q++ = alpha; - break; -#if SPLASH_CMYK - case splashModeCMYK8: - *q++ = alpha; - col = &imgData->lookup[4 * *p]; - *q++ = col[0]; - *q++ = col[1]; - *q++ = col[2]; - *q++ = col[3]; - break; -#endif - case splashModeAMono8: - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeACMYK8: -#endif - //~ unimplemented - break; - } - } else { - switch (imgData->colorMode) { - case splashModeMono1: - case splashModeMono8: - imgData->colorMap->getGray(p, &gray); - *q++ = alpha; - *q++ = colToByte(gray); - break; - case splashModeRGB8: - imgData->colorMap->getRGB(p, &rgb); - *q++ = alpha; - *q++ = colToByte(rgb.r); - *q++ = colToByte(rgb.g); - *q++ = colToByte(rgb.b); - break; - case splashModeBGR8: - imgData->colorMap->getRGB(p, &rgb); - *q++ = colToByte(rgb.b); - *q++ = colToByte(rgb.g); - *q++ = colToByte(rgb.r); - *q++ = alpha; - break; -#if SPLASH_CMYK - case splashModeCMYK8: - imgData->colorMap->getCMYK(p, &cmyk); - *q++ = alpha; - *q++ = colToByte(cmyk.c); - *q++ = colToByte(cmyk.m); - *q++ = colToByte(cmyk.y); - *q++ = colToByte(cmyk.k); - break; -#endif - case splashModeAMono8: - case splashModeARGB8: - case splashModeBGRA8: -#if SPLASH_CMYK - case splashModeACMYK8: -#endif - //~ unimplemented - break; - } - } - } - - ++imgData->y; - return gTrue; -} - -void SplashOutputDev::drawMaskedImage(GfxState *state, Object */*ref*/, - Stream *str, int width, int height, - GfxImageColorMap *colorMap, - Stream *maskStr, int maskWidth, - int maskHeight, GBool maskInvert) { - double *ctm; - SplashCoord mat[6]; - SplashOutMaskedImageData imgData; - SplashOutImageMaskData imgMaskData; - SplashColorMode srcMode; - SplashBitmap *maskBitmap; - Splash *maskSplash; - SplashColor maskColor; - GfxGray gray; - GfxRGB rgb; -#if SPLASH_CMYK - GfxCMYK cmyk; -#endif - Guchar pix; - int n, i; - - //----- scale the mask image to the same size as the source image - - mat[0] = (SplashCoord)width; - mat[1] = 0; - mat[2] = 0; - mat[3] = (SplashCoord)height; - mat[4] = 0; - mat[5] = 0; - imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, 1, 1); - imgMaskData.imgStr->reset(); - imgMaskData.invert = maskInvert ? 0 : 1; - imgMaskData.width = maskWidth; - imgMaskData.height = maskHeight; - imgMaskData.y = 0; - maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1); - maskSplash = new Splash(maskBitmap); - maskColor[0] = 0; - maskSplash->clear(maskColor); - maskColor[0] = 1; - maskSplash->setFillPattern(new SplashSolidColor(maskColor)); - maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData, - maskWidth, maskHeight, mat); - delete imgMaskData.imgStr; - maskStr->close(); - delete maskSplash; - - //----- draw the source image - - ctm = state->getCTM(); - mat[0] = ctm[0]; - mat[1] = ctm[1]; - mat[2] = -ctm[2]; - mat[3] = -ctm[3]; - mat[4] = ctm[2] + ctm[4]; - mat[5] = ctm[3] + ctm[5]; - - imgData.imgStr = new ImageStream(str, width, - colorMap->getNumPixelComps(), - colorMap->getBits()); - imgData.imgStr->reset(); - imgData.colorMap = colorMap; - imgData.mask = maskBitmap; - imgData.colorMode = colorMode; - imgData.width = width; - imgData.height = height; - imgData.y = 0; - - // special case for one-channel (monochrome/gray/separation) images: - // build a lookup table here - imgData.lookup = NULL; - if (colorMap->getNumPixelComps() == 1) { - n = 1 << colorMap->getBits(); - switch (colorMode) { - case splashModeMono1: - case splashModeMono8: - imgData.lookup = (SplashColorPtr)gmalloc(n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getGray(&pix, &gray); - imgData.lookup[i] = colToByte(gray); - } - break; - case splashModeRGB8: - imgData.lookup = (SplashColorPtr)gmalloc(3 * n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getRGB(&pix, &rgb); - imgData.lookup[3*i] = colToByte(rgb.r); - imgData.lookup[3*i+1] = colToByte(rgb.g); - imgData.lookup[3*i+2] = colToByte(rgb.b); - } - break; - case splashModeBGR8: - imgData.lookup = (SplashColorPtr)gmalloc(3 * n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getRGB(&pix, &rgb); - imgData.lookup[3*i] = colToByte(rgb.b); - imgData.lookup[3*i+1] = colToByte(rgb.g); - imgData.lookup[3*i+2] = colToByte(rgb.r); - } - break; -#if SPLASH_CMYK - case splashModeCMYK8: - imgData.lookup = (SplashColorPtr)gmalloc(4 * n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getCMYK(&pix, &cmyk); - imgData.lookup[4*i] = colToByte(cmyk.c); - imgData.lookup[4*i+1] = colToByte(cmyk.m); - imgData.lookup[4*i+2] = colToByte(cmyk.y); - imgData.lookup[4*i+3] = colToByte(cmyk.k); - } - break; -#endif - default: - //~ unimplemented - break; - } - } - - switch (colorMode) { - case splashModeMono1: - case splashModeMono8: - srcMode = splashModeAMono8; - break; - case splashModeRGB8: - srcMode = splashModeARGB8; - break; - case splashModeBGR8: - srcMode = splashModeBGRA8; - break; -#if SPLASH_CMYK - case splashModeCMYK8: - srcMode = splashModeACMYK8; - break; -#endif - default: - //~ unimplemented - srcMode = splashModeARGB8; - break; - } - splash->drawImage(&maskedImageSrc, &imgData, srcMode, width, height, mat); - - delete maskBitmap; - gfree(imgData.lookup); - delete imgData.imgStr; - str->close(); -} - -void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object */*ref*/, - Stream *str, int width, int height, - GfxImageColorMap *colorMap, - Stream *maskStr, - int maskWidth, int maskHeight, - GfxImageColorMap *maskColorMap) { - double *ctm; - SplashCoord mat[6]; - SplashOutImageData imgData; - SplashOutImageData imgMaskData; - SplashColorMode srcMode; - SplashBitmap *maskBitmap; - Splash *maskSplash; - SplashColor maskColor; - GfxGray gray; - GfxRGB rgb; -#if SPLASH_CMYK - GfxCMYK cmyk; -#endif - Guchar pix; - int n, i; - - ctm = state->getCTM(); - mat[0] = ctm[0]; - mat[1] = ctm[1]; - mat[2] = -ctm[2]; - mat[3] = -ctm[3]; - mat[4] = ctm[2] + ctm[4]; - mat[5] = ctm[3] + ctm[5]; - - //----- set up the soft mask - - imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, - maskColorMap->getNumPixelComps(), - maskColorMap->getBits()); - imgMaskData.imgStr->reset(); - imgMaskData.colorMap = maskColorMap; - imgMaskData.maskColors = NULL; - imgMaskData.colorMode = splashModeMono8; - imgMaskData.width = maskWidth; - imgMaskData.height = maskHeight; - imgMaskData.y = 0; - n = 1 << maskColorMap->getBits(); - imgMaskData.lookup = (SplashColorPtr)gmalloc(n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - maskColorMap->getGray(&pix, &gray); - imgMaskData.lookup[i] = colToByte(gray); - } - maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), - 1, splashModeMono8); - maskSplash = new Splash(maskBitmap); - maskColor[0] = 0; - maskSplash->clear(maskColor); - maskSplash->drawImage(&imageSrc, &imgMaskData, - splashModeMono8, maskWidth, maskHeight, mat); - delete imgMaskData.imgStr; - maskStr->close(); - gfree(imgMaskData.lookup); - delete maskSplash; - splash->setSoftMask(maskBitmap); - - //----- draw the source image - - imgData.imgStr = new ImageStream(str, width, - colorMap->getNumPixelComps(), - colorMap->getBits()); - imgData.imgStr->reset(); - imgData.colorMap = colorMap; - imgData.maskColors = NULL; - imgData.colorMode = colorMode; - imgData.width = width; - imgData.height = height; - imgData.y = 0; - - // special case for one-channel (monochrome/gray/separation) images: - // build a lookup table here - imgData.lookup = NULL; - if (colorMap->getNumPixelComps() == 1) { - n = 1 << colorMap->getBits(); - switch (colorMode) { - case splashModeMono1: - case splashModeMono8: - imgData.lookup = (SplashColorPtr)gmalloc(n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getGray(&pix, &gray); - imgData.lookup[i] = colToByte(gray); - } - break; - case splashModeRGB8: - imgData.lookup = (SplashColorPtr)gmalloc(3 * n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getRGB(&pix, &rgb); - imgData.lookup[3*i] = colToByte(rgb.r); - imgData.lookup[3*i+1] = colToByte(rgb.g); - imgData.lookup[3*i+2] = colToByte(rgb.b); - } - break; - case splashModeBGR8: - imgData.lookup = (SplashColorPtr)gmalloc(3 * n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getRGB(&pix, &rgb); - imgData.lookup[3*i] = colToByte(rgb.b); - imgData.lookup[3*i+1] = colToByte(rgb.g); - imgData.lookup[3*i+2] = colToByte(rgb.r); - } - break; -#if SPLASH_CMYK - case splashModeCMYK8: - imgData.lookup = (SplashColorPtr)gmalloc(4 * n); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - colorMap->getCMYK(&pix, &cmyk); - imgData.lookup[4*i] = colToByte(cmyk.c); - imgData.lookup[4*i+1] = colToByte(cmyk.m); - imgData.lookup[4*i+2] = colToByte(cmyk.y); - imgData.lookup[4*i+3] = colToByte(cmyk.k); - } - break; -#endif - default: - //~ unimplemented - break; - } - } - - switch (colorMode) { - case splashModeMono1: - case splashModeMono8: - srcMode = splashModeMono8; - break; - case splashModeRGB8: - srcMode = splashModeRGB8; - break; - case splashModeBGR8: - srcMode = splashModeBGR8; - break; -#if SPLASH_CMYK - case splashModeCMYK8: - srcMode = splashModeCMYK8; - break; -#endif - default: - //~ unimplemented - srcMode = splashModeRGB8; - break; - } - splash->drawImage(&imageSrc, &imgData, srcMode, width, height, mat); - - splash->setSoftMask(NULL); - gfree(imgData.lookup); - delete imgData.imgStr; - str->close(); -} - -void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA) { - splashColorCopy(paperColor, paperColorA); -} - -int SplashOutputDev::getBitmapWidth() { - return bitmap->getWidth(); -} - -int SplashOutputDev::getBitmapHeight() { - return bitmap->getHeight(); -} - -SplashBitmap *SplashOutputDev::takeBitmap() { - SplashBitmap *ret; - - ret = bitmap; - bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, bitmapTopDown); - return ret; -} - -void SplashOutputDev::getModRegion(int *xMin, int *yMin, - int *xMax, int *yMax) { - splash->getModRegion(xMin, yMin, xMax, yMax); -} - -void SplashOutputDev::clearModRegion() { - splash->clearModRegion(); -} - -void SplashOutputDev::setFillColor(int r, int g, int b) { - GfxRGB rgb; - GfxGray gray; -#if SPLASH_CMYK - GfxCMYK cmyk; -#endif - - rgb.r = byteToCol(r); - rgb.g = byteToCol(g); - rgb.b = byteToCol(b); - gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5); - if (gray > gfxColorComp1) { - gray = gfxColorComp1; - } -#if SPLASH_CMYK - cmyk.c = gfxColorComp1 - rgb.r; - cmyk.m = gfxColorComp1 - rgb.g; - cmyk.y = gfxColorComp1 - rgb.b; - cmyk.k = 0; - splash->setFillPattern(getColor(gray, &rgb, &cmyk)); -#else - splash->setFillPattern(getColor(gray, &rgb)); -#endif -} - -SplashFont *SplashOutputDev::getFont(GString *name, double *mat) { - DisplayFontParam *dfp; - Ref ref; - SplashOutFontFileID *id; - SplashFontFile *fontFile; - SplashFont *fontObj; - FoFiTrueType *ff; - Gushort *codeToGID; - Unicode u; - int cmap, i; - - for (i = 0; i < 16; ++i) { - if (!name->cmp(splashOutSubstFonts[i].name)) { - break; - } - } - if (i == 16) { - return NULL; - } - ref.num = i; - ref.gen = -1; - id = new SplashOutFontFileID(&ref); - - // check the font file cache - if ((fontFile = fontEngine->getFontFile(id))) { - delete id; - - // load the font file - } else { - dfp = globalParams->getDisplayFont(name); - if (dfp && dfp->kind == displayFontT1) { - SplashFontSrc *fontsrc = new SplashFontSrc; - fontsrc->setFile(dfp->t1.fileName, gFalse); - fontFile = fontEngine->loadType1Font(id, fontsrc, winAnsiEncoding); - } else if (dfp && dfp->kind == displayFontTT) { - if (!(ff = FoFiTrueType::load(dfp->tt.fileName->getCString()))) { - return NULL; - } - for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { - if ((ff->getCmapPlatform(cmap) == 3 && - ff->getCmapEncoding(cmap) == 1) || - ff->getCmapPlatform(cmap) == 0) { - break; - } - } - if (cmap == ff->getNumCmaps()) { - delete ff; - return NULL; - } - codeToGID = (Gushort *)gmallocn(256, sizeof(Gushort)); - for (i = 0; i < 256; ++i) { - codeToGID[i] = 0; - if (winAnsiEncoding[i] && - (u = globalParams->mapNameToUnicode(winAnsiEncoding[i]))) { - codeToGID[i] = ff->mapCodeToGID(cmap, u); - } - } - delete ff; - SplashFontSrc *fontsrc = new SplashFontSrc; - fontsrc->setFile(dfp->tt.fileName, gFalse); - fontFile = fontEngine->loadTrueTypeFont(id, fontsrc, codeToGID, 256); - } else { - return NULL; - } - } - - // create the scaled font - fontObj = fontEngine->getFont(fontFile, (SplashCoord *)mat); - - return fontObj; -} diff --git a/xpdf/xpdf/SplashOutputDev.h b/xpdf/xpdf/SplashOutputDev.h deleted file mode 100644 index 2cd66ab3c..000000000 --- a/xpdf/xpdf/SplashOutputDev.h +++ /dev/null @@ -1,222 +0,0 @@ -//======================================================================== -// -// SplashOutputDev.h -// -// Copyright 2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef SPLASHOUTPUTDEV_H -#define SPLASHOUTPUTDEV_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "SplashTypes.h" -#include "config.h" -#include "OutputDev.h" -#include "GfxState.h" - -class Gfx8BitFont; -class SplashBitmap; -class Splash; -class SplashPath; -class SplashPattern; -class SplashFontEngine; -class SplashFont; -class T3FontCache; -struct T3FontCacheTag; -struct T3GlyphStack; - -//------------------------------------------------------------------------ - -// number of Type 3 fonts to cache -#define splashOutT3FontCacheSize 8 - -//------------------------------------------------------------------------ -// SplashOutputDev -//------------------------------------------------------------------------ - -class SplashOutputDev: public OutputDev { -public: - - // Constructor. - SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, - GBool reverseVideoA, SplashColorPtr paperColorA, - GBool bitmapTopDownA = gTrue, - GBool allowAntialiasA = gTrue); - - // Destructor. - virtual ~SplashOutputDev(); - - //----- get info about output device - - // Does this device use upside-down coordinates? - // (Upside-down means (0,0) is the top left corner of the page.) - virtual GBool upsideDown() { return gTrue; } - - // Does this device use drawChar() or drawString()? - virtual GBool useDrawChar() { return gTrue; } - - // Does this device use beginType3Char/endType3Char? Otherwise, - // text in Type 3 fonts will be drawn with drawChar/drawString. - virtual GBool interpretType3Chars() { return gTrue; } - - //----- initialization and control - - // Start a page. - virtual void startPage(int pageNum, GfxState *state); - - // End a page. - virtual void endPage(); - - //----- link borders - virtual void drawLink(Link *link, Catalog *catalog); - - //----- save/restore graphics state - virtual void saveState(GfxState *state); - virtual void restoreState(GfxState *state); - - //----- update graphics state - virtual void updateAll(GfxState *state); - virtual void updateCTM(GfxState *state, double m11, double m12, - double m21, double m22, double m31, double m32); - virtual void updateLineDash(GfxState *state); - virtual void updateFlatness(GfxState *state); - virtual void updateLineJoin(GfxState *state); - virtual void updateLineCap(GfxState *state); - virtual void updateMiterLimit(GfxState *state); - virtual void updateLineWidth(GfxState *state); - virtual void updateFillColor(GfxState *state); - virtual void updateStrokeColor(GfxState *state); - virtual void updateBlendMode(GfxState *state); - virtual void updateFillOpacity(GfxState *state); - virtual void updateStrokeOpacity(GfxState *state); - - //----- update text state - virtual void updateFont(GfxState *state); - - //----- path painting - virtual void stroke(GfxState *state); - virtual void fill(GfxState *state); - virtual void eoFill(GfxState *state); - - //----- path clipping - virtual void clip(GfxState *state); - virtual void eoClip(GfxState *state); - - //----- text drawing - virtual void drawChar(GfxState *state, double x, double y, - double dx, double dy, - double originX, double originY, - CharCode code, int nBytes, Unicode *u, int uLen); - virtual GBool beginType3Char(GfxState *state, double x, double y, - double dx, double dy, - CharCode code, Unicode *u, int uLen); - virtual void endType3Char(GfxState *state); - virtual void endTextObject(GfxState *state); - - //----- image drawing - virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg); - virtual void drawImage(GfxState *state, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - int *maskColors, GBool inlineImg); - virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - Stream *maskStr, int maskWidth, int maskHeight, - GBool maskInvert); - virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - Stream *maskStr, - int maskWidth, int maskHeight, - GfxImageColorMap *maskColorMap); - - //----- Type 3 font operators - virtual void type3D0(GfxState *state, double wx, double wy); - virtual void type3D1(GfxState *state, double wx, double wy, - double llx, double lly, double urx, double ury); - - //----- special access - - // Called to indicate that a new PDF document has been loaded. - void startDoc(XRef *xrefA); - - void setPaperColor(SplashColorPtr paperColorA); - - GBool isReverseVideo() { return reverseVideo; } - void setReverseVideo(GBool reverseVideoA) { reverseVideo = reverseVideoA; } - - // Get the bitmap and its size. - SplashBitmap *getBitmap() { return bitmap; } - int getBitmapWidth(); - int getBitmapHeight(); - - // Returns the last rasterized bitmap, transferring ownership to the - // caller. - SplashBitmap *takeBitmap(); - - // Get the Splash object. - Splash *getSplash() { return splash; } - - // Get the modified region. - void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax); - - // Clear the modified region. - void clearModRegion(); - - // Set the Splash fill color. - void setFillColor(int r, int g, int b); - - // Get a font object for a Base-14 font, using the Latin-1 encoding. - SplashFont *getFont(GString *name, double *mat); - - SplashFont *getCurrentFont() { return font; } - -private: - -#if SPLASH_CMYK - SplashPattern *getColor(GfxGray gray, GfxRGB *rgb, GfxCMYK *cmyk); -#else - SplashPattern *getColor(GfxGray gray, GfxRGB *rgb); -#endif - SplashPath *convertPath(GfxState *state, GfxPath *path); - void drawType3Glyph(T3FontCache *t3Font, - T3FontCacheTag *tag, Guchar *data, - double x, double y); - static GBool imageMaskSrc(void *data, SplashColorPtr line); - static GBool imageSrc(void *data, SplashColorPtr line); - static GBool alphaImageSrc(void *data, SplashColorPtr line); - static GBool maskedImageSrc(void *data, SplashColorPtr line); - - SplashColorMode colorMode; - int bitmapRowPad; - GBool bitmapTopDown; - GBool allowAntialias; - GBool reverseVideo; // reverse video mode - SplashColor paperColor; // paper color - - XRef *xref; // xref table for current document - - SplashBitmap *bitmap; - Splash *splash; - SplashFontEngine *fontEngine; - - T3FontCache * // Type 3 font cache - t3FontCache[splashOutT3FontCacheSize]; - int nT3Fonts; // number of valid entries in t3FontCache - T3GlyphStack *t3GlyphStack; // Type 3 glyph context stack - - SplashFont *font; // current font - GBool needFontUpdate; // set when the font needs to be updated - SplashPath *textClipPath; // clipping path built with text object -}; - -#endif diff --git a/xpdf/xpdf/Stream-CCITT.h b/xpdf/xpdf/Stream-CCITT.h deleted file mode 100644 index a9b1d1ede..000000000 --- a/xpdf/xpdf/Stream-CCITT.h +++ /dev/null @@ -1,462 +0,0 @@ -#ifndef STREAM_CCITT_H -#define STREAM_CCITT_H -//======================================================================== -// -// Stream-CCITT.h -// -// Tables for CCITT Fax decoding. -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -struct CCITTCode { - short bits; - short n; -}; - -#define ccittEOL -2 - -//------------------------------------------------------------------------ -// 2D codes -//------------------------------------------------------------------------ - -#define twoDimPass 0 -#define twoDimHoriz 1 -#define twoDimVert0 2 -#define twoDimVertR1 3 -#define twoDimVertL1 4 -#define twoDimVertR2 5 -#define twoDimVertL2 6 -#define twoDimVertR3 7 -#define twoDimVertL3 8 - -// 1-7 bit codes -static CCITTCode twoDimTab1[128] = { - {-1, -1}, {-1, -1}, // 000000x - {7, twoDimVertL3}, // 0000010 - {7, twoDimVertR3}, // 0000011 - {6, twoDimVertL2}, {6, twoDimVertL2}, // 000010x - {6, twoDimVertR2}, {6, twoDimVertR2}, // 000011x - {4, twoDimPass}, {4, twoDimPass}, // 0001xxx - {4, twoDimPass}, {4, twoDimPass}, - {4, twoDimPass}, {4, twoDimPass}, - {4, twoDimPass}, {4, twoDimPass}, - {3, twoDimHoriz}, {3, twoDimHoriz}, // 001xxxx - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimVertL1}, {3, twoDimVertL1}, // 010xxxx - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, // 011xxxx - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {1, twoDimVert0}, {1, twoDimVert0}, // 1xxxxxx - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0} -}; - -//------------------------------------------------------------------------ -// white run lengths -//------------------------------------------------------------------------ - -// 11-12 bit codes (upper 7 bits are 0) -static CCITTCode whiteTab1[32] = { - {-1, -1}, // 00000 - {12, ccittEOL}, // 00001 - {-1, -1}, {-1, -1}, // 0001x - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 001xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 010xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 011xx - {11, 1792}, {11, 1792}, // 1000x - {12, 1984}, // 10010 - {12, 2048}, // 10011 - {12, 2112}, // 10100 - {12, 2176}, // 10101 - {12, 2240}, // 10110 - {12, 2304}, // 10111 - {11, 1856}, {11, 1856}, // 1100x - {11, 1920}, {11, 1920}, // 1101x - {12, 2368}, // 11100 - {12, 2432}, // 11101 - {12, 2496}, // 11110 - {12, 2560} // 11111 -}; - -// 1-9 bit codes -static CCITTCode whiteTab2[512] = { - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000000xx - {8, 29}, {8, 29}, // 00000010x - {8, 30}, {8, 30}, // 00000011x - {8, 45}, {8, 45}, // 00000100x - {8, 46}, {8, 46}, // 00000101x - {7, 22}, {7, 22}, {7, 22}, {7, 22}, // 0000011xx - {7, 23}, {7, 23}, {7, 23}, {7, 23}, // 0000100xx - {8, 47}, {8, 47}, // 00001010x - {8, 48}, {8, 48}, // 00001011x - {6, 13}, {6, 13}, {6, 13}, {6, 13}, // 000011xxx - {6, 13}, {6, 13}, {6, 13}, {6, 13}, - {7, 20}, {7, 20}, {7, 20}, {7, 20}, // 0001000xx - {8, 33}, {8, 33}, // 00010010x - {8, 34}, {8, 34}, // 00010011x - {8, 35}, {8, 35}, // 00010100x - {8, 36}, {8, 36}, // 00010101x - {8, 37}, {8, 37}, // 00010110x - {8, 38}, {8, 38}, // 00010111x - {7, 19}, {7, 19}, {7, 19}, {7, 19}, // 0001100xx - {8, 31}, {8, 31}, // 00011010x - {8, 32}, {8, 32}, // 00011011x - {6, 1}, {6, 1}, {6, 1}, {6, 1}, // 000111xxx - {6, 1}, {6, 1}, {6, 1}, {6, 1}, - {6, 12}, {6, 12}, {6, 12}, {6, 12}, // 001000xxx - {6, 12}, {6, 12}, {6, 12}, {6, 12}, - {8, 53}, {8, 53}, // 00100100x - {8, 54}, {8, 54}, // 00100101x - {7, 26}, {7, 26}, {7, 26}, {7, 26}, // 0010011xx - {8, 39}, {8, 39}, // 00101000x - {8, 40}, {8, 40}, // 00101001x - {8, 41}, {8, 41}, // 00101010x - {8, 42}, {8, 42}, // 00101011x - {8, 43}, {8, 43}, // 00101100x - {8, 44}, {8, 44}, // 00101101x - {7, 21}, {7, 21}, {7, 21}, {7, 21}, // 0010111xx - {7, 28}, {7, 28}, {7, 28}, {7, 28}, // 0011000xx - {8, 61}, {8, 61}, // 00110010x - {8, 62}, {8, 62}, // 00110011x - {8, 63}, {8, 63}, // 00110100x - {8, 0}, {8, 0}, // 00110101x - {8, 320}, {8, 320}, // 00110110x - {8, 384}, {8, 384}, // 00110111x - {5, 10}, {5, 10}, {5, 10}, {5, 10}, // 00111xxxx - {5, 10}, {5, 10}, {5, 10}, {5, 10}, - {5, 10}, {5, 10}, {5, 10}, {5, 10}, - {5, 10}, {5, 10}, {5, 10}, {5, 10}, - {5, 11}, {5, 11}, {5, 11}, {5, 11}, // 01000xxxx - {5, 11}, {5, 11}, {5, 11}, {5, 11}, - {5, 11}, {5, 11}, {5, 11}, {5, 11}, - {5, 11}, {5, 11}, {5, 11}, {5, 11}, - {7, 27}, {7, 27}, {7, 27}, {7, 27}, // 0100100xx - {8, 59}, {8, 59}, // 01001010x - {8, 60}, {8, 60}, // 01001011x - {9, 1472}, // 010011000 - {9, 1536}, // 010011001 - {9, 1600}, // 010011010 - {9, 1728}, // 010011011 - {7, 18}, {7, 18}, {7, 18}, {7, 18}, // 0100111xx - {7, 24}, {7, 24}, {7, 24}, {7, 24}, // 0101000xx - {8, 49}, {8, 49}, // 01010010x - {8, 50}, {8, 50}, // 01010011x - {8, 51}, {8, 51}, // 01010100x - {8, 52}, {8, 52}, // 01010101x - {7, 25}, {7, 25}, {7, 25}, {7, 25}, // 0101011xx - {8, 55}, {8, 55}, // 01011000x - {8, 56}, {8, 56}, // 01011001x - {8, 57}, {8, 57}, // 01011010x - {8, 58}, {8, 58}, // 01011011x - {6, 192}, {6, 192}, {6, 192}, {6, 192}, // 010111xxx - {6, 192}, {6, 192}, {6, 192}, {6, 192}, - {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, // 011000xxx - {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, - {8, 448}, {8, 448}, // 01100100x - {8, 512}, {8, 512}, // 01100101x - {9, 704}, // 011001100 - {9, 768}, // 011001101 - {8, 640}, {8, 640}, // 01100111x - {8, 576}, {8, 576}, // 01101000x - {9, 832}, // 011010010 - {9, 896}, // 011010011 - {9, 960}, // 011010100 - {9, 1024}, // 011010101 - {9, 1088}, // 011010110 - {9, 1152}, // 011010111 - {9, 1216}, // 011011000 - {9, 1280}, // 011011001 - {9, 1344}, // 011011010 - {9, 1408}, // 011011011 - {7, 256}, {7, 256}, {7, 256}, {7, 256}, // 0110111xx - {4, 2}, {4, 2}, {4, 2}, {4, 2}, // 0111xxxxx - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, // 1000xxxxx - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {5, 128}, {5, 128}, {5, 128}, {5, 128}, // 10010xxxx - {5, 128}, {5, 128}, {5, 128}, {5, 128}, - {5, 128}, {5, 128}, {5, 128}, {5, 128}, - {5, 128}, {5, 128}, {5, 128}, {5, 128}, - {5, 8}, {5, 8}, {5, 8}, {5, 8}, // 10011xxxx - {5, 8}, {5, 8}, {5, 8}, {5, 8}, - {5, 8}, {5, 8}, {5, 8}, {5, 8}, - {5, 8}, {5, 8}, {5, 8}, {5, 8}, - {5, 9}, {5, 9}, {5, 9}, {5, 9}, // 10100xxxx - {5, 9}, {5, 9}, {5, 9}, {5, 9}, - {5, 9}, {5, 9}, {5, 9}, {5, 9}, - {5, 9}, {5, 9}, {5, 9}, {5, 9}, - {6, 16}, {6, 16}, {6, 16}, {6, 16}, // 101010xxx - {6, 16}, {6, 16}, {6, 16}, {6, 16}, - {6, 17}, {6, 17}, {6, 17}, {6, 17}, // 101011xxx - {6, 17}, {6, 17}, {6, 17}, {6, 17}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, // 1011xxxxx - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 1100xxxxx - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {6, 14}, {6, 14}, {6, 14}, {6, 14}, // 110100xxx - {6, 14}, {6, 14}, {6, 14}, {6, 14}, - {6, 15}, {6, 15}, {6, 15}, {6, 15}, // 110101xxx - {6, 15}, {6, 15}, {6, 15}, {6, 15}, - {5, 64}, {5, 64}, {5, 64}, {5, 64}, // 11011xxxx - {5, 64}, {5, 64}, {5, 64}, {5, 64}, - {5, 64}, {5, 64}, {5, 64}, {5, 64}, - {5, 64}, {5, 64}, {5, 64}, {5, 64}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 1110xxxxx - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, // 1111xxxxx - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7} -}; - -//------------------------------------------------------------------------ -// black run lengths -//------------------------------------------------------------------------ - -// 10-13 bit codes (upper 6 bits are 0) -static CCITTCode blackTab1[128] = { - {-1, -1}, {-1, -1}, // 000000000000x - {12, ccittEOL}, {12, ccittEOL}, // 000000000001x - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000001xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000010xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000011xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000100xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000101xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000110xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000111xx - {11, 1792}, {11, 1792}, {11, 1792}, {11, 1792}, // 00000001000xx - {12, 1984}, {12, 1984}, // 000000010010x - {12, 2048}, {12, 2048}, // 000000010011x - {12, 2112}, {12, 2112}, // 000000010100x - {12, 2176}, {12, 2176}, // 000000010101x - {12, 2240}, {12, 2240}, // 000000010110x - {12, 2304}, {12, 2304}, // 000000010111x - {11, 1856}, {11, 1856}, {11, 1856}, {11, 1856}, // 00000001100xx - {11, 1920}, {11, 1920}, {11, 1920}, {11, 1920}, // 00000001101xx - {12, 2368}, {12, 2368}, // 000000011100x - {12, 2432}, {12, 2432}, // 000000011101x - {12, 2496}, {12, 2496}, // 000000011110x - {12, 2560}, {12, 2560}, // 000000011111x - {10, 18}, {10, 18}, {10, 18}, {10, 18}, // 0000001000xxx - {10, 18}, {10, 18}, {10, 18}, {10, 18}, - {12, 52}, {12, 52}, // 000000100100x - {13, 640}, // 0000001001010 - {13, 704}, // 0000001001011 - {13, 768}, // 0000001001100 - {13, 832}, // 0000001001101 - {12, 55}, {12, 55}, // 000000100111x - {12, 56}, {12, 56}, // 000000101000x - {13, 1280}, // 0000001010010 - {13, 1344}, // 0000001010011 - {13, 1408}, // 0000001010100 - {13, 1472}, // 0000001010101 - {12, 59}, {12, 59}, // 000000101011x - {12, 60}, {12, 60}, // 000000101100x - {13, 1536}, // 0000001011010 - {13, 1600}, // 0000001011011 - {11, 24}, {11, 24}, {11, 24}, {11, 24}, // 00000010111xx - {11, 25}, {11, 25}, {11, 25}, {11, 25}, // 00000011000xx - {13, 1664}, // 0000001100100 - {13, 1728}, // 0000001100101 - {12, 320}, {12, 320}, // 000000110011x - {12, 384}, {12, 384}, // 000000110100x - {12, 448}, {12, 448}, // 000000110101x - {13, 512}, // 0000001101100 - {13, 576}, // 0000001101101 - {12, 53}, {12, 53}, // 000000110111x - {12, 54}, {12, 54}, // 000000111000x - {13, 896}, // 0000001110010 - {13, 960}, // 0000001110011 - {13, 1024}, // 0000001110100 - {13, 1088}, // 0000001110101 - {13, 1152}, // 0000001110110 - {13, 1216}, // 0000001110111 - {10, 64}, {10, 64}, {10, 64}, {10, 64}, // 0000001111xxx - {10, 64}, {10, 64}, {10, 64}, {10, 64} -}; - -// 7-12 bit codes (upper 4 bits are 0) -static CCITTCode blackTab2[192] = { - {8, 13}, {8, 13}, {8, 13}, {8, 13}, // 00000100xxxx - {8, 13}, {8, 13}, {8, 13}, {8, 13}, - {8, 13}, {8, 13}, {8, 13}, {8, 13}, - {8, 13}, {8, 13}, {8, 13}, {8, 13}, - {11, 23}, {11, 23}, // 00000101000x - {12, 50}, // 000001010010 - {12, 51}, // 000001010011 - {12, 44}, // 000001010100 - {12, 45}, // 000001010101 - {12, 46}, // 000001010110 - {12, 47}, // 000001010111 - {12, 57}, // 000001011000 - {12, 58}, // 000001011001 - {12, 61}, // 000001011010 - {12, 256}, // 000001011011 - {10, 16}, {10, 16}, {10, 16}, {10, 16}, // 0000010111xx - {10, 17}, {10, 17}, {10, 17}, {10, 17}, // 0000011000xx - {12, 48}, // 000001100100 - {12, 49}, // 000001100101 - {12, 62}, // 000001100110 - {12, 63}, // 000001100111 - {12, 30}, // 000001101000 - {12, 31}, // 000001101001 - {12, 32}, // 000001101010 - {12, 33}, // 000001101011 - {12, 40}, // 000001101100 - {12, 41}, // 000001101101 - {11, 22}, {11, 22}, // 00000110111x - {8, 14}, {8, 14}, {8, 14}, {8, 14}, // 00000111xxxx - {8, 14}, {8, 14}, {8, 14}, {8, 14}, - {8, 14}, {8, 14}, {8, 14}, {8, 14}, - {8, 14}, {8, 14}, {8, 14}, {8, 14}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, // 0000100xxxxx - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, // 0000101xxxxx - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {9, 15}, {9, 15}, {9, 15}, {9, 15}, // 000011000xxx - {9, 15}, {9, 15}, {9, 15}, {9, 15}, - {12, 128}, // 000011001000 - {12, 192}, // 000011001001 - {12, 26}, // 000011001010 - {12, 27}, // 000011001011 - {12, 28}, // 000011001100 - {12, 29}, // 000011001101 - {11, 19}, {11, 19}, // 00001100111x - {11, 20}, {11, 20}, // 00001101000x - {12, 34}, // 000011010010 - {12, 35}, // 000011010011 - {12, 36}, // 000011010100 - {12, 37}, // 000011010101 - {12, 38}, // 000011010110 - {12, 39}, // 000011010111 - {11, 21}, {11, 21}, // 00001101100x - {12, 42}, // 000011011010 - {12, 43}, // 000011011011 - {10, 0}, {10, 0}, {10, 0}, {10, 0}, // 0000110111xx - {7, 12}, {7, 12}, {7, 12}, {7, 12}, // 0000111xxxxx - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12} -}; - -// 2-6 bit codes -static CCITTCode blackTab3[64] = { - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000xx - {6, 9}, // 000100 - {6, 8}, // 000101 - {5, 7}, {5, 7}, // 00011x - {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 0010xx - {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 0011xx - {3, 1}, {3, 1}, {3, 1}, {3, 1}, // 010xxx - {3, 1}, {3, 1}, {3, 1}, {3, 1}, - {3, 4}, {3, 4}, {3, 4}, {3, 4}, // 011xxx - {3, 4}, {3, 4}, {3, 4}, {3, 4}, - {2, 3}, {2, 3}, {2, 3}, {2, 3}, // 10xxxx - {2, 3}, {2, 3}, {2, 3}, {2, 3}, - {2, 3}, {2, 3}, {2, 3}, {2, 3}, - {2, 3}, {2, 3}, {2, 3}, {2, 3}, - {2, 2}, {2, 2}, {2, 2}, {2, 2}, // 11xxxx - {2, 2}, {2, 2}, {2, 2}, {2, 2}, - {2, 2}, {2, 2}, {2, 2}, {2, 2}, - {2, 2}, {2, 2}, {2, 2}, {2, 2} -}; -#endif diff --git a/xpdf/xpdf/Stream.cc b/xpdf/xpdf/Stream.cc deleted file mode 100644 index b54ebb071..000000000 --- a/xpdf/xpdf/Stream.cc +++ /dev/null @@ -1,4586 +0,0 @@ -//======================================================================== -// -// Stream.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#ifndef WIN32 -#include -#endif -#include -#include -#include "gmem.h" -#include "gfile.h" -#include "xpdf_config.h" -#include "Error.h" -#include "Object.h" -#include "Lexer.h" -#include "Decrypt.h" -#include "GfxState.h" -#include "Stream.h" -#include "JBIG2Stream.h" -#include "JPXStream.h" -#include "Stream-CCITT.h" -#include "DCTStream.h" -#include "UGString.h" - -#ifdef __DJGPP__ -static GBool setDJSYSFLAGS = gFalse; -#endif - -#ifdef VMS -#ifdef __GNUC__ -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 -#endif -#endif - -//------------------------------------------------------------------------ -// Stream (base class) -//------------------------------------------------------------------------ - -Stream::Stream() { - ref = 1; -} - -Stream::~Stream() { -} - -void Stream::close() { -} - -int Stream::getRawChar() { - error(-1, "Internal: called getRawChar() on non-predictor stream"); - return EOF; -} - -char *Stream::getLine(char *buf, int size) { - int i; - int c; - - if (lookChar() == EOF) - return NULL; - for (i = 0; i < size - 1; ++i) { - c = getChar(); - if (c == EOF || c == '\n') - break; - if (c == '\r') { - if ((c = lookChar()) == '\n') - getChar(); - break; - } - buf[i] = c; - } - buf[i] = '\0'; - return buf; -} - -GString *Stream::getPSFilter(int /*psLevel*/, const char */*indent*/) { - return new GString(); -} - -Stream *Stream::addFilters(Object *dict) { - Object obj, obj2; - Object params, params2; - Stream *str; - int i; - - str = this; - dict->dictLookup("Filter", &obj); - if (obj.isNull()) { - obj.free(); - dict->dictLookup("F", &obj); - } - dict->dictLookup("DecodeParms", ¶ms); - if (params.isNull()) { - params.free(); - dict->dictLookup("DP", ¶ms); - } - if (obj.isName()) { - str = makeFilter(obj.getName(), str, ¶ms); - } else if (obj.isArray()) { - for (i = 0; i < obj.arrayGetLength(); ++i) { - obj.arrayGet(i, &obj2); - if (params.isArray()) - params.arrayGet(i, ¶ms2); - else - params2.initNull(); - if (obj2.isName()) { - str = makeFilter(obj2.getName(), str, ¶ms2); - } else { - error(getPos(), "Bad filter name"); - str = new EOFStream(str); - } - obj2.free(); - params2.free(); - } - } else if (!obj.isNull()) { - error(getPos(), "Bad 'Filter' attribute in stream"); - } - obj.free(); - params.free(); - - return str; -} - -Stream *Stream::makeFilter(const char *name, Stream *str, Object *params) { - int pred; // parameters - int colors; - int bits; - int early; - int encoding; - GBool endOfLine, byteAlign, endOfBlock, black; - int columns, rows; - Object globals, obj; - - if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) { - str = new ASCIIHexStream(str); - } else if (!strcmp(name, "ASCII85Decode") || !strcmp(name, "A85")) { - str = new ASCII85Stream(str); - } else if (!strcmp(name, "LZWDecode") || !strcmp(name, "LZW")) { - pred = 1; - columns = 1; - colors = 1; - bits = 8; - early = 1; - if (params->isDict()) { - params->dictLookup("Predictor", &obj); - if (obj.isInt()) - pred = obj.getInt(); - obj.free(); - params->dictLookup("Columns", &obj); - if (obj.isInt()) - columns = obj.getInt(); - obj.free(); - params->dictLookup("Colors", &obj); - if (obj.isInt()) - colors = obj.getInt(); - obj.free(); - params->dictLookup("BitsPerComponent", &obj); - if (obj.isInt()) - bits = obj.getInt(); - obj.free(); - params->dictLookup("EarlyChange", &obj); - if (obj.isInt()) - early = obj.getInt(); - obj.free(); - } - str = new LZWStream(str, pred, columns, colors, bits, early); - } else if (!strcmp(name, "RunLengthDecode") || !strcmp(name, "RL")) { - str = new RunLengthStream(str); - } else if (!strcmp(name, "CCITTFaxDecode") || !strcmp(name, "CCF")) { - encoding = 0; - endOfLine = gFalse; - byteAlign = gFalse; - columns = 1728; - rows = 0; - endOfBlock = gTrue; - black = gFalse; - if (params->isDict()) { - params->dictLookup("K", &obj); - if (obj.isInt()) { - encoding = obj.getInt(); - } - obj.free(); - params->dictLookup("EndOfLine", &obj); - if (obj.isBool()) { - endOfLine = obj.getBool(); - } - obj.free(); - params->dictLookup("EncodedByteAlign", &obj); - if (obj.isBool()) { - byteAlign = obj.getBool(); - } - obj.free(); - params->dictLookup("Columns", &obj); - if (obj.isInt()) { - columns = obj.getInt(); - } - obj.free(); - params->dictLookup("Rows", &obj); - if (obj.isInt()) { - rows = obj.getInt(); - } - obj.free(); - params->dictLookup("EndOfBlock", &obj); - if (obj.isBool()) { - endOfBlock = obj.getBool(); - } - obj.free(); - params->dictLookup("BlackIs1", &obj); - if (obj.isBool()) { - black = obj.getBool(); - } - obj.free(); - } - str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign, - columns, rows, endOfBlock, black); - } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) { - str = new DCTStream(str); - } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) { - pred = 1; - columns = 1; - colors = 1; - bits = 8; - if (params->isDict()) { - params->dictLookup("Predictor", &obj); - if (obj.isInt()) - pred = obj.getInt(); - obj.free(); - params->dictLookup("Columns", &obj); - if (obj.isInt()) - columns = obj.getInt(); - obj.free(); - params->dictLookup("Colors", &obj); - if (obj.isInt()) - colors = obj.getInt(); - obj.free(); - params->dictLookup("BitsPerComponent", &obj); - if (obj.isInt()) - bits = obj.getInt(); - obj.free(); - } - str = new FlateStream(str, pred, columns, colors, bits); - } else if (!strcmp(name, "JBIG2Decode")) { - if (params->isDict()) { - params->dictLookup("JBIG2Globals", &globals); - } - str = new JBIG2Stream(str, &globals); - globals.free(); - } else if (!strcmp(name, "JPXDecode")) { - str = new JPXStream(str); - } else { - error(getPos(), "Unknown filter '%s'", name); - str = new EOFStream(str); - } - return str; -} - -//------------------------------------------------------------------------ -// BaseStream -//------------------------------------------------------------------------ - -BaseStream::BaseStream(Object *dictA) { - dict = *dictA; - decrypt = NULL; -} - -BaseStream::~BaseStream() { - dict.free(); - if (decrypt) - delete decrypt; -} - -void BaseStream::doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen) { - decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); -} - -//------------------------------------------------------------------------ -// FilterStream -//------------------------------------------------------------------------ - -FilterStream::FilterStream(Stream *strA) { - str = strA; -} - -FilterStream::~FilterStream() { -} - -void FilterStream::close() { - str->close(); -} - -void FilterStream::setPos(Guint /*pos*/, int /*dir*/) { - error(-1, "Internal: called setPos() on FilterStream"); -} - -//------------------------------------------------------------------------ -// ImageStream -//------------------------------------------------------------------------ - -ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) { - int imgLineSize; - - str = strA; - width = widthA; - nComps = nCompsA; - nBits = nBitsA; - - nVals = width * nComps; - if (nBits == 1) { - imgLineSize = (nVals + 7) & ~7; - } else { - imgLineSize = nVals; - } - imgLine = (Guchar *)gmallocn(imgLineSize, sizeof(Guchar)); - imgIdx = nVals; -} - -ImageStream::~ImageStream() { - gfree(imgLine); -} - -void ImageStream::reset() { - str->reset(); -} - -GBool ImageStream::getPixel(Guchar *pix) { - int i; - - if (imgIdx >= nVals) { - getLine(); - imgIdx = 0; - } - for (i = 0; i < nComps; ++i) { - pix[i] = imgLine[imgIdx++]; - } - return gTrue; -} - -Guchar *ImageStream::getLine() { - Gulong buf, bitMask; - int bits; - int c; - int i; - - if (nBits == 1) { - for (i = 0; i < nVals; i += 8) { - c = str->getChar(); - imgLine[i+0] = (Guchar)((c >> 7) & 1); - imgLine[i+1] = (Guchar)((c >> 6) & 1); - imgLine[i+2] = (Guchar)((c >> 5) & 1); - imgLine[i+3] = (Guchar)((c >> 4) & 1); - imgLine[i+4] = (Guchar)((c >> 3) & 1); - imgLine[i+5] = (Guchar)((c >> 2) & 1); - imgLine[i+6] = (Guchar)((c >> 1) & 1); - imgLine[i+7] = (Guchar)(c & 1); - } - } else if (nBits == 8) { - for (i = 0; i < nVals; ++i) { - imgLine[i] = str->getChar(); - } - } else { - bitMask = (1 << nBits) - 1; - buf = 0; - bits = 0; - for (i = 0; i < nVals; ++i) { - if (bits < nBits) { - buf = (buf << 8) | (str->getChar() & 0xff); - bits += 8; - } - imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); - bits -= nBits; - } - } - return imgLine; -} - -void ImageStream::skipLine() { - int n, i; - - n = (nVals * nBits + 7) >> 3; - for (i = 0; i < n; ++i) { - str->getChar(); - } -} - -//------------------------------------------------------------------------ -// StreamPredictor -//------------------------------------------------------------------------ - -StreamPredictor::StreamPredictor(Stream *strA, int predictorA, - int widthA, int nCompsA, int nBitsA) { - str = strA; - predictor = predictorA; - width = widthA; - nComps = nCompsA; - nBits = nBitsA; - predLine = NULL; - ok = gFalse; - - if (width <= 0 || nComps <= 0 || nBits <= 0 || - nComps >= INT_MAX / nBits || - width >= INT_MAX / nComps / nBits) - return; - - nVals = width * nComps; - if (nVals * nBits + 7 <= 0) - return; - pixBytes = (nComps * nBits + 7) >> 3; - rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; - if (rowBytes < 0) - return; - - predLine = (Guchar *)gmalloc(rowBytes); - memset(predLine, 0, rowBytes); - predIdx = rowBytes; - - ok = gTrue; -} - -StreamPredictor::~StreamPredictor() { - gfree(predLine); -} - -int StreamPredictor::lookChar() { - if (predIdx >= rowBytes) { - if (!getNextLine()) { - return EOF; - } - } - return predLine[predIdx]; -} - -int StreamPredictor::getChar() { - if (predIdx >= rowBytes) { - if (!getNextLine()) { - return EOF; - } - } - return predLine[predIdx++]; -} - -GBool StreamPredictor::getNextLine() { - int curPred; - Guchar upLeftBuf[gfxColorMaxComps * 2 + 1]; - int left, up, upLeft, p, pa, pb, pc; - int c; - Gulong inBuf, outBuf, bitMask; - int inBits, outBits; - int i, j, k, kk; - - // get PNG optimum predictor number - if (predictor >= 10) { - if ((curPred = str->getRawChar()) == EOF) { - return gFalse; - } - curPred += 10; - } else { - curPred = predictor; - } - - // read the raw line, apply PNG (byte) predictor - memset(upLeftBuf, 0, pixBytes + 1); - for (i = pixBytes; i < rowBytes; ++i) { - for (j = pixBytes; j > 0; --j) { - upLeftBuf[j] = upLeftBuf[j-1]; - } - upLeftBuf[0] = predLine[i]; - if ((c = str->getRawChar()) == EOF) { - if (i > pixBytes) { - // this ought to return false, but some (broken) PDF files - // contain truncated image data, and Adobe apparently reads the - // last partial line - break; - } - return gFalse; - } - switch (curPred) { - case 11: // PNG sub - predLine[i] = predLine[i - pixBytes] + (Guchar)c; - break; - case 12: // PNG up - predLine[i] = predLine[i] + (Guchar)c; - break; - case 13: // PNG average - predLine[i] = ((predLine[i - pixBytes] + predLine[i]) >> 1) + - (Guchar)c; - break; - case 14: // PNG Paeth - left = predLine[i - pixBytes]; - up = predLine[i]; - upLeft = upLeftBuf[pixBytes]; - p = left + up - upLeft; - if ((pa = p - left) < 0) - pa = -pa; - if ((pb = p - up) < 0) - pb = -pb; - if ((pc = p - upLeft) < 0) - pc = -pc; - if (pa <= pb && pa <= pc) - predLine[i] = left + (Guchar)c; - else if (pb <= pc) - predLine[i] = up + (Guchar)c; - else - predLine[i] = upLeft + (Guchar)c; - break; - case 10: // PNG none - default: // no predictor or TIFF predictor - predLine[i] = (Guchar)c; - break; - } - } - - // apply TIFF (component) predictor - if (predictor == 2) { - if (nBits == 1) { - inBuf = predLine[pixBytes - 1]; - for (i = pixBytes; i < rowBytes; i += 8) { - // 1-bit add is just xor - inBuf = (inBuf << 8) | predLine[i]; - predLine[i] ^= inBuf >> nComps; - } - } else if (nBits == 8) { - for (i = pixBytes; i < rowBytes; ++i) { - predLine[i] += predLine[i - nComps]; - } - } else { - memset(upLeftBuf, 0, nComps + 1); - bitMask = (1 << nBits) - 1; - inBuf = outBuf = 0; - inBits = outBits = 0; - j = k = pixBytes; - for (i = 0; i < width; ++i) { - for (kk = 0; kk < nComps; ++kk) { - if (inBits < nBits) { - inBuf = (inBuf << 8) | (predLine[j++] & 0xff); - inBits += 8; - } - upLeftBuf[kk] = (upLeftBuf[kk] + - (inBuf >> (inBits - nBits))) & bitMask; - inBits -= nBits; - outBuf = (outBuf << nBits) | upLeftBuf[kk]; - outBits += nBits; - if (outBits >= 8) { - predLine[k++] = (Guchar)(outBuf >> (outBits - 8)); - outBits -= 8; - } - } - } - if (outBits > 0) { - predLine[k++] = (Guchar)((outBuf << (8 - outBits)) + - (inBuf & ((1 << (8 - outBits)) - 1))); - } - } - } - - // reset to start of line - predIdx = pixBytes; - - return gTrue; -} - -//------------------------------------------------------------------------ -// FileStream -//------------------------------------------------------------------------ - -FileStream::FileStream(FILE *fA, Guint startA, GBool limitedA, - Guint lengthA, Object *dictA): - BaseStream(dictA) { - f = fA; - start = startA; - limited = limitedA; - length = lengthA; - bufPtr = bufEnd = buf; - bufPos = start; - savePos = 0; - saved = gFalse; -} - -FileStream::~FileStream() { - close(); -} - -Stream *FileStream::makeSubStream(Guint startA, GBool limitedA, - Guint lengthA, Object *dictA) { - return new FileStream(f, startA, limitedA, lengthA, dictA); -} - -void FileStream::reset() { -#if HAVE_FSEEKO - savePos = (Guint)ftello(f); - fseeko(f, start, SEEK_SET); -#elif HAVE_FSEEK64 - savePos = (Guint)ftell64(f); - fseek64(f, start, SEEK_SET); -#else - savePos = (Guint)ftell(f); - fseek(f, start, SEEK_SET); -#endif - saved = gTrue; - bufPtr = bufEnd = buf; - bufPos = start; - if (decrypt) - decrypt->reset(); -} - -void FileStream::close() { - if (saved) { -#if HAVE_FSEEKO - fseeko(f, savePos, SEEK_SET); -#elif HAVE_FSEEK64 - fseek64(f, savePos, SEEK_SET); -#else - fseek(f, savePos, SEEK_SET); -#endif - saved = gFalse; - } -} - -GBool FileStream::fillBuf() { - int n; - char *p; - - bufPos += bufEnd - buf; - bufPtr = bufEnd = buf; - if (limited && bufPos >= start + length) { - return gFalse; - } - if (limited && bufPos + fileStreamBufSize > start + length) { - n = start + length - bufPos; - } else { - n = fileStreamBufSize; - } - n = fread(buf, 1, n, f); - bufEnd = buf + n; - if (bufPtr >= bufEnd) { - return gFalse; - } - if (decrypt) { - for (p = buf; p < bufEnd; ++p) { - *p = (char)decrypt->decryptByte((Guchar)*p); - } - } - return gTrue; -} - -void FileStream::setPos(Guint pos, int dir) { - Guint size; - - if (dir >= 0) { -#if HAVE_FSEEKO - fseeko(f, pos, SEEK_SET); -#elif HAVE_FSEEK64 - fseek64(f, pos, SEEK_SET); -#else - fseek(f, pos, SEEK_SET); -#endif - bufPos = pos; - } else { -#if HAVE_FSEEKO - fseeko(f, 0, SEEK_END); - size = (Guint)ftello(f); -#elif HAVE_FSEEK64 - fseek64(f, 0, SEEK_END); - size = (Guint)ftell64(f); -#else - fseek(f, 0, SEEK_END); - size = (Guint)ftell(f); -#endif - if (pos > size) - pos = (Guint)size; -#ifdef __CYGWIN32__ - //~ work around a bug in cygwin's implementation of fseek - rewind(f); -#endif -#if HAVE_FSEEKO - fseeko(f, -(int)pos, SEEK_END); - bufPos = (Guint)ftello(f); -#elif HAVE_FSEEK64 - fseek64(f, -(int)pos, SEEK_END); - bufPos = (Guint)ftell64(f); -#else - fseek(f, -(int)pos, SEEK_END); - bufPos = (Guint)ftell(f); -#endif - } - bufPtr = bufEnd = buf; -} - -void FileStream::moveStart(int delta) { - start += delta; - bufPtr = bufEnd = buf; - bufPos = start; -} - -//------------------------------------------------------------------------ -// MemStream -//------------------------------------------------------------------------ - -MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA): - BaseStream(dictA) { - buf = bufA; - start = startA; - length = lengthA; - bufEnd = buf + start + length; - bufPtr = buf + start; - needFree = gFalse; -} - -MemStream::~MemStream() { - if (needFree) { - gfree(buf); - } -} - -Stream *MemStream::makeSubStream(Guint startA, GBool limited, - Guint lengthA, Object *dictA) { - MemStream *subStr; - Guint newLength; - - if (!limited || startA + lengthA > start + length) { - newLength = start + length - startA; - } else { - newLength = lengthA; - } - subStr = new MemStream(buf, startA, newLength, dictA); - return subStr; -} - -void MemStream::reset() { - bufPtr = buf + start; - if (decrypt) { - decrypt->reset(); - } -} - -void MemStream::close() { -} - -void MemStream::setPos(Guint pos, int dir) { - Guint i; - - if (dir >= 0) { - i = pos; - } else { - i = start + length - pos; - } - if (i < start) { - i = start; - } else if (i > start + length) { - i = start + length; - } - bufPtr = buf + i; -} - -void MemStream::moveStart(int delta) { - start += delta; - length -= delta; - bufPtr = buf + start; -} - -void MemStream::doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen) { - char *newBuf; - char *p, *q; - - this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen); - if (decrypt) { - newBuf = (char *)gmalloc(length); - for (p = buf + start, q = newBuf; p < bufEnd; ++p, ++q) { - *q = (char)decrypt->decryptByte((Guchar)*p); - } - bufEnd = newBuf + length; - bufPtr = newBuf + (bufPtr - (buf + start)); - start = 0; - buf = newBuf; - needFree = gTrue; - } -} - -//------------------------------------------------------------------------ -// EmbedStream -//------------------------------------------------------------------------ - -EmbedStream::EmbedStream(Stream *strA, Object *dictA, - GBool limitedA, Guint lengthA): - BaseStream(dictA) { - str = strA; - limited = limitedA; - length = lengthA; -} - -EmbedStream::~EmbedStream() { -} - -Stream *EmbedStream::makeSubStream(Guint /*start*/, GBool /*limitedA*/, - Guint /*lengthA*/, Object */*dictA*/) { - error(-1, "Internal: called makeSubStream() on EmbedStream"); - return NULL; -} - -int EmbedStream::getChar() { - if (limited && !length) { - return EOF; - } - --length; - return str->getChar(); -} - -int EmbedStream::lookChar() { - if (limited && !length) { - return EOF; - } - return str->lookChar(); -} - -void EmbedStream::setPos(Guint /*pos*/, int /*dir*/) { - error(-1, "Internal: called setPos() on EmbedStream"); -} - -Guint EmbedStream::getStart() { - error(-1, "Internal: called getStart() on EmbedStream"); - return 0; -} - -void EmbedStream::moveStart(int /*delta*/) { - error(-1, "Internal: called moveStart() on EmbedStream"); -} - -//------------------------------------------------------------------------ -// ASCIIHexStream -//------------------------------------------------------------------------ - -ASCIIHexStream::ASCIIHexStream(Stream *strA): - FilterStream(strA) { - buf = EOF; - eof = gFalse; -} - -ASCIIHexStream::~ASCIIHexStream() { - delete str; -} - -void ASCIIHexStream::reset() { - str->reset(); - buf = EOF; - eof = gFalse; -} - -int ASCIIHexStream::lookChar() { - int c1, c2, x; - - if (buf != EOF) - return buf; - if (eof) { - buf = EOF; - return EOF; - } - do { - c1 = str->getChar(); - } while (isspace(c1)); - if (c1 == '>') { - eof = gTrue; - buf = EOF; - return buf; - } - do { - c2 = str->getChar(); - } while (isspace(c2)); - if (c2 == '>') { - eof = gTrue; - c2 = '0'; - } - if (c1 >= '0' && c1 <= '9') { - x = (c1 - '0') << 4; - } else if (c1 >= 'A' && c1 <= 'F') { - x = (c1 - 'A' + 10) << 4; - } else if (c1 >= 'a' && c1 <= 'f') { - x = (c1 - 'a' + 10) << 4; - } else if (c1 == EOF) { - eof = gTrue; - x = 0; - } else { - error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c1); - x = 0; - } - if (c2 >= '0' && c2 <= '9') { - x += c2 - '0'; - } else if (c2 >= 'A' && c2 <= 'F') { - x += c2 - 'A' + 10; - } else if (c2 >= 'a' && c2 <= 'f') { - x += c2 - 'a' + 10; - } else if (c2 == EOF) { - eof = gTrue; - x = 0; - } else { - error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c2); - } - buf = x & 0xff; - return buf; -} - -GString *ASCIIHexStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("/ASCIIHexDecode filter\n"); - return s; -} - -GBool ASCIIHexStream::isBinary(GBool /*last*/) { - return str->isBinary(gFalse); -} - -//------------------------------------------------------------------------ -// ASCII85Stream -//------------------------------------------------------------------------ - -ASCII85Stream::ASCII85Stream(Stream *strA): - FilterStream(strA) { - index = n = 0; - eof = gFalse; -} - -ASCII85Stream::~ASCII85Stream() { - delete str; -} - -void ASCII85Stream::reset() { - str->reset(); - index = n = 0; - eof = gFalse; -} - -int ASCII85Stream::lookChar() { - int k; - Gulong t; - - if (index >= n) { - if (eof) - return EOF; - index = 0; - do { - c[0] = str->getChar(); - } while (Lexer::isSpace(c[0])); - if (c[0] == '~' || c[0] == EOF) { - eof = gTrue; - n = 0; - return EOF; - } else if (c[0] == 'z') { - b[0] = b[1] = b[2] = b[3] = 0; - n = 4; - } else { - for (k = 1; k < 5; ++k) { - do { - c[k] = str->getChar(); - } while (Lexer::isSpace(c[k])); - if (c[k] == '~' || c[k] == EOF) - break; - } - n = k - 1; - if (k < 5 && (c[k] == '~' || c[k] == EOF)) { - for (++k; k < 5; ++k) - c[k] = 0x21 + 84; - eof = gTrue; - } - t = 0; - for (k = 0; k < 5; ++k) - t = t * 85 + (c[k] - 0x21); - for (k = 3; k >= 0; --k) { - b[k] = (int)(t & 0xff); - t >>= 8; - } - } - } - return b[index]; -} - -GString *ASCII85Stream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("/ASCII85Decode filter\n"); - return s; -} - -GBool ASCII85Stream::isBinary(GBool /*last*/) { - return str->isBinary(gFalse); -} - -//------------------------------------------------------------------------ -// LZWStream -//------------------------------------------------------------------------ - -LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors, - int bits, int earlyA): - FilterStream(strA) { - if (predictor != 1) { - pred = new StreamPredictor(this, predictor, columns, colors, bits); - if (!pred->isOk()) { - delete pred; - pred = NULL; - } - } else { - pred = NULL; - } - early = earlyA; - eof = gFalse; - inputBits = 0; - clearTable(); -} - -LZWStream::~LZWStream() { - if (pred) { - delete pred; - } - delete str; -} - -int LZWStream::getChar() { - if (pred) { - return pred->getChar(); - } - if (eof) { - return EOF; - } - if (seqIndex >= seqLength) { - if (!processNextCode()) { - return EOF; - } - } - return seqBuf[seqIndex++]; -} - -int LZWStream::lookChar() { - if (pred) { - return pred->lookChar(); - } - if (eof) { - return EOF; - } - if (seqIndex >= seqLength) { - if (!processNextCode()) { - return EOF; - } - } - return seqBuf[seqIndex]; -} - -int LZWStream::getRawChar() { - if (eof) { - return EOF; - } - if (seqIndex >= seqLength) { - if (!processNextCode()) { - return EOF; - } - } - return seqBuf[seqIndex++]; -} - -void LZWStream::reset() { - str->reset(); - eof = gFalse; - inputBits = 0; - clearTable(); -} - -GBool LZWStream::processNextCode() { - int code; - int nextLength; - int i, j; - - // check for EOF - if (eof) { - return gFalse; - } - - // check for eod and clear-table codes - start: - code = getCode(); - if (code == EOF || code == 257) { - eof = gTrue; - return gFalse; - } - if (code == 256) { - clearTable(); - goto start; - } - if (nextCode >= 4097) { - error(getPos(), "Bad LZW stream - expected clear-table code"); - clearTable(); - } - - // process the next code - nextLength = seqLength + 1; - if (code < 256) { - seqBuf[0] = code; - seqLength = 1; - } else if (code < nextCode) { - seqLength = table[code].length; - for (i = seqLength - 1, j = code; i > 0; --i) { - seqBuf[i] = table[j].tail; - j = table[j].head; - } - seqBuf[0] = j; - } else if (code == nextCode) { - seqBuf[seqLength] = newChar; - ++seqLength; - } else { - error(getPos(), "Bad LZW stream - unexpected code"); - eof = gTrue; - return gFalse; - } - newChar = seqBuf[0]; - if (first) { - first = gFalse; - } else { - table[nextCode].length = nextLength; - table[nextCode].head = prevCode; - table[nextCode].tail = newChar; - ++nextCode; - if (nextCode + early == 512) - nextBits = 10; - else if (nextCode + early == 1024) - nextBits = 11; - else if (nextCode + early == 2048) - nextBits = 12; - } - prevCode = code; - - // reset buffer - seqIndex = 0; - - return gTrue; -} - -void LZWStream::clearTable() { - nextCode = 258; - nextBits = 9; - seqIndex = seqLength = 0; - first = gTrue; -} - -int LZWStream::getCode() { - int c; - int code; - - while (inputBits < nextBits) { - if ((c = str->getChar()) == EOF) - return EOF; - inputBuf = (inputBuf << 8) | (c & 0xff); - inputBits += 8; - } - code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1); - inputBits -= nextBits; - return code; -} - -GString *LZWStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2 || pred) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("<< "); - if (!early) { - s->append("/EarlyChange 0 "); - } - s->append(">> /LZWDecode filter\n"); - return s; -} - -GBool LZWStream::isBinary(GBool /*last*/) { - return str->isBinary(gTrue); -} - -//------------------------------------------------------------------------ -// RunLengthStream -//------------------------------------------------------------------------ - -RunLengthStream::RunLengthStream(Stream *strA): - FilterStream(strA) { - bufPtr = bufEnd = buf; - eof = gFalse; -} - -RunLengthStream::~RunLengthStream() { - delete str; -} - -void RunLengthStream::reset() { - str->reset(); - bufPtr = bufEnd = buf; - eof = gFalse; -} - -GString *RunLengthStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("/RunLengthDecode filter\n"); - return s; -} - -GBool RunLengthStream::isBinary(GBool /*last*/) { - return str->isBinary(gTrue); -} - -GBool RunLengthStream::fillBuf() { - int c; - int n, i; - - if (eof) - return gFalse; - c = str->getChar(); - if (c == 0x80 || c == EOF) { - eof = gTrue; - return gFalse; - } - if (c < 0x80) { - n = c + 1; - for (i = 0; i < n; ++i) - buf[i] = (char)str->getChar(); - } else { - n = 0x101 - c; - c = str->getChar(); - for (i = 0; i < n; ++i) - buf[i] = (char)c; - } - bufPtr = buf; - bufEnd = buf + n; - return gTrue; -} - -//------------------------------------------------------------------------ -// CCITTFaxStream -//------------------------------------------------------------------------ - -CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, - GBool byteAlignA, int columnsA, int rowsA, - GBool endOfBlockA, GBool blackA): - FilterStream(strA) { - encoding = encodingA; - endOfLine = endOfLineA; - byteAlign = byteAlignA; - columns = columnsA; - if (columns < 1 || columns >= INT_MAX / sizeof(short)) { - error(getPos(), "Bad number of columns in CCITTFaxStream"); - exit(1); - } - rows = rowsA; - endOfBlock = endOfBlockA; - black = blackA; - refLine = (short *)gmallocn(columns + 4, sizeof(short)); - codingLine = (short *)gmallocn(columns + 3, sizeof(short)); - - eof = gFalse; - row = 0; - nextLine2D = encoding < 0; - inputBits = 0; - codingLine[0] = 0; - codingLine[1] = refLine[2] = columns; - a0 = 1; - - buf = EOF; -} - -CCITTFaxStream::~CCITTFaxStream() { - delete str; - gfree(refLine); - gfree(codingLine); -} - -void CCITTFaxStream::reset() { - short code1; - - str->reset(); - eof = gFalse; - row = 0; - nextLine2D = encoding < 0; - inputBits = 0; - codingLine[0] = 0; - codingLine[1] = refLine[2] = columns; - a0 = 1; - buf = EOF; - - // skip any initial zero bits and end-of-line marker, and get the 2D - // encoding tag - while ((code1 = lookBits(12)) == 0) { - eatBits(1); - } - if (code1 == 0x001) { - eatBits(12); - } - if (encoding > 0) { - nextLine2D = !lookBits(1); - eatBits(1); - } -} - -int CCITTFaxStream::lookChar() { - short code1, code2, code3; - int a0New; - GBool err, gotEOL; - int ret; - int bits, i; - - // if at eof just return EOF - if (eof && codingLine[a0] >= columns) { - return EOF; - } - - // read the next row - err = gFalse; - if (codingLine[a0] >= columns) { - - // 2-D encoding - if (nextLine2D) { - for (i = 0; codingLine[i] < columns; ++i) - refLine[i] = codingLine[i]; - refLine[i] = refLine[i + 1] = columns; - b1 = 1; - a0New = codingLine[a0 = 0] = 0; - do { - code1 = getTwoDimCode(); - switch (code1) { - case twoDimPass: - if (refLine[b1] < columns) { - a0New = refLine[b1 + 1]; - b1 += 2; - } - break; - case twoDimHoriz: - if ((a0 & 1) == 0) { - code1 = code2 = 0; - do { - code1 += code3 = getWhiteCode(); - } while (code3 >= 64); - do { - code2 += code3 = getBlackCode(); - } while (code3 >= 64); - } else { - code1 = code2 = 0; - do { - code1 += code3 = getBlackCode(); - } while (code3 >= 64); - do { - code2 += code3 = getWhiteCode(); - } while (code3 >= 64); - } - if (code1 > 0 || code2 > 0) { - codingLine[a0 + 1] = a0New + code1; - ++a0; - a0New = codingLine[a0 + 1] = codingLine[a0] + code2; - ++a0; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVert0: - a0New = codingLine[++a0] = refLine[b1]; - if (refLine[b1] < columns) { - ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVertR1: - a0New = codingLine[++a0] = refLine[b1] + 1; - if (refLine[b1] < columns) { - ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVertL1: - if (a0 == 0 || refLine[b1] - 1 > a0New) { - a0New = codingLine[++a0] = refLine[b1] - 1; - --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVertR2: - a0New = codingLine[++a0] = refLine[b1] + 2; - if (refLine[b1] < columns) { - ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVertL2: - if (a0 == 0 || refLine[b1] - 2 > a0New) { - a0New = codingLine[++a0] = refLine[b1] - 2; - --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVertR3: - a0New = codingLine[++a0] = refLine[b1] + 3; - if (refLine[b1] < columns) { - ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVertL3: - if (a0 == 0 || refLine[b1] - 3 > a0New) { - a0New = codingLine[++a0] = refLine[b1] - 3; - --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case EOF: - eof = gTrue; - codingLine[a0 = 0] = columns; - return EOF; - default: - error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1); - err = gTrue; - break; - } - } while (codingLine[a0] < columns); - - // 1-D encoding - } else { - codingLine[a0 = 0] = 0; - while (1) { - code1 = 0; - do { - code1 += code3 = getWhiteCode(); - } while (code3 >= 64); - codingLine[a0+1] = codingLine[a0] + code1; - ++a0; - if (codingLine[a0] >= columns) - break; - code2 = 0; - do { - code2 += code3 = getBlackCode(); - } while (code3 >= 64); - codingLine[a0+1] = codingLine[a0] + code2; - ++a0; - if (codingLine[a0] >= columns) - break; - } - } - - if (codingLine[a0] != columns) { - error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]); - // force the row to be the correct length - while (codingLine[a0] > columns) { - --a0; - } - codingLine[++a0] = columns; - err = gTrue; - } - - // byte-align the row - if (byteAlign) { - inputBits &= ~7; - } - - // check for end-of-line marker, skipping over any extra zero bits - gotEOL = gFalse; - if (!endOfBlock && row == rows - 1) { - eof = gTrue; - } else { - code1 = lookBits(12); - while (code1 == 0) { - eatBits(1); - code1 = lookBits(12); - } - if (code1 == 0x001) { - eatBits(12); - gotEOL = gTrue; - } else if (code1 == EOF) { - eof = gTrue; - } - } - - // get 2D encoding tag - if (!eof && encoding > 0) { - nextLine2D = !lookBits(1); - eatBits(1); - } - - // check for end-of-block marker - if (endOfBlock && gotEOL) { - code1 = lookBits(12); - if (code1 == 0x001) { - eatBits(12); - if (encoding > 0) { - lookBits(1); - eatBits(1); - } - if (encoding >= 0) { - for (i = 0; i < 4; ++i) { - code1 = lookBits(12); - if (code1 != 0x001) { - error(getPos(), "Bad RTC code in CCITTFax stream"); - } - eatBits(12); - if (encoding > 0) { - lookBits(1); - eatBits(1); - } - } - } - eof = gTrue; - } - - // look for an end-of-line marker after an error -- we only do - // this if we know the stream contains end-of-line markers because - // the "just plow on" technique tends to work better otherwise - } else if (err && endOfLine) { - do { - if (code1 == EOF) { - eof = gTrue; - return EOF; - } - eatBits(1); - code1 = lookBits(13); - } while ((code1 >> 1) != 0x001); - eatBits(12); - if (encoding > 0) { - eatBits(1); - nextLine2D = !(code1 & 1); - } - } - - a0 = 0; - outputBits = codingLine[1] - codingLine[0]; - if (outputBits == 0) { - a0 = 1; - outputBits = codingLine[2] - codingLine[1]; - } - - ++row; - } - - // get a byte - if (outputBits >= 8) { - ret = ((a0 & 1) == 0) ? 0xff : 0x00; - if ((outputBits -= 8) == 0) { - ++a0; - if (codingLine[a0] < columns) { - outputBits = codingLine[a0 + 1] - codingLine[a0]; - } - } - } else { - bits = 8; - ret = 0; - do { - if (outputBits > bits) { - i = bits; - bits = 0; - if ((a0 & 1) == 0) { - ret |= 0xff >> (8 - i); - } - outputBits -= i; - } else { - i = outputBits; - bits -= outputBits; - if ((a0 & 1) == 0) { - ret |= (0xff >> (8 - i)) << bits; - } - outputBits = 0; - ++a0; - if (codingLine[a0] < columns) { - outputBits = codingLine[a0 + 1] - codingLine[a0]; - } - } - } while (bits > 0 && codingLine[a0] < columns); - } - buf = black ? (ret ^ 0xff) : ret; - return buf; -} - -short CCITTFaxStream::getTwoDimCode() { - short code; - CCITTCode *p; - int n; - - code = 0; // make gcc happy - if (endOfBlock) { - code = lookBits(7); - p = &twoDimTab1[code]; - if (p->bits > 0) { - eatBits(p->bits); - return p->n; - } - } else { - for (n = 1; n <= 7; ++n) { - code = lookBits(n); - if (n < 7) { - code <<= 7 - n; - } - p = &twoDimTab1[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - error(getPos(), "Bad two dim code (%04x) in CCITTFax stream", code); - return EOF; -} - -short CCITTFaxStream::getWhiteCode() { - short code; - CCITTCode *p; - int n; - - code = 0; // make gcc happy - if (endOfBlock) { - code = lookBits(12); - if ((code >> 5) == 0) { - p = &whiteTab1[code]; - } else { - p = &whiteTab2[code >> 3]; - } - if (p->bits > 0) { - eatBits(p->bits); - return p->n; - } - } else { - for (n = 1; n <= 9; ++n) { - code = lookBits(n); - if (n < 9) { - code <<= 9 - n; - } - p = &whiteTab2[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - for (n = 11; n <= 12; ++n) { - code = lookBits(n); - if (n < 12) { - code <<= 12 - n; - } - p = &whiteTab1[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - error(getPos(), "Bad white code (%04x) in CCITTFax stream", code); - // eat a bit and return a positive number so that the caller doesn't - // go into an infinite loop - eatBits(1); - return 1; -} - -short CCITTFaxStream::getBlackCode() { - short code; - CCITTCode *p; - int n; - - code = 0; // make gcc happy - if (endOfBlock) { - code = lookBits(13); - if ((code >> 7) == 0) { - p = &blackTab1[code]; - } else if ((code >> 9) == 0) { - p = &blackTab2[(code >> 1) - 64]; - } else { - p = &blackTab3[code >> 7]; - } - if (p->bits > 0) { - eatBits(p->bits); - return p->n; - } - } else { - for (n = 2; n <= 6; ++n) { - code = lookBits(n); - if (n < 6) { - code <<= 6 - n; - } - p = &blackTab3[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - for (n = 7; n <= 12; ++n) { - code = lookBits(n); - if (n < 12) { - code <<= 12 - n; - } - if (code >= 64) { - p = &blackTab2[code - 64]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - for (n = 10; n <= 13; ++n) { - code = lookBits(n); - if (n < 13) { - code <<= 13 - n; - } - p = &blackTab1[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - error(getPos(), "Bad black code (%04x) in CCITTFax stream", code); - // eat a bit and return a positive number so that the caller doesn't - // go into an infinite loop - eatBits(1); - return 1; -} - -short CCITTFaxStream::lookBits(int n) { - int c; - - while (inputBits < n) { - if ((c = str->getChar()) == EOF) { - if (inputBits == 0) { - return EOF; - } - // near the end of the stream, the caller may ask for more bits - // than are available, but there may still be a valid code in - // however many bits are available -- we need to return correct - // data in this case - return (inputBuf << (n - inputBits)) & (0xffff >> (16 - n)); - } - inputBuf = (inputBuf << 8) + c; - inputBits += 8; - } - return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n)); -} - -GString *CCITTFaxStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - char s1[50]; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("<< "); - if (encoding != 0) { - sprintf(s1, "/K %d ", encoding); - s->append(s1); - } - if (endOfLine) { - s->append("/EndOfLine true "); - } - if (byteAlign) { - s->append("/EncodedByteAlign true "); - } - sprintf(s1, "/Columns %d ", columns); - s->append(s1); - if (rows != 0) { - sprintf(s1, "/Rows %d ", rows); - s->append(s1); - } - if (!endOfBlock) { - s->append("/EndOfBlock false "); - } - if (black) { - s->append("/BlackIs1 true "); - } - s->append(">> /CCITTFaxDecode filter\n"); - return s; -} - -GBool CCITTFaxStream::isBinary(GBool /*last*/) { - return str->isBinary(gTrue); -} - -#if 0 - -//------------------------------------------------------------------------ -// DCTStream -//------------------------------------------------------------------------ - -// IDCT constants (20.12 fixed point format) -#define dctCos1 4017 // cos(pi/16) -#define dctSin1 799 // sin(pi/16) -#define dctCos3 3406 // cos(3*pi/16) -#define dctSin3 2276 // sin(3*pi/16) -#define dctCos6 1567 // cos(6*pi/16) -#define dctSin6 3784 // sin(6*pi/16) -#define dctSqrt2 5793 // sqrt(2) -#define dctSqrt1d2 2896 // sqrt(2) / 2 - -// color conversion parameters (16.16 fixed point format) -#define dctCrToR 91881 // 1.4020 -#define dctCbToG -22553 // -0.3441363 -#define dctCrToG -46802 // -0.71413636 -#define dctCbToB 116130 // 1.772 - -// clip [-256,511] --> [0,255] -#define dctClipOffset 256 -static Guchar dctClip[768]; -static int dctClipInit = 0; - -// zig zag decode map -static int dctZigZag[64] = { - 0, - 1, 8, - 16, 9, 2, - 3, 10, 17, 24, - 32, 25, 18, 11, 4, - 5, 12, 19, 26, 33, 40, - 48, 41, 34, 27, 20, 13, 6, - 7, 14, 21, 28, 35, 42, 49, 56, - 57, 50, 43, 36, 29, 22, 15, - 23, 30, 37, 44, 51, 58, - 59, 52, 45, 38, 31, - 39, 46, 53, 60, - 61, 54, 47, - 55, 62, - 63 -}; - -DCTStream::DCTStream(Stream *strA): - FilterStream(strA) { - int i, j; - - progressive = interleaved = gFalse; - width = height = 0; - mcuWidth = mcuHeight = 0; - numComps = 0; - comp = 0; - x = y = dy = 0; - for (i = 0; i < 4; ++i) { - for (j = 0; j < 32; ++j) { - rowBuf[i][j] = NULL; - } - frameBuf[i] = NULL; - } - - if (!dctClipInit) { - for (i = -256; i < 0; ++i) - dctClip[dctClipOffset + i] = 0; - for (i = 0; i < 256; ++i) - dctClip[dctClipOffset + i] = i; - for (i = 256; i < 512; ++i) - dctClip[dctClipOffset + i] = 255; - dctClipInit = 1; - } -} - -DCTStream::~DCTStream() { - int i, j; - - delete str; - if (progressive || !interleaved) { - for (i = 0; i < numComps; ++i) { - gfree(frameBuf[i]); - } - } else { - for (i = 0; i < numComps; ++i) { - for (j = 0; j < mcuHeight; ++j) { - gfree(rowBuf[i][j]); - } - } - } -} - -void DCTStream::reset() { - int i, j; - - str->reset(); - - progressive = interleaved = gFalse; - width = height = 0; - numComps = 0; - numQuantTables = 0; - numDCHuffTables = 0; - numACHuffTables = 0; - colorXform = 0; - gotJFIFMarker = gFalse; - gotAdobeMarker = gFalse; - restartInterval = 0; - - if (!readHeader()) { - y = height; - return; - } - - // compute MCU size - if (numComps == 1) { - compInfo[0].hSample = compInfo[0].vSample = 1; - } - mcuWidth = compInfo[0].hSample; - mcuHeight = compInfo[0].vSample; - for (i = 1; i < numComps; ++i) { - if (compInfo[i].hSample > mcuWidth) { - mcuWidth = compInfo[i].hSample; - } - if (compInfo[i].vSample > mcuHeight) { - mcuHeight = compInfo[i].vSample; - } - } - mcuWidth *= 8; - mcuHeight *= 8; - - // figure out color transform - if (!gotAdobeMarker && numComps == 3) { - if (gotJFIFMarker) { - colorXform = 1; - } else if (compInfo[0].id == 82 && compInfo[1].id == 71 && - compInfo[2].id == 66) { // ASCII "RGB" - colorXform = 0; - } else { - colorXform = 1; - } - } - - if (progressive || !interleaved) { - - // allocate a buffer for the whole image - bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; - bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight; - for (i = 0; i < numComps; ++i) { - frameBuf[i] = (int *)gmallocn(bufWidth * bufHeight, sizeof(int)); - memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int)); - } - - // read the image data - do { - restartMarker = 0xd0; - restart(); - readScan(); - } while (readHeader()); - - // decode - decodeImage(); - - // initialize counters - comp = 0; - x = 0; - y = 0; - - } else { - - // allocate a buffer for one row of MCUs - bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; - for (i = 0; i < numComps; ++i) { - for (j = 0; j < mcuHeight; ++j) { - rowBuf[i][j] = (Guchar *)gmallocn(bufWidth, sizeof(Guchar)); - } - } - - // initialize counters - comp = 0; - x = 0; - y = 0; - dy = mcuHeight; - - restartMarker = 0xd0; - restart(); - } -} - -int DCTStream::getChar() { - int c; - - if (y >= height) { - return EOF; - } - if (progressive || !interleaved) { - c = frameBuf[comp][y * bufWidth + x]; - if (++comp == numComps) { - comp = 0; - if (++x == width) { - x = 0; - ++y; - } - } - } else { - if (dy >= mcuHeight) { - if (!readMCURow()) { - y = height; - return EOF; - } - comp = 0; - x = 0; - dy = 0; - } - c = rowBuf[comp][dy][x]; - if (++comp == numComps) { - comp = 0; - if (++x == width) { - x = 0; - ++y; - ++dy; - if (y == height) { - readTrailer(); - } - } - } - } - return c; -} - -int DCTStream::lookChar() { - if (y >= height) { - return EOF; - } - if (progressive || !interleaved) { - return frameBuf[comp][y * bufWidth + x]; - } else { - if (dy >= mcuHeight) { - if (!readMCURow()) { - y = height; - return EOF; - } - comp = 0; - x = 0; - dy = 0; - } - return rowBuf[comp][dy][x]; - } -} - -void DCTStream::restart() { - int i; - - inputBits = 0; - restartCtr = restartInterval; - for (i = 0; i < numComps; ++i) { - compInfo[i].prevDC = 0; - } - eobRun = 0; -} - -// Read one row of MCUs from a sequential JPEG stream. -GBool DCTStream::readMCURow() { - int data1[64]; - Guchar data2[64]; - Guchar *p1, *p2; - int pY, pCb, pCr, pR, pG, pB; - int h, v, horiz, vert, hSub, vSub; - int x1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; - int c; - - for (x1 = 0; x1 < width; x1 += mcuWidth) { - - // deal with restart marker - if (restartInterval > 0 && restartCtr == 0) { - c = readMarker(); - if (c != restartMarker) { - error(getPos(), "Bad DCT data: incorrect restart marker"); - return gFalse; - } - if (++restartMarker == 0xd8) - restartMarker = 0xd0; - restart(); - } - - // read one MCU - for (cc = 0; cc < numComps; ++cc) { - h = compInfo[cc].hSample; - v = compInfo[cc].vSample; - horiz = mcuWidth / h; - vert = mcuHeight / v; - hSub = horiz / 8; - vSub = vert / 8; - for (y2 = 0; y2 < mcuHeight; y2 += vert) { - for (x2 = 0; x2 < mcuWidth; x2 += horiz) { - if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], - &acHuffTables[scanInfo.acHuffTable[cc]], - &compInfo[cc].prevDC, - data1)) { - return gFalse; - } - transformDataUnit(quantTables[compInfo[cc].quantTable], - data1, data2); - if (hSub == 1 && vSub == 1) { - for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { - p1 = &rowBuf[cc][y2+y3][x1+x2]; - p1[0] = data2[i]; - p1[1] = data2[i+1]; - p1[2] = data2[i+2]; - p1[3] = data2[i+3]; - p1[4] = data2[i+4]; - p1[5] = data2[i+5]; - p1[6] = data2[i+6]; - p1[7] = data2[i+7]; - } - } else if (hSub == 2 && vSub == 2) { - for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { - p1 = &rowBuf[cc][y2+y3][x1+x2]; - p2 = &rowBuf[cc][y2+y3+1][x1+x2]; - p1[0] = p1[1] = p2[0] = p2[1] = data2[i]; - p1[2] = p1[3] = p2[2] = p2[3] = data2[i+1]; - p1[4] = p1[5] = p2[4] = p2[5] = data2[i+2]; - p1[6] = p1[7] = p2[6] = p2[7] = data2[i+3]; - p1[8] = p1[9] = p2[8] = p2[9] = data2[i+4]; - p1[10] = p1[11] = p2[10] = p2[11] = data2[i+5]; - p1[12] = p1[13] = p2[12] = p2[13] = data2[i+6]; - p1[14] = p1[15] = p2[14] = p2[15] = data2[i+7]; - } - } else { - i = 0; - for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { - for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { - for (y5 = 0; y5 < vSub; ++y5) - for (x5 = 0; x5 < hSub; ++x5) - rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data2[i]; - ++i; - } - } - } - } - } - } - --restartCtr; - - // color space conversion - if (colorXform) { - // convert YCbCr to RGB - if (numComps == 3) { - for (y2 = 0; y2 < mcuHeight; ++y2) { - for (x2 = 0; x2 < mcuWidth; ++x2) { - pY = rowBuf[0][y2][x1+x2]; - pCb = rowBuf[1][y2][x1+x2] - 128; - pCr = rowBuf[2][y2][x1+x2] - 128; - pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; - rowBuf[0][y2][x1+x2] = dctClip[dctClipOffset + pR]; - pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; - rowBuf[1][y2][x1+x2] = dctClip[dctClipOffset + pG]; - pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; - rowBuf[2][y2][x1+x2] = dctClip[dctClipOffset + pB]; - } - } - // convert YCbCrK to CMYK (K is passed through unchanged) - } else if (numComps == 4) { - for (y2 = 0; y2 < mcuHeight; ++y2) { - for (x2 = 0; x2 < mcuWidth; ++x2) { - pY = rowBuf[0][y2][x1+x2]; - pCb = rowBuf[1][y2][x1+x2] - 128; - pCr = rowBuf[2][y2][x1+x2] - 128; - pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; - rowBuf[0][y2][x1+x2] = 255 - dctClip[dctClipOffset + pR]; - pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; - rowBuf[1][y2][x1+x2] = 255 - dctClip[dctClipOffset + pG]; - pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; - rowBuf[2][y2][x1+x2] = 255 - dctClip[dctClipOffset + pB]; - } - } - } - } - } - return gTrue; -} - -// Read one scan from a progressive or non-interleaved JPEG stream. -void DCTStream::readScan() { - int data[64]; - int x1, y1, dx1, dy1, x2, y2, y3, cc, i; - int h, v, horiz, vert, vSub; - int *p1; - int c; - - if (scanInfo.numComps == 1) { - for (cc = 0; cc < numComps; ++cc) { - if (scanInfo.comp[cc]) { - break; - } - } - dx1 = mcuWidth / compInfo[cc].hSample; - dy1 = mcuHeight / compInfo[cc].vSample; - } else { - dx1 = mcuWidth; - dy1 = mcuHeight; - } - - for (y1 = 0; y1 < height; y1 += dy1) { - for (x1 = 0; x1 < width; x1 += dx1) { - - // deal with restart marker - if (restartInterval > 0 && restartCtr == 0) { - c = readMarker(); - if (c != restartMarker) { - error(getPos(), "Bad DCT data: incorrect restart marker"); - return; - } - if (++restartMarker == 0xd8) { - restartMarker = 0xd0; - } - restart(); - } - - // read one MCU - for (cc = 0; cc < numComps; ++cc) { - if (!scanInfo.comp[cc]) { - continue; - } - - h = compInfo[cc].hSample; - v = compInfo[cc].vSample; - horiz = mcuWidth / h; - vert = mcuHeight / v; - vSub = vert / 8; - for (y2 = 0; y2 < dy1; y2 += vert) { - for (x2 = 0; x2 < dx1; x2 += horiz) { - - // pull out the current values - p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; - for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { - data[i] = p1[0]; - data[i+1] = p1[1]; - data[i+2] = p1[2]; - data[i+3] = p1[3]; - data[i+4] = p1[4]; - data[i+5] = p1[5]; - data[i+6] = p1[6]; - data[i+7] = p1[7]; - p1 += bufWidth * vSub; - } - - // read one data unit - if (progressive) { - if (!readProgressiveDataUnit( - &dcHuffTables[scanInfo.dcHuffTable[cc]], - &acHuffTables[scanInfo.acHuffTable[cc]], - &compInfo[cc].prevDC, - data)) { - return; - } - } else { - if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], - &acHuffTables[scanInfo.acHuffTable[cc]], - &compInfo[cc].prevDC, - data)) { - return; - } - } - - // add the data unit into frameBuf - p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; - for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { - p1[0] = data[i]; - p1[1] = data[i+1]; - p1[2] = data[i+2]; - p1[3] = data[i+3]; - p1[4] = data[i+4]; - p1[5] = data[i+5]; - p1[6] = data[i+6]; - p1[7] = data[i+7]; - p1 += bufWidth * vSub; - } - } - } - } - --restartCtr; - } - } -} - -// Read one data unit from a sequential JPEG stream. -GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - int *prevDC, int data[64]) { - int run, size, amp; - int c; - int i, j; - - if ((size = readHuffSym(dcHuffTable)) == 9999) { - return gFalse; - } - if (size > 0) { - if ((amp = readAmp(size)) == 9999) { - return gFalse; - } - } else { - amp = 0; - } - data[0] = *prevDC += amp; - for (i = 1; i < 64; ++i) { - data[i] = 0; - } - i = 1; - while (i < 64) { - run = 0; - while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) { - run += 0x10; - } - if (c == 9999) { - return gFalse; - } - if (c == 0x00) { - break; - } else { - run += (c >> 4) & 0x0f; - size = c & 0x0f; - amp = readAmp(size); - if (amp == 9999) { - return gFalse; - } - i += run; - if (i < 64) { - j = dctZigZag[i++]; - data[j] = amp; - } - } - } - return gTrue; -} - -// Read one data unit from a sequential JPEG stream. -GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - int *prevDC, int data[64]) { - int run, size, amp, bit, c; - int i, j, k; - - // get the DC coefficient - i = scanInfo.firstCoeff; - if (i == 0) { - if (scanInfo.ah == 0) { - if ((size = readHuffSym(dcHuffTable)) == 9999) { - return gFalse; - } - if (size > 0) { - if ((amp = readAmp(size)) == 9999) { - return gFalse; - } - } else { - amp = 0; - } - data[0] += (*prevDC += amp) << scanInfo.al; - } else { - if ((bit = readBit()) == 9999) { - return gFalse; - } - data[0] += bit << scanInfo.al; - } - ++i; - } - if (scanInfo.lastCoeff == 0) { - return gTrue; - } - - // check for an EOB run - if (eobRun > 0) { - while (i <= scanInfo.lastCoeff) { - j = dctZigZag[i++]; - if (data[j] != 0) { - if ((bit = readBit()) == EOF) { - return gFalse; - } - if (bit) { - data[j] += 1 << scanInfo.al; - } - } - } - --eobRun; - return gTrue; - } - - // read the AC coefficients - while (i <= scanInfo.lastCoeff) { - if ((c = readHuffSym(acHuffTable)) == 9999) { - return gFalse; - } - - // ZRL - if (c == 0xf0) { - k = 0; - while (k < 16) { - j = dctZigZag[i++]; - if (data[j] == 0) { - ++k; - } else { - if ((bit = readBit()) == EOF) { - return gFalse; - } - if (bit) { - data[j] += 1 << scanInfo.al; - } - } - } - - // EOB run - } else if ((c & 0x0f) == 0x00) { - j = c >> 4; - eobRun = 0; - for (k = 0; k < j; ++k) { - if ((bit = readBit()) == EOF) { - return gFalse; - } - eobRun = (eobRun << 1) | bit; - } - eobRun += 1 << j; - while (i <= scanInfo.lastCoeff) { - j = dctZigZag[i++]; - if (data[j] != 0) { - if ((bit = readBit()) == EOF) { - return gFalse; - } - if (bit) { - data[j] += 1 << scanInfo.al; - } - } - } - --eobRun; - break; - - // zero run and one AC coefficient - } else { - run = (c >> 4) & 0x0f; - size = c & 0x0f; - if ((amp = readAmp(size)) == 9999) { - return gFalse; - } - k = 0; - do { - j = dctZigZag[i++]; - while (data[j] != 0) { - if ((bit = readBit()) == EOF) { - return gFalse; - } - if (bit) { - data[j] += 1 << scanInfo.al; - } - j = dctZigZag[i++]; - } - ++k; - } while (k <= run); - data[j] = amp << scanInfo.al; - } - } - - return gTrue; -} - -// Decode a progressive JPEG image. -void DCTStream::decodeImage() { - int dataIn[64]; - Guchar dataOut[64]; - Gushort *quantTable; - int pY, pCb, pCr, pR, pG, pB; - int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; - int h, v, horiz, vert, hSub, vSub; - int *p0, *p1, *p2; - - for (y1 = 0; y1 < bufHeight; y1 += mcuHeight) { - for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { - for (cc = 0; cc < numComps; ++cc) { - quantTable = quantTables[compInfo[cc].quantTable]; - h = compInfo[cc].hSample; - v = compInfo[cc].vSample; - horiz = mcuWidth / h; - vert = mcuHeight / v; - hSub = horiz / 8; - vSub = vert / 8; - for (y2 = 0; y2 < mcuHeight; y2 += vert) { - for (x2 = 0; x2 < mcuWidth; x2 += horiz) { - - // pull out the coded data unit - p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; - for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { - dataIn[i] = p1[0]; - dataIn[i+1] = p1[1]; - dataIn[i+2] = p1[2]; - dataIn[i+3] = p1[3]; - dataIn[i+4] = p1[4]; - dataIn[i+5] = p1[5]; - dataIn[i+6] = p1[6]; - dataIn[i+7] = p1[7]; - p1 += bufWidth * vSub; - } - - // transform - transformDataUnit(quantTable, dataIn, dataOut); - - // store back into frameBuf, doing replication for - // subsampled components - p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; - if (hSub == 1 && vSub == 1) { - for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { - p1[0] = dataOut[i] & 0xff; - p1[1] = dataOut[i+1] & 0xff; - p1[2] = dataOut[i+2] & 0xff; - p1[3] = dataOut[i+3] & 0xff; - p1[4] = dataOut[i+4] & 0xff; - p1[5] = dataOut[i+5] & 0xff; - p1[6] = dataOut[i+6] & 0xff; - p1[7] = dataOut[i+7] & 0xff; - p1 += bufWidth; - } - } else if (hSub == 2 && vSub == 2) { - p2 = p1 + bufWidth; - for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { - p1[0] = p1[1] = p2[0] = p2[1] = dataOut[i] & 0xff; - p1[2] = p1[3] = p2[2] = p2[3] = dataOut[i+1] & 0xff; - p1[4] = p1[5] = p2[4] = p2[5] = dataOut[i+2] & 0xff; - p1[6] = p1[7] = p2[6] = p2[7] = dataOut[i+3] & 0xff; - p1[8] = p1[9] = p2[8] = p2[9] = dataOut[i+4] & 0xff; - p1[10] = p1[11] = p2[10] = p2[11] = dataOut[i+5] & 0xff; - p1[12] = p1[13] = p2[12] = p2[13] = dataOut[i+6] & 0xff; - p1[14] = p1[15] = p2[14] = p2[15] = dataOut[i+7] & 0xff; - p1 += bufWidth * 2; - p2 += bufWidth * 2; - } - } else { - i = 0; - for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { - for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { - p2 = p1 + x4; - for (y5 = 0; y5 < vSub; ++y5) { - for (x5 = 0; x5 < hSub; ++x5) { - p2[x5] = dataOut[i] & 0xff; - } - p2 += bufWidth; - } - ++i; - } - p1 += bufWidth * vSub; - } - } - } - } - } - - // color space conversion - if (colorXform) { - // convert YCbCr to RGB - if (numComps == 3) { - for (y2 = 0; y2 < mcuHeight; ++y2) { - p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; - p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; - p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; - for (x2 = 0; x2 < mcuWidth; ++x2) { - pY = *p0; - pCb = *p1 - 128; - pCr = *p2 - 128; - pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; - *p0++ = dctClip[dctClipOffset + pR]; - pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + - 32768) >> 16; - *p1++ = dctClip[dctClipOffset + pG]; - pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; - *p2++ = dctClip[dctClipOffset + pB]; - } - } - // convert YCbCrK to CMYK (K is passed through unchanged) - } else if (numComps == 4) { - for (y2 = 0; y2 < mcuHeight; ++y2) { - p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; - p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; - p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; - for (x2 = 0; x2 < mcuWidth; ++x2) { - pY = *p0; - pCb = *p1 - 128; - pCr = *p2 - 128; - pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; - *p0++ = 255 - dctClip[dctClipOffset + pR]; - pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + - 32768) >> 16; - *p1++ = 255 - dctClip[dctClipOffset + pG]; - pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; - *p2++ = 255 - dctClip[dctClipOffset + pB]; - } - } - } - } - } - } -} - -// Transform one data unit -- this performs the dequantization and -// IDCT steps. This IDCT algorithm is taken from: -// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, -// "Practical Fast 1-D DCT Algorithms with 11 Multiplications", -// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, -// 988-991. -// The stage numbers mentioned in the comments refer to Figure 1 in this -// paper. -void DCTStream::transformDataUnit(Gushort *quantTable, - int dataIn[64], Guchar dataOut[64]) { - int v0, v1, v2, v3, v4, v5, v6, v7, t; - int *p; - int i; - - // dequant - for (i = 0; i < 64; ++i) { - dataIn[i] *= quantTable[i]; - } - - // inverse DCT on rows - for (i = 0; i < 64; i += 8) { - p = dataIn + i; - - // check for all-zero AC coefficients - if (p[1] == 0 && p[2] == 0 && p[3] == 0 && - p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] == 0) { - t = (dctSqrt2 * p[0] + 512) >> 10; - p[0] = t; - p[1] = t; - p[2] = t; - p[3] = t; - p[4] = t; - p[5] = t; - p[6] = t; - p[7] = t; - continue; - } - - // stage 4 - v0 = (dctSqrt2 * p[0] + 128) >> 8; - v1 = (dctSqrt2 * p[4] + 128) >> 8; - v2 = p[2]; - v3 = p[6]; - v4 = (dctSqrt1d2 * (p[1] - p[7]) + 128) >> 8; - v7 = (dctSqrt1d2 * (p[1] + p[7]) + 128) >> 8; - v5 = p[3] << 4; - v6 = p[5] << 4; - - // stage 3 - t = (v0 - v1+ 1) >> 1; - v0 = (v0 + v1 + 1) >> 1; - v1 = t; - t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8; - v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8; - v3 = t; - t = (v4 - v6 + 1) >> 1; - v4 = (v4 + v6 + 1) >> 1; - v6 = t; - t = (v7 + v5 + 1) >> 1; - v5 = (v7 - v5 + 1) >> 1; - v7 = t; - - // stage 2 - t = (v0 - v3 + 1) >> 1; - v0 = (v0 + v3 + 1) >> 1; - v3 = t; - t = (v1 - v2 + 1) >> 1; - v1 = (v1 + v2 + 1) >> 1; - v2 = t; - t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; - v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; - v7 = t; - t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; - v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; - v6 = t; - - // stage 1 - p[0] = v0 + v7; - p[7] = v0 - v7; - p[1] = v1 + v6; - p[6] = v1 - v6; - p[2] = v2 + v5; - p[5] = v2 - v5; - p[3] = v3 + v4; - p[4] = v3 - v4; - } - - // inverse DCT on columns - for (i = 0; i < 8; ++i) { - p = dataIn + i; - - // check for all-zero AC coefficients - if (p[1*8] == 0 && p[2*8] == 0 && p[3*8] == 0 && - p[4*8] == 0 && p[5*8] == 0 && p[6*8] == 0 && p[7*8] == 0) { - t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14; - p[0*8] = t; - p[1*8] = t; - p[2*8] = t; - p[3*8] = t; - p[4*8] = t; - p[5*8] = t; - p[6*8] = t; - p[7*8] = t; - continue; - } - - // stage 4 - v0 = (dctSqrt2 * p[0*8] + 2048) >> 12; - v1 = (dctSqrt2 * p[4*8] + 2048) >> 12; - v2 = p[2*8]; - v3 = p[6*8]; - v4 = (dctSqrt1d2 * (p[1*8] - p[7*8]) + 2048) >> 12; - v7 = (dctSqrt1d2 * (p[1*8] + p[7*8]) + 2048) >> 12; - v5 = p[3*8]; - v6 = p[5*8]; - - // stage 3 - t = (v0 - v1 + 1) >> 1; - v0 = (v0 + v1 + 1) >> 1; - v1 = t; - t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12; - v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12; - v3 = t; - t = (v4 - v6 + 1) >> 1; - v4 = (v4 + v6 + 1) >> 1; - v6 = t; - t = (v7 + v5 + 1) >> 1; - v5 = (v7 - v5 + 1) >> 1; - v7 = t; - - // stage 2 - t = (v0 - v3 + 1) >> 1; - v0 = (v0 + v3 + 1) >> 1; - v3 = t; - t = (v1 - v2 + 1) >> 1; - v1 = (v1 + v2 + 1) >> 1; - v2 = t; - t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; - v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; - v7 = t; - t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; - v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; - v6 = t; - - // stage 1 - p[0*8] = v0 + v7; - p[7*8] = v0 - v7; - p[1*8] = v1 + v6; - p[6*8] = v1 - v6; - p[2*8] = v2 + v5; - p[5*8] = v2 - v5; - p[3*8] = v3 + v4; - p[4*8] = v3 - v4; - } - - // convert to 8-bit integers - for (i = 0; i < 64; ++i) { - dataOut[i] = dctClip[dctClipOffset + 128 + ((dataIn[i] + 8) >> 4)]; - } -} - -int DCTStream::readHuffSym(DCTHuffTable *table) { - Gushort code; - int bit; - int codeBits; - - code = 0; - codeBits = 0; - do { - // add a bit to the code - if ((bit = readBit()) == EOF) - return 9999; - code = (code << 1) + bit; - ++codeBits; - - // look up code - if (code - table->firstCode[codeBits] < table->numCodes[codeBits]) { - code -= table->firstCode[codeBits]; - return table->sym[table->firstSym[codeBits] + code]; - } - } while (codeBits < 16); - - error(getPos(), "Bad Huffman code in DCT stream"); - return 9999; -} - -int DCTStream::readAmp(int size) { - int amp, bit; - int bits; - - amp = 0; - for (bits = 0; bits < size; ++bits) { - if ((bit = readBit()) == EOF) - return 9999; - amp = (amp << 1) + bit; - } - if (amp < (1 << (size - 1))) - amp -= (1 << size) - 1; - return amp; -} - -int DCTStream::readBit() { - int bit; - int c, c2; - - if (inputBits == 0) { - if ((c = str->getChar()) == EOF) - return EOF; - if (c == 0xff) { - do { - c2 = str->getChar(); - } while (c2 == 0xff); - if (c2 != 0x00) { - error(getPos(), "Bad DCT data: missing 00 after ff"); - return EOF; - } - } - inputBuf = c; - inputBits = 8; - } - bit = (inputBuf >> (inputBits - 1)) & 1; - --inputBits; - return bit; -} - -GBool DCTStream::readHeader() { - GBool doScan; - int n; - int c = 0; - int i; - - // read headers - doScan = gFalse; - while (!doScan) { - c = readMarker(); - switch (c) { - case 0xc0: // SOF0 (sequential) - case 0xc1: // SOF1 (extended sequential) - if (!readBaselineSOF()) { - return gFalse; - } - break; - case 0xc2: // SOF2 (progressive) - if (!readProgressiveSOF()) { - return gFalse; - } - break; - case 0xc4: // DHT - if (!readHuffmanTables()) { - return gFalse; - } - break; - case 0xd8: // SOI - break; - case 0xd9: // EOI - return gFalse; - case 0xda: // SOS - if (!readScanInfo()) { - return gFalse; - } - doScan = gTrue; - break; - case 0xdb: // DQT - if (!readQuantTables()) { - return gFalse; - } - break; - case 0xdd: // DRI - if (!readRestartInterval()) { - return gFalse; - } - break; - case 0xe0: // APP0 - if (!readJFIFMarker()) { - return gFalse; - } - break; - case 0xee: // APP14 - if (!readAdobeMarker()) { - return gFalse; - } - break; - case EOF: - error(getPos(), "Bad DCT header"); - return gFalse; - default: - // skip APPn / COM / etc. - if (c >= 0xe0) { - n = read16() - 2; - for (i = 0; i < n; ++i) { - str->getChar(); - } - } else { - error(getPos(), "Unknown DCT marker <%02x>", c); - return gFalse; - } - break; - } - } - - return gTrue; -} - -GBool DCTStream::readBaselineSOF() { - int length; - int prec; - int i; - int c; - - length = read16(); - prec = str->getChar(); - height = read16(); - width = read16(); - numComps = str->getChar(); - if (numComps <= 0 || numComps > 4) { - numComps = 0; - error(getPos(), "Bad number of components in DCT stream"); - return gFalse; - } - if (prec != 8) { - error(getPos(), "Bad DCT precision %d", prec); - return gFalse; - } - for (i = 0; i < numComps; ++i) { - compInfo[i].id = str->getChar(); - c = str->getChar(); - compInfo[i].hSample = (c >> 4) & 0x0f; - compInfo[i].vSample = c & 0x0f; - compInfo[i].quantTable = str->getChar(); - } - progressive = gFalse; - return gTrue; -} - -GBool DCTStream::readProgressiveSOF() { - int length; - int prec; - int i; - int c; - - length = read16(); - prec = str->getChar(); - height = read16(); - width = read16(); - numComps = str->getChar(); - if (numComps <= 0 || numComps > 4) { - numComps = 0; - error(getPos(), "Bad number of components in DCT stream"); - return gFalse; - } - if (prec != 8) { - error(getPos(), "Bad DCT precision %d", prec); - return gFalse; - } - for (i = 0; i < numComps; ++i) { - compInfo[i].id = str->getChar(); - c = str->getChar(); - compInfo[i].hSample = (c >> 4) & 0x0f; - compInfo[i].vSample = c & 0x0f; - compInfo[i].quantTable = str->getChar(); - } - progressive = gTrue; - return gTrue; -} - -GBool DCTStream::readScanInfo() { - int length; - int id, c; - int i, j; - - length = read16() - 2; - scanInfo.numComps = str->getChar(); - if (scanInfo.numComps <= 0 || scanInfo.numComps > 4) { - scanInfo.numComps = 0; - error(getPos(), "Bad number of components in DCT stream"); - return gFalse; - } - --length; - if (length != 2 * scanInfo.numComps + 3) { - error(getPos(), "Bad DCT scan info block"); - return gFalse; - } - interleaved = scanInfo.numComps == numComps; - for (j = 0; j < numComps; ++j) { - scanInfo.comp[j] = gFalse; - } - for (i = 0; i < scanInfo.numComps; ++i) { - id = str->getChar(); - // some (broken) DCT streams reuse ID numbers, but at least they - // keep the components in order, so we check compInfo[i] first to - // work around the problem - if (id == compInfo[i].id) { - j = i; - } else { - for (j = 0; j < numComps; ++j) { - if (id == compInfo[j].id) { - break; - } - } - if (j == numComps) { - error(getPos(), "Bad DCT component ID in scan info block"); - return gFalse; - } - } - scanInfo.comp[j] = gTrue; - c = str->getChar(); - scanInfo.dcHuffTable[j] = (c >> 4) & 0x0f; - scanInfo.acHuffTable[j] = c & 0x0f; - } - scanInfo.firstCoeff = str->getChar(); - scanInfo.lastCoeff = str->getChar(); - c = str->getChar(); - scanInfo.ah = (c >> 4) & 0x0f; - scanInfo.al = c & 0x0f; - return gTrue; -} - -GBool DCTStream::readQuantTables() { - int length, prec, i, index; - - length = read16() - 2; - while (length > 0) { - index = str->getChar(); - prec = (index >> 4) & 0x0f; - index &= 0x0f; - if (prec > 1 || index >= 4) { - error(getPos(), "Bad DCT quantization table"); - return gFalse; - } - if (index == numQuantTables) { - numQuantTables = index + 1; - } - for (i = 0; i < 64; ++i) { - if (prec) { - quantTables[index][dctZigZag[i]] = read16(); - } else { - quantTables[index][dctZigZag[i]] = str->getChar(); - } - } - if (prec) { - length -= 129; - } else { - length -= 65; - } - } - return gTrue; -} - -GBool DCTStream::readHuffmanTables() { - DCTHuffTable *tbl; - int length; - int index; - Gushort code; - Guchar sym; - int i; - int c; - - length = read16() - 2; - while (length > 0) { - index = str->getChar(); - --length; - if ((index & ~0x10) >= 4 || (index & ~0x10) < 0) { - error(getPos(), "Bad DCT Huffman table"); - return gFalse; - } - if (index & 0x10) { - index &= 0x03; - if (index >= numACHuffTables) - numACHuffTables = index+1; - tbl = &acHuffTables[index]; - } else { - if (index >= numDCHuffTables) - numDCHuffTables = index+1; - tbl = &dcHuffTables[index]; - } - sym = 0; - code = 0; - for (i = 1; i <= 16; ++i) { - c = str->getChar(); - tbl->firstSym[i] = sym; - tbl->firstCode[i] = code; - tbl->numCodes[i] = c; - sym += c; - code = (code + c) << 1; - } - length -= 16; - for (i = 0; i < sym; ++i) - tbl->sym[i] = str->getChar(); - length -= sym; - } - return gTrue; -} - -GBool DCTStream::readRestartInterval() { - int length; - - length = read16(); - if (length != 4) { - error(getPos(), "Bad DCT restart interval"); - return gFalse; - } - restartInterval = read16(); - return gTrue; -} - -GBool DCTStream::readJFIFMarker() { - int length, i; - char buf[5]; - int c; - - length = read16(); - length -= 2; - if (length >= 5) { - for (i = 0; i < 5; ++i) { - if ((c = str->getChar()) == EOF) { - error(getPos(), "Bad DCT APP0 marker"); - return gFalse; - } - buf[i] = c; - } - length -= 5; - if (!memcmp(buf, "JFIF\0", 5)) { - gotJFIFMarker = gTrue; - } - } - while (length > 0) { - if (str->getChar() == EOF) { - error(getPos(), "Bad DCT APP0 marker"); - return gFalse; - } - --length; - } - return gTrue; -} - -GBool DCTStream::readAdobeMarker() { - int length, i; - char buf[12]; - int c; - - length = read16(); - if (length < 14) { - goto err; - } - for (i = 0; i < 12; ++i) { - if ((c = str->getChar()) == EOF) { - goto err; - } - buf[i] = c; - } - if (strncmp(buf, "Adobe", 5)) { - goto err; - } - colorXform = buf[11]; - gotAdobeMarker = gTrue; - for (i = 14; i < length; ++i) { - if (str->getChar() == EOF) { - goto err; - } - } - return gTrue; - - err: - error(getPos(), "Bad DCT Adobe APP14 marker"); - return gFalse; -} - -GBool DCTStream::readTrailer() { - int c; - - c = readMarker(); - if (c != 0xd9) { // EOI - error(getPos(), "Bad DCT trailer"); - return gFalse; - } - return gTrue; -} - -int DCTStream::readMarker() { - int c; - - do { - do { - c = str->getChar(); - } while (c != 0xff && c != EOF); - do { - c = str->getChar(); - } while (c == 0xff); - } while (c == 0x00); - return c; -} - -int DCTStream::read16() { - int c1, c2; - - if ((c1 = str->getChar()) == EOF) - return EOF; - if ((c2 = str->getChar()) == EOF) - return EOF; - return (c1 << 8) + c2; -} - -GString *DCTStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("<< >> /DCTDecode filter\n"); - return s; -} - -GBool DCTStream::isBinary(GBool last) { - return str->isBinary(gTrue); -} - -#endif - -//------------------------------------------------------------------------ -// FlateStream -//------------------------------------------------------------------------ - -int FlateStream::codeLenCodeMap[flateMaxCodeLenCodes] = { - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 -}; - -FlateDecode FlateStream::lengthDecode[flateMaxLitCodes-257] = { - {0, 3}, - {0, 4}, - {0, 5}, - {0, 6}, - {0, 7}, - {0, 8}, - {0, 9}, - {0, 10}, - {1, 11}, - {1, 13}, - {1, 15}, - {1, 17}, - {2, 19}, - {2, 23}, - {2, 27}, - {2, 31}, - {3, 35}, - {3, 43}, - {3, 51}, - {3, 59}, - {4, 67}, - {4, 83}, - {4, 99}, - {4, 115}, - {5, 131}, - {5, 163}, - {5, 195}, - {5, 227}, - {0, 258}, - {0, 258}, - {0, 258} -}; - -FlateDecode FlateStream::distDecode[flateMaxDistCodes] = { - { 0, 1}, - { 0, 2}, - { 0, 3}, - { 0, 4}, - { 1, 5}, - { 1, 7}, - { 2, 9}, - { 2, 13}, - { 3, 17}, - { 3, 25}, - { 4, 33}, - { 4, 49}, - { 5, 65}, - { 5, 97}, - { 6, 129}, - { 6, 193}, - { 7, 257}, - { 7, 385}, - { 8, 513}, - { 8, 769}, - { 9, 1025}, - { 9, 1537}, - {10, 2049}, - {10, 3073}, - {11, 4097}, - {11, 6145}, - {12, 8193}, - {12, 12289}, - {13, 16385}, - {13, 24577} -}; - -static FlateCode flateFixedLitCodeTabCodes[512] = { - {7, 0x0100}, - {8, 0x0050}, - {8, 0x0010}, - {8, 0x0118}, - {7, 0x0110}, - {8, 0x0070}, - {8, 0x0030}, - {9, 0x00c0}, - {7, 0x0108}, - {8, 0x0060}, - {8, 0x0020}, - {9, 0x00a0}, - {8, 0x0000}, - {8, 0x0080}, - {8, 0x0040}, - {9, 0x00e0}, - {7, 0x0104}, - {8, 0x0058}, - {8, 0x0018}, - {9, 0x0090}, - {7, 0x0114}, - {8, 0x0078}, - {8, 0x0038}, - {9, 0x00d0}, - {7, 0x010c}, - {8, 0x0068}, - {8, 0x0028}, - {9, 0x00b0}, - {8, 0x0008}, - {8, 0x0088}, - {8, 0x0048}, - {9, 0x00f0}, - {7, 0x0102}, - {8, 0x0054}, - {8, 0x0014}, - {8, 0x011c}, - {7, 0x0112}, - {8, 0x0074}, - {8, 0x0034}, - {9, 0x00c8}, - {7, 0x010a}, - {8, 0x0064}, - {8, 0x0024}, - {9, 0x00a8}, - {8, 0x0004}, - {8, 0x0084}, - {8, 0x0044}, - {9, 0x00e8}, - {7, 0x0106}, - {8, 0x005c}, - {8, 0x001c}, - {9, 0x0098}, - {7, 0x0116}, - {8, 0x007c}, - {8, 0x003c}, - {9, 0x00d8}, - {7, 0x010e}, - {8, 0x006c}, - {8, 0x002c}, - {9, 0x00b8}, - {8, 0x000c}, - {8, 0x008c}, - {8, 0x004c}, - {9, 0x00f8}, - {7, 0x0101}, - {8, 0x0052}, - {8, 0x0012}, - {8, 0x011a}, - {7, 0x0111}, - {8, 0x0072}, - {8, 0x0032}, - {9, 0x00c4}, - {7, 0x0109}, - {8, 0x0062}, - {8, 0x0022}, - {9, 0x00a4}, - {8, 0x0002}, - {8, 0x0082}, - {8, 0x0042}, - {9, 0x00e4}, - {7, 0x0105}, - {8, 0x005a}, - {8, 0x001a}, - {9, 0x0094}, - {7, 0x0115}, - {8, 0x007a}, - {8, 0x003a}, - {9, 0x00d4}, - {7, 0x010d}, - {8, 0x006a}, - {8, 0x002a}, - {9, 0x00b4}, - {8, 0x000a}, - {8, 0x008a}, - {8, 0x004a}, - {9, 0x00f4}, - {7, 0x0103}, - {8, 0x0056}, - {8, 0x0016}, - {8, 0x011e}, - {7, 0x0113}, - {8, 0x0076}, - {8, 0x0036}, - {9, 0x00cc}, - {7, 0x010b}, - {8, 0x0066}, - {8, 0x0026}, - {9, 0x00ac}, - {8, 0x0006}, - {8, 0x0086}, - {8, 0x0046}, - {9, 0x00ec}, - {7, 0x0107}, - {8, 0x005e}, - {8, 0x001e}, - {9, 0x009c}, - {7, 0x0117}, - {8, 0x007e}, - {8, 0x003e}, - {9, 0x00dc}, - {7, 0x010f}, - {8, 0x006e}, - {8, 0x002e}, - {9, 0x00bc}, - {8, 0x000e}, - {8, 0x008e}, - {8, 0x004e}, - {9, 0x00fc}, - {7, 0x0100}, - {8, 0x0051}, - {8, 0x0011}, - {8, 0x0119}, - {7, 0x0110}, - {8, 0x0071}, - {8, 0x0031}, - {9, 0x00c2}, - {7, 0x0108}, - {8, 0x0061}, - {8, 0x0021}, - {9, 0x00a2}, - {8, 0x0001}, - {8, 0x0081}, - {8, 0x0041}, - {9, 0x00e2}, - {7, 0x0104}, - {8, 0x0059}, - {8, 0x0019}, - {9, 0x0092}, - {7, 0x0114}, - {8, 0x0079}, - {8, 0x0039}, - {9, 0x00d2}, - {7, 0x010c}, - {8, 0x0069}, - {8, 0x0029}, - {9, 0x00b2}, - {8, 0x0009}, - {8, 0x0089}, - {8, 0x0049}, - {9, 0x00f2}, - {7, 0x0102}, - {8, 0x0055}, - {8, 0x0015}, - {8, 0x011d}, - {7, 0x0112}, - {8, 0x0075}, - {8, 0x0035}, - {9, 0x00ca}, - {7, 0x010a}, - {8, 0x0065}, - {8, 0x0025}, - {9, 0x00aa}, - {8, 0x0005}, - {8, 0x0085}, - {8, 0x0045}, - {9, 0x00ea}, - {7, 0x0106}, - {8, 0x005d}, - {8, 0x001d}, - {9, 0x009a}, - {7, 0x0116}, - {8, 0x007d}, - {8, 0x003d}, - {9, 0x00da}, - {7, 0x010e}, - {8, 0x006d}, - {8, 0x002d}, - {9, 0x00ba}, - {8, 0x000d}, - {8, 0x008d}, - {8, 0x004d}, - {9, 0x00fa}, - {7, 0x0101}, - {8, 0x0053}, - {8, 0x0013}, - {8, 0x011b}, - {7, 0x0111}, - {8, 0x0073}, - {8, 0x0033}, - {9, 0x00c6}, - {7, 0x0109}, - {8, 0x0063}, - {8, 0x0023}, - {9, 0x00a6}, - {8, 0x0003}, - {8, 0x0083}, - {8, 0x0043}, - {9, 0x00e6}, - {7, 0x0105}, - {8, 0x005b}, - {8, 0x001b}, - {9, 0x0096}, - {7, 0x0115}, - {8, 0x007b}, - {8, 0x003b}, - {9, 0x00d6}, - {7, 0x010d}, - {8, 0x006b}, - {8, 0x002b}, - {9, 0x00b6}, - {8, 0x000b}, - {8, 0x008b}, - {8, 0x004b}, - {9, 0x00f6}, - {7, 0x0103}, - {8, 0x0057}, - {8, 0x0017}, - {8, 0x011f}, - {7, 0x0113}, - {8, 0x0077}, - {8, 0x0037}, - {9, 0x00ce}, - {7, 0x010b}, - {8, 0x0067}, - {8, 0x0027}, - {9, 0x00ae}, - {8, 0x0007}, - {8, 0x0087}, - {8, 0x0047}, - {9, 0x00ee}, - {7, 0x0107}, - {8, 0x005f}, - {8, 0x001f}, - {9, 0x009e}, - {7, 0x0117}, - {8, 0x007f}, - {8, 0x003f}, - {9, 0x00de}, - {7, 0x010f}, - {8, 0x006f}, - {8, 0x002f}, - {9, 0x00be}, - {8, 0x000f}, - {8, 0x008f}, - {8, 0x004f}, - {9, 0x00fe}, - {7, 0x0100}, - {8, 0x0050}, - {8, 0x0010}, - {8, 0x0118}, - {7, 0x0110}, - {8, 0x0070}, - {8, 0x0030}, - {9, 0x00c1}, - {7, 0x0108}, - {8, 0x0060}, - {8, 0x0020}, - {9, 0x00a1}, - {8, 0x0000}, - {8, 0x0080}, - {8, 0x0040}, - {9, 0x00e1}, - {7, 0x0104}, - {8, 0x0058}, - {8, 0x0018}, - {9, 0x0091}, - {7, 0x0114}, - {8, 0x0078}, - {8, 0x0038}, - {9, 0x00d1}, - {7, 0x010c}, - {8, 0x0068}, - {8, 0x0028}, - {9, 0x00b1}, - {8, 0x0008}, - {8, 0x0088}, - {8, 0x0048}, - {9, 0x00f1}, - {7, 0x0102}, - {8, 0x0054}, - {8, 0x0014}, - {8, 0x011c}, - {7, 0x0112}, - {8, 0x0074}, - {8, 0x0034}, - {9, 0x00c9}, - {7, 0x010a}, - {8, 0x0064}, - {8, 0x0024}, - {9, 0x00a9}, - {8, 0x0004}, - {8, 0x0084}, - {8, 0x0044}, - {9, 0x00e9}, - {7, 0x0106}, - {8, 0x005c}, - {8, 0x001c}, - {9, 0x0099}, - {7, 0x0116}, - {8, 0x007c}, - {8, 0x003c}, - {9, 0x00d9}, - {7, 0x010e}, - {8, 0x006c}, - {8, 0x002c}, - {9, 0x00b9}, - {8, 0x000c}, - {8, 0x008c}, - {8, 0x004c}, - {9, 0x00f9}, - {7, 0x0101}, - {8, 0x0052}, - {8, 0x0012}, - {8, 0x011a}, - {7, 0x0111}, - {8, 0x0072}, - {8, 0x0032}, - {9, 0x00c5}, - {7, 0x0109}, - {8, 0x0062}, - {8, 0x0022}, - {9, 0x00a5}, - {8, 0x0002}, - {8, 0x0082}, - {8, 0x0042}, - {9, 0x00e5}, - {7, 0x0105}, - {8, 0x005a}, - {8, 0x001a}, - {9, 0x0095}, - {7, 0x0115}, - {8, 0x007a}, - {8, 0x003a}, - {9, 0x00d5}, - {7, 0x010d}, - {8, 0x006a}, - {8, 0x002a}, - {9, 0x00b5}, - {8, 0x000a}, - {8, 0x008a}, - {8, 0x004a}, - {9, 0x00f5}, - {7, 0x0103}, - {8, 0x0056}, - {8, 0x0016}, - {8, 0x011e}, - {7, 0x0113}, - {8, 0x0076}, - {8, 0x0036}, - {9, 0x00cd}, - {7, 0x010b}, - {8, 0x0066}, - {8, 0x0026}, - {9, 0x00ad}, - {8, 0x0006}, - {8, 0x0086}, - {8, 0x0046}, - {9, 0x00ed}, - {7, 0x0107}, - {8, 0x005e}, - {8, 0x001e}, - {9, 0x009d}, - {7, 0x0117}, - {8, 0x007e}, - {8, 0x003e}, - {9, 0x00dd}, - {7, 0x010f}, - {8, 0x006e}, - {8, 0x002e}, - {9, 0x00bd}, - {8, 0x000e}, - {8, 0x008e}, - {8, 0x004e}, - {9, 0x00fd}, - {7, 0x0100}, - {8, 0x0051}, - {8, 0x0011}, - {8, 0x0119}, - {7, 0x0110}, - {8, 0x0071}, - {8, 0x0031}, - {9, 0x00c3}, - {7, 0x0108}, - {8, 0x0061}, - {8, 0x0021}, - {9, 0x00a3}, - {8, 0x0001}, - {8, 0x0081}, - {8, 0x0041}, - {9, 0x00e3}, - {7, 0x0104}, - {8, 0x0059}, - {8, 0x0019}, - {9, 0x0093}, - {7, 0x0114}, - {8, 0x0079}, - {8, 0x0039}, - {9, 0x00d3}, - {7, 0x010c}, - {8, 0x0069}, - {8, 0x0029}, - {9, 0x00b3}, - {8, 0x0009}, - {8, 0x0089}, - {8, 0x0049}, - {9, 0x00f3}, - {7, 0x0102}, - {8, 0x0055}, - {8, 0x0015}, - {8, 0x011d}, - {7, 0x0112}, - {8, 0x0075}, - {8, 0x0035}, - {9, 0x00cb}, - {7, 0x010a}, - {8, 0x0065}, - {8, 0x0025}, - {9, 0x00ab}, - {8, 0x0005}, - {8, 0x0085}, - {8, 0x0045}, - {9, 0x00eb}, - {7, 0x0106}, - {8, 0x005d}, - {8, 0x001d}, - {9, 0x009b}, - {7, 0x0116}, - {8, 0x007d}, - {8, 0x003d}, - {9, 0x00db}, - {7, 0x010e}, - {8, 0x006d}, - {8, 0x002d}, - {9, 0x00bb}, - {8, 0x000d}, - {8, 0x008d}, - {8, 0x004d}, - {9, 0x00fb}, - {7, 0x0101}, - {8, 0x0053}, - {8, 0x0013}, - {8, 0x011b}, - {7, 0x0111}, - {8, 0x0073}, - {8, 0x0033}, - {9, 0x00c7}, - {7, 0x0109}, - {8, 0x0063}, - {8, 0x0023}, - {9, 0x00a7}, - {8, 0x0003}, - {8, 0x0083}, - {8, 0x0043}, - {9, 0x00e7}, - {7, 0x0105}, - {8, 0x005b}, - {8, 0x001b}, - {9, 0x0097}, - {7, 0x0115}, - {8, 0x007b}, - {8, 0x003b}, - {9, 0x00d7}, - {7, 0x010d}, - {8, 0x006b}, - {8, 0x002b}, - {9, 0x00b7}, - {8, 0x000b}, - {8, 0x008b}, - {8, 0x004b}, - {9, 0x00f7}, - {7, 0x0103}, - {8, 0x0057}, - {8, 0x0017}, - {8, 0x011f}, - {7, 0x0113}, - {8, 0x0077}, - {8, 0x0037}, - {9, 0x00cf}, - {7, 0x010b}, - {8, 0x0067}, - {8, 0x0027}, - {9, 0x00af}, - {8, 0x0007}, - {8, 0x0087}, - {8, 0x0047}, - {9, 0x00ef}, - {7, 0x0107}, - {8, 0x005f}, - {8, 0x001f}, - {9, 0x009f}, - {7, 0x0117}, - {8, 0x007f}, - {8, 0x003f}, - {9, 0x00df}, - {7, 0x010f}, - {8, 0x006f}, - {8, 0x002f}, - {9, 0x00bf}, - {8, 0x000f}, - {8, 0x008f}, - {8, 0x004f}, - {9, 0x00ff} -}; - -FlateHuffmanTab FlateStream::fixedLitCodeTab = { - flateFixedLitCodeTabCodes, 9 -}; - -static FlateCode flateFixedDistCodeTabCodes[32] = { - {5, 0x0000}, - {5, 0x0010}, - {5, 0x0008}, - {5, 0x0018}, - {5, 0x0004}, - {5, 0x0014}, - {5, 0x000c}, - {5, 0x001c}, - {5, 0x0002}, - {5, 0x0012}, - {5, 0x000a}, - {5, 0x001a}, - {5, 0x0006}, - {5, 0x0016}, - {5, 0x000e}, - {0, 0x0000}, - {5, 0x0001}, - {5, 0x0011}, - {5, 0x0009}, - {5, 0x0019}, - {5, 0x0005}, - {5, 0x0015}, - {5, 0x000d}, - {5, 0x001d}, - {5, 0x0003}, - {5, 0x0013}, - {5, 0x000b}, - {5, 0x001b}, - {5, 0x0007}, - {5, 0x0017}, - {5, 0x000f}, - {0, 0x0000} -}; - -FlateHuffmanTab FlateStream::fixedDistCodeTab = { - flateFixedDistCodeTabCodes, 5 -}; - -FlateStream::FlateStream(Stream *strA, int predictor, int columns, - int colors, int bits): - FilterStream(strA) { - if (predictor != 1) { - pred = new StreamPredictor(this, predictor, columns, colors, bits); - if (!pred->isOk()) { - delete pred; - pred = NULL; - } - } else { - pred = NULL; - } - litCodeTab.codes = NULL; - distCodeTab.codes = NULL; -} - -FlateStream::~FlateStream() { - if (litCodeTab.codes != fixedLitCodeTab.codes) { - gfree(litCodeTab.codes); - } - if (distCodeTab.codes != fixedDistCodeTab.codes) { - gfree(distCodeTab.codes); - } - if (pred) { - delete pred; - } - delete str; -} - -void FlateStream::reset() { - int cmf, flg; - - index = 0; - remain = 0; - codeBuf = 0; - codeSize = 0; - compressedBlock = gFalse; - endOfBlock = gTrue; - eof = gTrue; - - str->reset(); - - // read header - //~ need to look at window size? - endOfBlock = eof = gTrue; - cmf = str->getChar(); - flg = str->getChar(); - if (cmf == EOF || flg == EOF) - return; - if ((cmf & 0x0f) != 0x08) { - error(getPos(), "Unknown compression method in flate stream"); - return; - } - if ((((cmf << 8) + flg) % 31) != 0) { - error(getPos(), "Bad FCHECK in flate stream"); - return; - } - if (flg & 0x20) { - error(getPos(), "FDICT bit set in flate stream"); - return; - } - - eof = gFalse; -} - -int FlateStream::getChar() { - int c; - - if (pred) { - return pred->getChar(); - } - while (remain == 0) { - if (endOfBlock && eof) - return EOF; - readSome(); - } - c = buf[index]; - index = (index + 1) & flateMask; - --remain; - return c; -} - -int FlateStream::lookChar() { - int c; - - if (pred) { - return pred->lookChar(); - } - while (remain == 0) { - if (endOfBlock && eof) - return EOF; - readSome(); - } - c = buf[index]; - return c; -} - -int FlateStream::getRawChar() { - int c; - - while (remain == 0) { - if (endOfBlock && eof) - return EOF; - readSome(); - } - c = buf[index]; - index = (index + 1) & flateMask; - --remain; - return c; -} - -GString *FlateStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 3 || pred) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("<< >> /FlateDecode filter\n"); - return s; -} - -GBool FlateStream::isBinary(GBool /*last*/) { - return str->isBinary(gTrue); -} - -void FlateStream::readSome() { - int code1, code2; - int len, dist; - int i, j, k; - int c; - - if (endOfBlock) { - if (!startBlock()) - return; - } - - if (compressedBlock) { - if ((code1 = getHuffmanCodeWord(&litCodeTab)) == EOF) - goto err; - if (code1 < 256) { - buf[index] = code1; - remain = 1; - } else if (code1 == 256) { - endOfBlock = gTrue; - remain = 0; - } else { - code1 -= 257; - code2 = lengthDecode[code1].bits; - if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF) - goto err; - len = lengthDecode[code1].first + code2; - if ((code1 = getHuffmanCodeWord(&distCodeTab)) == EOF) - goto err; - code2 = distDecode[code1].bits; - if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF) - goto err; - dist = distDecode[code1].first + code2; - i = index; - j = (index - dist) & flateMask; - for (k = 0; k < len; ++k) { - buf[i] = buf[j]; - i = (i + 1) & flateMask; - j = (j + 1) & flateMask; - } - remain = len; - } - - } else { - len = (blockLen < flateWindow) ? blockLen : flateWindow; - for (i = 0, j = index; i < len; ++i, j = (j + 1) & flateMask) { - if ((c = str->getChar()) == EOF) { - endOfBlock = eof = gTrue; - break; - } - buf[j] = c & 0xff; - } - remain = i; - blockLen -= len; - if (blockLen == 0) - endOfBlock = gTrue; - } - - return; - -err: - error(getPos(), "Unexpected end of file in flate stream"); - endOfBlock = eof = gTrue; - remain = 0; -} - -GBool FlateStream::startBlock() { - int blockHdr; - int c; - int check; - - // free the code tables from the previous block - if (litCodeTab.codes != fixedLitCodeTab.codes) { - gfree(litCodeTab.codes); - } - litCodeTab.codes = NULL; - if (distCodeTab.codes != fixedDistCodeTab.codes) { - gfree(distCodeTab.codes); - } - distCodeTab.codes = NULL; - - // read block header - blockHdr = getCodeWord(3); - if (blockHdr & 1) - eof = gTrue; - blockHdr >>= 1; - - // uncompressed block - if (blockHdr == 0) { - compressedBlock = gFalse; - if ((c = str->getChar()) == EOF) - goto err; - blockLen = c & 0xff; - if ((c = str->getChar()) == EOF) - goto err; - blockLen |= (c & 0xff) << 8; - if ((c = str->getChar()) == EOF) - goto err; - check = c & 0xff; - if ((c = str->getChar()) == EOF) - goto err; - check |= (c & 0xff) << 8; - if (check != (~blockLen & 0xffff)) - error(getPos(), "Bad uncompressed block length in flate stream"); - codeBuf = 0; - codeSize = 0; - - // compressed block with fixed codes - } else if (blockHdr == 1) { - compressedBlock = gTrue; - loadFixedCodes(); - - // compressed block with dynamic codes - } else if (blockHdr == 2) { - compressedBlock = gTrue; - if (!readDynamicCodes()) { - goto err; - } - - // unknown block type - } else { - goto err; - } - - endOfBlock = gFalse; - return gTrue; - -err: - error(getPos(), "Bad block header in flate stream"); - endOfBlock = eof = gTrue; - return gFalse; -} - -void FlateStream::loadFixedCodes() { - litCodeTab.codes = fixedLitCodeTab.codes; - litCodeTab.maxLen = fixedLitCodeTab.maxLen; - distCodeTab.codes = fixedDistCodeTab.codes; - distCodeTab.maxLen = fixedDistCodeTab.maxLen; -} - -GBool FlateStream::readDynamicCodes() { - int numCodeLenCodes; - int numLitCodes; - int numDistCodes; - int codeLenCodeLengths[flateMaxCodeLenCodes]; - FlateHuffmanTab codeLenCodeTab; - int len, repeat, code; - int i; - - codeLenCodeTab.codes = NULL; - - // read lengths - if ((numLitCodes = getCodeWord(5)) == EOF) { - goto err; - } - numLitCodes += 257; - if ((numDistCodes = getCodeWord(5)) == EOF) { - goto err; - } - numDistCodes += 1; - if ((numCodeLenCodes = getCodeWord(4)) == EOF) { - goto err; - } - numCodeLenCodes += 4; - if (numLitCodes > flateMaxLitCodes || - numDistCodes > flateMaxDistCodes || - numCodeLenCodes > flateMaxCodeLenCodes) { - goto err; - } - - // build the code length code table - for (i = 0; i < flateMaxCodeLenCodes; ++i) { - codeLenCodeLengths[i] = 0; - } - for (i = 0; i < numCodeLenCodes; ++i) { - if ((codeLenCodeLengths[codeLenCodeMap[i]] = getCodeWord(3)) == -1) { - goto err; - } - } - compHuffmanCodes(codeLenCodeLengths, flateMaxCodeLenCodes, &codeLenCodeTab); - - // build the literal and distance code tables - len = 0; - repeat = 0; - i = 0; - while (i < numLitCodes + numDistCodes) { - if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) { - goto err; - } - if (code == 16) { - if ((repeat = getCodeWord(2)) == EOF) { - goto err; - } - repeat += 3; - if (i + repeat > numLitCodes + numDistCodes) { - goto err; - } - for (; repeat > 0; --repeat) { - codeLengths[i++] = len; - } - } else if (code == 17) { - if ((repeat = getCodeWord(3)) == EOF) { - goto err; - } - repeat += 3; - if (i + repeat > numLitCodes + numDistCodes) { - goto err; - } - len = 0; - for (; repeat > 0; --repeat) { - codeLengths[i++] = 0; - } - } else if (code == 18) { - if ((repeat = getCodeWord(7)) == EOF) { - goto err; - } - repeat += 11; - if (i + repeat > numLitCodes + numDistCodes) { - goto err; - } - len = 0; - for (; repeat > 0; --repeat) { - codeLengths[i++] = 0; - } - } else { - codeLengths[i++] = len = code; - } - } - compHuffmanCodes(codeLengths, numLitCodes, &litCodeTab); - compHuffmanCodes(codeLengths + numLitCodes, numDistCodes, &distCodeTab); - - gfree(codeLenCodeTab.codes); - return gTrue; - -err: - error(getPos(), "Bad dynamic code table in flate stream"); - gfree(codeLenCodeTab.codes); - return gFalse; -} - -// Convert an array of lengths, in value order, into a -// Huffman code lookup table. -void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) { - int tabSize, len, code, code2, skip, val, i, t; - - // find max code length - tab->maxLen = 0; - for (val = 0; val < n; ++val) { - if (lengths[val] > tab->maxLen) { - tab->maxLen = lengths[val]; - } - } - - // allocate the table - tabSize = 1 << tab->maxLen; - tab->codes = (FlateCode *)gmallocn(tabSize, sizeof(FlateCode)); - - // clear the table - for (i = 0; i < tabSize; ++i) { - tab->codes[i].len = 0; - tab->codes[i].val = 0; - } - - // build the table - for (len = 1, code = 0, skip = 2; - len <= tab->maxLen; - ++len, code <<= 1, skip <<= 1) { - for (val = 0; val < n; ++val) { - if (lengths[val] == len) { - - // bit-reverse the code - code2 = 0; - t = code; - for (i = 0; i < len; ++i) { - code2 = (code2 << 1) | (t & 1); - t >>= 1; - } - - // fill in the table entries - for (i = code2; i < tabSize; i += skip) { - tab->codes[i].len = (Gushort)len; - tab->codes[i].val = (Gushort)val; - } - - ++code; - } - } - } -} - -int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) { - FlateCode *code; - int c; - - while (codeSize < tab->maxLen) { - if ((c = str->getChar()) == EOF) { - break; - } - codeBuf |= (c & 0xff) << codeSize; - codeSize += 8; - } - code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)]; - if (codeSize == 0 || codeSize < code->len || code->len == 0) { - return EOF; - } - codeBuf >>= code->len; - codeSize -= code->len; - return (int)code->val; -} - -int FlateStream::getCodeWord(int bits) { - int c; - - while (codeSize < bits) { - if ((c = str->getChar()) == EOF) - return EOF; - codeBuf |= (c & 0xff) << codeSize; - codeSize += 8; - } - c = codeBuf & ((1 << bits) - 1); - codeBuf >>= bits; - codeSize -= bits; - return c; -} - -//------------------------------------------------------------------------ -// EOFStream -//------------------------------------------------------------------------ - -EOFStream::EOFStream(Stream *strA): - FilterStream(strA) { -} - -EOFStream::~EOFStream() { - delete str; -} - -//------------------------------------------------------------------------ -// FixedLengthEncoder -//------------------------------------------------------------------------ - -FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA): - FilterStream(strA) { - length = lengthA; - count = 0; -} - -FixedLengthEncoder::~FixedLengthEncoder() { - if (str->isEncoder()) - delete str; -} - -void FixedLengthEncoder::reset() { - str->reset(); - count = 0; -} - -int FixedLengthEncoder::getChar() { - if (length >= 0 && count >= length) - return EOF; - ++count; - return str->getChar(); -} - -int FixedLengthEncoder::lookChar() { - if (length >= 0 && count >= length) - return EOF; - return str->getChar(); -} - -GBool FixedLengthEncoder::isBinary(GBool /*last*/) { - return str->isBinary(gTrue); -} - -//------------------------------------------------------------------------ -// ASCIIHexEncoder -//------------------------------------------------------------------------ - -ASCIIHexEncoder::ASCIIHexEncoder(Stream *strA): - FilterStream(strA) { - bufPtr = bufEnd = buf; - lineLen = 0; - eof = gFalse; -} - -ASCIIHexEncoder::~ASCIIHexEncoder() { - if (str->isEncoder()) { - delete str; - } -} - -void ASCIIHexEncoder::reset() { - str->reset(); - bufPtr = bufEnd = buf; - lineLen = 0; - eof = gFalse; -} - -GBool ASCIIHexEncoder::fillBuf() { - static const char *hex = "0123456789abcdef"; - int c; - - if (eof) { - return gFalse; - } - bufPtr = bufEnd = buf; - if ((c = str->getChar()) == EOF) { - *bufEnd++ = '>'; - eof = gTrue; - } else { - if (lineLen >= 64) { - *bufEnd++ = '\n'; - lineLen = 0; - } - *bufEnd++ = hex[(c >> 4) & 0x0f]; - *bufEnd++ = hex[c & 0x0f]; - lineLen += 2; - } - return gTrue; -} - -//------------------------------------------------------------------------ -// ASCII85Encoder -//------------------------------------------------------------------------ - -ASCII85Encoder::ASCII85Encoder(Stream *strA): - FilterStream(strA) { - bufPtr = bufEnd = buf; - lineLen = 0; - eof = gFalse; -} - -ASCII85Encoder::~ASCII85Encoder() { - if (str->isEncoder()) - delete str; -} - -void ASCII85Encoder::reset() { - str->reset(); - bufPtr = bufEnd = buf; - lineLen = 0; - eof = gFalse; -} - -GBool ASCII85Encoder::fillBuf() { - Gulong t; - char buf1[5]; - int c; - int n, i; - - if (eof) - return gFalse; - t = 0; - for (n = 0; n < 4; ++n) { - if ((c = str->getChar()) == EOF) - break; - t = (t << 8) + c; - } - bufPtr = bufEnd = buf; - if (n > 0) { - if (n == 4 && t == 0) { - *bufEnd++ = 'z'; - if (++lineLen == 65) { - *bufEnd++ = '\n'; - lineLen = 0; - } - } else { - if (n < 4) - t <<= 8 * (4 - n); - for (i = 4; i >= 0; --i) { - buf1[i] = (char)(t % 85 + 0x21); - t /= 85; - } - for (i = 0; i <= n; ++i) { - *bufEnd++ = buf1[i]; - if (++lineLen == 65) { - *bufEnd++ = '\n'; - lineLen = 0; - } - } - } - } - if (n < 4) { - *bufEnd++ = '~'; - *bufEnd++ = '>'; - eof = gTrue; - } - return bufPtr < bufEnd; -} - -//------------------------------------------------------------------------ -// RunLengthEncoder -//------------------------------------------------------------------------ - -RunLengthEncoder::RunLengthEncoder(Stream *strA): - FilterStream(strA) { - bufPtr = bufEnd = nextEnd = buf; - eof = gFalse; -} - -RunLengthEncoder::~RunLengthEncoder() { - if (str->isEncoder()) - delete str; -} - -void RunLengthEncoder::reset() { - str->reset(); - bufPtr = bufEnd = nextEnd = buf; - eof = gFalse; -} - -// -// When fillBuf finishes, buf[] looks like this: -// +-----+--------------+-----------------+-- -// + tag | ... data ... | next 0, 1, or 2 | -// +-----+--------------+-----------------+-- -// ^ ^ ^ -// bufPtr bufEnd nextEnd -// -GBool RunLengthEncoder::fillBuf() { - int c, c1, c2; - int n; - - // already hit EOF? - if (eof) - return gFalse; - - // grab two bytes - if (nextEnd < bufEnd + 1) { - if ((c1 = str->getChar()) == EOF) { - eof = gTrue; - return gFalse; - } - } else { - c1 = bufEnd[0] & 0xff; - } - if (nextEnd < bufEnd + 2) { - if ((c2 = str->getChar()) == EOF) { - eof = gTrue; - buf[0] = 0; - buf[1] = c1; - bufPtr = buf; - bufEnd = &buf[2]; - return gTrue; - } - } else { - c2 = bufEnd[1] & 0xff; - } - - // check for repeat - c = 0; // make gcc happy - if (c1 == c2) { - n = 2; - while (n < 128 && (c = str->getChar()) == c1) - ++n; - buf[0] = (char)(257 - n); - buf[1] = c1; - bufEnd = &buf[2]; - if (c == EOF) { - eof = gTrue; - } else if (n < 128) { - buf[2] = c; - nextEnd = &buf[3]; - } else { - nextEnd = bufEnd; - } - - // get up to 128 chars - } else { - buf[1] = c1; - buf[2] = c2; - n = 2; - while (n < 128) { - if ((c = str->getChar()) == EOF) { - eof = gTrue; - break; - } - ++n; - buf[n] = c; - if (buf[n] == buf[n-1]) - break; - } - if (buf[n] == buf[n-1]) { - buf[0] = (char)(n-2-1); - bufEnd = &buf[n-1]; - nextEnd = &buf[n+1]; - } else { - buf[0] = (char)(n-1); - bufEnd = nextEnd = &buf[n+1]; - } - } - bufPtr = buf; - return gTrue; -} diff --git a/xpdf/xpdf/Stream.h b/xpdf/xpdf/Stream.h deleted file mode 100644 index 085f3a0a1..000000000 --- a/xpdf/xpdf/Stream.h +++ /dev/null @@ -1,850 +0,0 @@ -//======================================================================== -// -// Stream.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef STREAM_H -#define STREAM_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include "gtypes.h" -#include "Object.h" - -class Decrypt; -class BaseStream; - -//------------------------------------------------------------------------ - -enum StreamKind { - strFile, - strASCIIHex, - strASCII85, - strLZW, - strRunLength, - strCCITTFax, - strDCT, - strFlate, - strJBIG2, - strJPX, - strWeird // internal-use stream types -}; - -enum StreamColorSpaceMode { - streamCSNone, - streamCSDeviceGray, - streamCSDeviceRGB, - streamCSDeviceCMYK -}; - -//------------------------------------------------------------------------ -// Stream (base class) -//------------------------------------------------------------------------ - -class Stream { -public: - - // Constructor. - Stream(); - - // Destructor. - virtual ~Stream(); - - // Reference counting. - int incRef() { return ++ref; } - int decRef() { return --ref; } - - // Get kind of stream. - virtual StreamKind getKind() = 0; - - // Reset stream to beginning. - virtual void reset() = 0; - - // Close down the stream. - virtual void close(); - - // Get next char from stream. - virtual int getChar() = 0; - - // Peek at next char in stream. - virtual int lookChar() = 0; - - // Get next char from stream without using the predictor. - // This is only used by StreamPredictor. - virtual int getRawChar(); - - // Get next line from stream. - virtual char *getLine(char *buf, int size); - - // Get current position in file. - virtual int getPos() = 0; - - // Go to a position in the stream. If

is negative, the - // position is from the end of the file; otherwise the position is - // from the start of the file. - virtual void setPos(Guint pos, int dir = 0) = 0; - - // Get PostScript command for the filter(s). - virtual GString *getPSFilter(int psLevel, const char *indent); - - // Does this stream type potentially contain non-printable chars? - virtual GBool isBinary(GBool last = gTrue) = 0; - - // Get the BaseStream of this stream. - virtual BaseStream *getBaseStream() = 0; - - // Get the dictionary associated with this stream. - virtual Dict *getDict() = 0; - - // Is this an encoding filter? - virtual GBool isEncoder() { return gFalse; } - - // Get image parameters which are defined by the stream contents. - virtual void getImageParams(int */*bitsPerComponent*/, - StreamColorSpaceMode */*csMode*/) {} - - // Add filters to this stream according to the parameters in . - // Returns the new stream. - Stream *addFilters(Object *dict); - -private: - - Stream *makeFilter(const char *name, Stream *str, Object *params); - - int ref; // reference count -}; - -//------------------------------------------------------------------------ -// BaseStream -// -// This is the base class for all streams that read directly from a file. -//------------------------------------------------------------------------ - -class BaseStream: public Stream { -public: - - BaseStream(Object *dictA); - virtual ~BaseStream(); - virtual Stream *makeSubStream(Guint start, GBool limited, - Guint length, Object *dict) = 0; - virtual void setPos(Guint pos, int dir = 0) = 0; - virtual GBool isBinary(GBool last = gTrue) { return last; } - virtual BaseStream *getBaseStream() { return this; } - virtual Dict *getDict() { return dict.getDict(); } - - // Get/set position of first byte of stream within the file. - virtual Guint getStart() = 0; - virtual void moveStart(int delta) = 0; - - // Set decryption for this stream. - virtual void doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen); - -protected: - - Decrypt *decrypt; - -private: - - Object dict; -}; - -//------------------------------------------------------------------------ -// FilterStream -// -// This is the base class for all streams that filter another stream. -//------------------------------------------------------------------------ - -class FilterStream: public Stream { -public: - - FilterStream(Stream *strA); - virtual ~FilterStream(); - virtual void close(); - virtual int getPos() { return str->getPos(); } - virtual void setPos(Guint pos, int dir = 0); - virtual BaseStream *getBaseStream() { return str->getBaseStream(); } - virtual Dict *getDict() { return str->getDict(); } - -protected: - - Stream *str; -}; - -//------------------------------------------------------------------------ -// ImageStream -//------------------------------------------------------------------------ - -class ImageStream { -public: - - // Create an image stream object for an image with the specified - // parameters. Note that these are the actual image parameters, - // which may be different from the predictor parameters. - ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA); - - ~ImageStream(); - - // Reset the stream. - void reset(); - - // Gets the next pixel from the stream. should be able to hold - // at least nComps elements. Returns false at end of file. - GBool getPixel(Guchar *pix); - - // Returns a pointer to the next line of pixels. Returns NULL at - // end of file. - Guchar *getLine(); - - // Skip an entire line from the image. - void skipLine(); - -private: - - Stream *str; // base stream - int width; // pixels per line - int nComps; // components per pixel - int nBits; // bits per component - int nVals; // components per line - Guchar *imgLine; // line buffer - int imgIdx; // current index in imgLine -}; - -//------------------------------------------------------------------------ -// StreamPredictor -//------------------------------------------------------------------------ - -class StreamPredictor { -public: - - // Create a predictor object. Note that the parameters are for the - // predictor, and may not match the actual image parameters. - StreamPredictor(Stream *strA, int predictorA, - int widthA, int nCompsA, int nBitsA); - - ~StreamPredictor(); - - GBool isOk() { return ok; } - - int lookChar(); - int getChar(); - -private: - - GBool getNextLine(); - - Stream *str; // base stream - int predictor; // predictor - int width; // pixels per line - int nComps; // components per pixel - int nBits; // bits per component - int nVals; // components per line - int pixBytes; // bytes per pixel - int rowBytes; // bytes per line - Guchar *predLine; // line buffer - int predIdx; // current index in predLine - GBool ok; -}; - -//------------------------------------------------------------------------ -// FileStream -//------------------------------------------------------------------------ - -#define fileStreamBufSize 256 - -class FileStream: public BaseStream { -public: - - FileStream(FILE *fA, Guint startA, GBool limitedA, - Guint lengthA, Object *dictA); - virtual ~FileStream(); - virtual Stream *makeSubStream(Guint startA, GBool limitedA, - Guint lengthA, Object *dictA); - virtual StreamKind getKind() { return strFile; } - virtual void reset(); - virtual void close(); - virtual int getChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } - virtual int lookChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual int getPos() { return bufPos + (bufPtr - buf); } - virtual void setPos(Guint pos, int dir = 0); - virtual Guint getStart() { return start; } - virtual void moveStart(int delta); - -private: - - GBool fillBuf(); - - FILE *f; - Guint start; - GBool limited; - Guint length; - char buf[fileStreamBufSize]; - char *bufPtr; - char *bufEnd; - Guint bufPos; - int savePos; - GBool saved; -}; - -//------------------------------------------------------------------------ -// MemStream -//------------------------------------------------------------------------ - -class MemStream: public BaseStream { -public: - - MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA); - virtual ~MemStream(); - virtual Stream *makeSubStream(Guint start, GBool limited, - Guint lengthA, Object *dictA); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual void close(); - virtual int getChar() - { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; } - virtual int lookChar() - { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; } - virtual int getPos() { return (int)(bufPtr - buf); } - virtual void setPos(Guint pos, int dir = 0); - virtual Guint getStart() { return start; } - virtual void moveStart(int delta); - virtual void doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen); - -private: - - char *buf; - Guint start; - Guint length; - char *bufEnd; - char *bufPtr; - GBool needFree; -}; - -//------------------------------------------------------------------------ -// EmbedStream -// -// This is a special stream type used for embedded streams (inline -// images). It reads directly from the base stream -- after the -// EmbedStream is deleted, reads from the base stream will proceed where -// the BaseStream left off. Note that this is very different behavior -// that creating a new FileStream (using makeSubStream). -//------------------------------------------------------------------------ - -class EmbedStream: public BaseStream { -public: - - EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Guint lengthA); - virtual ~EmbedStream(); - virtual Stream *makeSubStream(Guint start, GBool limitedA, - Guint lengthA, Object *dictA); - virtual StreamKind getKind() { return str->getKind(); } - virtual void reset() {} - virtual int getChar(); - virtual int lookChar(); - virtual int getPos() { return str->getPos(); } - virtual void setPos(Guint pos, int dir = 0); - virtual Guint getStart(); - virtual void moveStart(int delta); - -private: - - Stream *str; - GBool limited; - Guint length; -}; - -//------------------------------------------------------------------------ -// ASCIIHexStream -//------------------------------------------------------------------------ - -class ASCIIHexStream: public FilterStream { -public: - - ASCIIHexStream(Stream *strA); - virtual ~ASCIIHexStream(); - virtual StreamKind getKind() { return strASCIIHex; } - virtual void reset(); - virtual int getChar() - { int c = lookChar(); buf = EOF; return c; } - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - int buf; - GBool eof; -}; - -//------------------------------------------------------------------------ -// ASCII85Stream -//------------------------------------------------------------------------ - -class ASCII85Stream: public FilterStream { -public: - - ASCII85Stream(Stream *strA); - virtual ~ASCII85Stream(); - virtual StreamKind getKind() { return strASCII85; } - virtual void reset(); - virtual int getChar() - { int ch = lookChar(); ++index; return ch; } - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - int c[5]; - int b[4]; - int index, n; - GBool eof; -}; - -//------------------------------------------------------------------------ -// LZWStream -//------------------------------------------------------------------------ - -class LZWStream: public FilterStream { -public: - - LZWStream(Stream *strA, int predictor, int columns, int colors, - int bits, int earlyA); - virtual ~LZWStream(); - virtual StreamKind getKind() { return strLZW; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual int getRawChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - StreamPredictor *pred; // predictor - int early; // early parameter - GBool eof; // true if at eof - int inputBuf; // input buffer - int inputBits; // number of bits in input buffer - struct { // decoding table - int length; - int head; - Guchar tail; - } table[4097]; - int nextCode; // next code to be used - int nextBits; // number of bits in next code word - int prevCode; // previous code used in stream - int newChar; // next char to be added to table - Guchar seqBuf[4097]; // buffer for current sequence - int seqLength; // length of current sequence - int seqIndex; // index into current sequence - GBool first; // first code after a table clear - - GBool processNextCode(); - void clearTable(); - int getCode(); -}; - -//------------------------------------------------------------------------ -// RunLengthStream -//------------------------------------------------------------------------ - -class RunLengthStream: public FilterStream { -public: - - RunLengthStream(Stream *strA); - virtual ~RunLengthStream(); - virtual StreamKind getKind() { return strRunLength; } - virtual void reset(); - virtual int getChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } - virtual int lookChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - char buf[128]; // buffer - char *bufPtr; // next char to read - char *bufEnd; // end of buffer - GBool eof; - - GBool fillBuf(); -}; - -//------------------------------------------------------------------------ -// CCITTFaxStream -//------------------------------------------------------------------------ - -struct CCITTCodeTable; - -class CCITTFaxStream: public FilterStream { -public: - - CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, - GBool byteAlignA, int columnsA, int rowsA, - GBool endOfBlockA, GBool blackA); - virtual ~CCITTFaxStream(); - virtual StreamKind getKind() { return strCCITTFax; } - virtual void reset(); - virtual int getChar() - { int c = lookChar(); buf = EOF; return c; } - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - int encoding; // 'K' parameter - GBool endOfLine; // 'EndOfLine' parameter - GBool byteAlign; // 'EncodedByteAlign' parameter - int columns; // 'Columns' parameter - int rows; // 'Rows' parameter - GBool endOfBlock; // 'EndOfBlock' parameter - GBool black; // 'BlackIs1' parameter - GBool eof; // true if at eof - GBool nextLine2D; // true if next line uses 2D encoding - int row; // current row - int inputBuf; // input buffer - int inputBits; // number of bits in input buffer - short *refLine; // reference line changing elements - int b1; // index into refLine - short *codingLine; // coding line changing elements - int a0; // index into codingLine - int outputBits; // remaining ouput bits - int buf; // character buffer - - short getTwoDimCode(); - short getWhiteCode(); - short getBlackCode(); - short lookBits(int n); - void eatBits(int n) { inputBits -= n; } -}; - - -#if 0 - -//------------------------------------------------------------------------ -// DCTStream -//------------------------------------------------------------------------ - -// DCT component info -struct DCTCompInfo { - int id; // component ID - int hSample, vSample; // horiz/vert sampling resolutions - int quantTable; // quantization table number - int prevDC; // DC coefficient accumulator -}; - -struct DCTScanInfo { - GBool comp[4]; // comp[i] is set if component i is - // included in this scan - int numComps; // number of components in the scan - int dcHuffTable[4]; // DC Huffman table numbers - int acHuffTable[4]; // AC Huffman table numbers - int firstCoeff, lastCoeff; // first and last DCT coefficient - int ah, al; // successive approximation parameters -}; - -// DCT Huffman decoding table -struct DCTHuffTable { - Guchar firstSym[17]; // first symbol for this bit length - Gushort firstCode[17]; // first code for this bit length - Gushort numCodes[17]; // number of codes of this bit length - Guchar sym[256]; // symbols -}; - -class DCTStream: public FilterStream { -public: - - DCTStream(Stream *strA); - virtual ~DCTStream(); - virtual StreamKind getKind() { return strDCT; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - Stream *getRawStream() { return str; } - -private: - - GBool progressive; // set if in progressive mode - GBool interleaved; // set if in interleaved mode - int width, height; // image size - int mcuWidth, mcuHeight; // size of min coding unit, in data units - int bufWidth, bufHeight; // frameBuf size - DCTCompInfo compInfo[4]; // info for each component - DCTScanInfo scanInfo; // info for the current scan - int numComps; // number of components in image - int colorXform; // need YCbCr-to-RGB transform? - GBool gotJFIFMarker; // set if APP0 JFIF marker was present - GBool gotAdobeMarker; // set if APP14 Adobe marker was present - int restartInterval; // restart interval, in MCUs - Gushort quantTables[4][64]; // quantization tables - int numQuantTables; // number of quantization tables - DCTHuffTable dcHuffTables[4]; // DC Huffman tables - DCTHuffTable acHuffTables[4]; // AC Huffman tables - int numDCHuffTables; // number of DC Huffman tables - int numACHuffTables; // number of AC Huffman tables - Guchar *rowBuf[4][32]; // buffer for one MCU (non-progressive mode) - int *frameBuf[4]; // buffer for frame (progressive mode) - int comp, x, y, dy; // current position within image/MCU - int restartCtr; // MCUs left until restart - int restartMarker; // next restart marker - int eobRun; // number of EOBs left in the current run - int inputBuf; // input buffer for variable length codes - int inputBits; // number of valid bits in input buffer - - void restart(); - GBool readMCURow(); - void readScan(); - GBool readDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - int *prevDC, int data[64]); - GBool readProgressiveDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - int *prevDC, int data[64]); - void decodeImage(); - void transformDataUnit(Gushort *quantTable, - int dataIn[64], Guchar dataOut[64]); - int readHuffSym(DCTHuffTable *table); - int readAmp(int size); - int readBit(); - GBool readHeader(); - GBool readBaselineSOF(); - GBool readProgressiveSOF(); - GBool readScanInfo(); - GBool readQuantTables(); - GBool readHuffmanTables(); - GBool readRestartInterval(); - GBool readJFIFMarker(); - GBool readAdobeMarker(); - GBool readTrailer(); - int readMarker(); - int read16(); -}; -#endif - -//------------------------------------------------------------------------ -// FlateStream -//------------------------------------------------------------------------ - -#define flateWindow 32768 // buffer size -#define flateMask (flateWindow-1) -#define flateMaxHuffman 15 // max Huffman code length -#define flateMaxCodeLenCodes 19 // max # code length codes -#define flateMaxLitCodes 288 // max # literal codes -#define flateMaxDistCodes 30 // max # distance codes - -// Huffman code table entry -struct FlateCode { - Gushort len; // code length, in bits - Gushort val; // value represented by this code -}; - -struct FlateHuffmanTab { - FlateCode *codes; - int maxLen; -}; - -// Decoding info for length and distance code words -struct FlateDecode { - int bits; // # extra bits - int first; // first length/distance -}; - -class FlateStream: public FilterStream { -public: - - FlateStream(Stream *strA, int predictor, int columns, - int colors, int bits); - virtual ~FlateStream(); - virtual StreamKind getKind() { return strFlate; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual int getRawChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - StreamPredictor *pred; // predictor - Guchar buf[flateWindow]; // output data buffer - int index; // current index into output buffer - int remain; // number valid bytes in output buffer - int codeBuf; // input buffer - int codeSize; // number of bits in input buffer - int // literal and distance code lengths - codeLengths[flateMaxLitCodes + flateMaxDistCodes]; - FlateHuffmanTab litCodeTab; // literal code table - FlateHuffmanTab distCodeTab; // distance code table - GBool compressedBlock; // set if reading a compressed block - int blockLen; // remaining length of uncompressed block - GBool endOfBlock; // set when end of block is reached - GBool eof; // set when end of stream is reached - - static int // code length code reordering - codeLenCodeMap[flateMaxCodeLenCodes]; - static FlateDecode // length decoding info - lengthDecode[flateMaxLitCodes-257]; - static FlateDecode // distance decoding info - distDecode[flateMaxDistCodes]; - static FlateHuffmanTab // fixed literal code table - fixedLitCodeTab; - static FlateHuffmanTab // fixed distance code table - fixedDistCodeTab; - - void readSome(); - GBool startBlock(); - void loadFixedCodes(); - GBool readDynamicCodes(); - void compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab); - int getHuffmanCodeWord(FlateHuffmanTab *tab); - int getCodeWord(int bits); -}; - -//------------------------------------------------------------------------ -// EOFStream -//------------------------------------------------------------------------ - -class EOFStream: public FilterStream { -public: - - EOFStream(Stream *strA); - virtual ~EOFStream(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset() {} - virtual int getChar() { return EOF; } - virtual int lookChar() { return EOF; } - virtual GString *getPSFilter(int /*psLevel*/, const char */*indent*/) { return NULL; } - virtual GBool isBinary(GBool /*last = gTrue*/) { return gFalse; } -}; - -//------------------------------------------------------------------------ -// FixedLengthEncoder -//------------------------------------------------------------------------ - -class FixedLengthEncoder: public FilterStream { -public: - - FixedLengthEncoder(Stream *strA, int lengthA); - ~FixedLengthEncoder(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual GString *getPSFilter(int /*psLevel*/, const char */*indent*/) { return NULL; } - virtual GBool isBinary(GBool last = gTrue); - virtual GBool isEncoder() { return gTrue; } - -private: - - int length; - int count; -}; - -//------------------------------------------------------------------------ -// ASCIIHexEncoder -//------------------------------------------------------------------------ - -class ASCIIHexEncoder: public FilterStream { -public: - - ASCIIHexEncoder(Stream *strA); - virtual ~ASCIIHexEncoder(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual int getChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } - virtual int lookChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int /*psLevel*/, const char */*indent*/) { return NULL; } - virtual GBool isBinary(GBool /*last = gTrue*/) { return gFalse; } - virtual GBool isEncoder() { return gTrue; } - -private: - - char buf[4]; - char *bufPtr; - char *bufEnd; - int lineLen; - GBool eof; - - GBool fillBuf(); -}; - -//------------------------------------------------------------------------ -// ASCII85Encoder -//------------------------------------------------------------------------ - -class ASCII85Encoder: public FilterStream { -public: - - ASCII85Encoder(Stream *strA); - virtual ~ASCII85Encoder(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual int getChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } - virtual int lookChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int /*psLevel*/, const char */*indent*/) { return NULL; } - virtual GBool isBinary(GBool /*last = gTrue*/) { return gFalse; } - virtual GBool isEncoder() { return gTrue; } - -private: - - char buf[8]; - char *bufPtr; - char *bufEnd; - int lineLen; - GBool eof; - - GBool fillBuf(); -}; - -//------------------------------------------------------------------------ -// RunLengthEncoder -//------------------------------------------------------------------------ - -class RunLengthEncoder: public FilterStream { -public: - - RunLengthEncoder(Stream *strA); - virtual ~RunLengthEncoder(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual int getChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } - virtual int lookChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int /*psLevel*/, const char */*indent*/) { return NULL; } - virtual GBool isBinary(GBool /*last = gTrue*/) { return gTrue; } - virtual GBool isEncoder() { return gTrue; } - -private: - - char buf[131]; - char *bufPtr; - char *bufEnd; - char *nextEnd; - GBool eof; - - GBool fillBuf(); -}; - -#endif diff --git a/xpdf/xpdf/TextOutputDev.cc b/xpdf/xpdf/TextOutputDev.cc deleted file mode 100644 index c74228fa6..000000000 --- a/xpdf/xpdf/TextOutputDev.cc +++ /dev/null @@ -1,3613 +0,0 @@ -//======================================================================== -// -// TextOutputDev.cc -// -// Copyright 1997-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include -#ifdef WIN32 -#include // for O_BINARY -#include // for setmode -#endif -#include "gmem.h" -#include "GString.h" -#include "GList.h" -#include "xpdf_config.h" -#include "Error.h" -#include "GlobalParams.h" -#include "UnicodeMap.h" -#include "UnicodeTypeTable.h" -#include "GfxState.h" -#include "TextOutputDev.h" - -#ifdef MACOS -// needed for setting type/creator of MacOS files -#include "ICSupport.h" -#endif - -//------------------------------------------------------------------------ -// parameters -//------------------------------------------------------------------------ - -// Each bucket in a text pool includes baselines within a range of -// this many points. -#define textPoolStep 4 - -// Inter-character space width which will cause addChar to start a new -// word. -#define minWordBreakSpace 0.1 - -// Negative inter-character space width, i.e., overlap, which will -// cause addChar to start a new word. -#define minDupBreakOverlap 0.2 - -// Max distance between baselines of two lines within a block, as a -// fraction of the font size. -#define maxLineSpacingDelta 1.5 - -// Max difference in primary font sizes on two lines in the same -// block. Delta1 is used when examining new lines above and below the -// current block; delta2 is used when examining text that overlaps the -// current block; delta3 is used when examining text to the left and -// right of the current block. -#define maxBlockFontSizeDelta1 0.05 -#define maxBlockFontSizeDelta2 0.6 -#define maxBlockFontSizeDelta3 0.2 - -// Max difference in font sizes inside a word. -#define maxWordFontSizeDelta 0.05 - -// Maximum distance between baselines of two words on the same line, -// e.g., distance between subscript or superscript and the primary -// baseline, as a fraction of the font size. -#define maxIntraLineDelta 0.5 - -// Minimum inter-word spacing, as a fraction of the font size. (Only -// used for raw ordering.) -#define minWordSpacing 0.15 - -// Maximum inter-word spacing, as a fraction of the font size. -#define maxWordSpacing 1.5 - -// Maximum horizontal spacing which will allow a word to be pulled -// into a block. -#define minColSpacing1 0.3 - -// Minimum spacing between columns, as a fraction of the font size. -#define minColSpacing2 1.0 - -// Maximum vertical spacing between blocks within a flow, as a -// multiple of the font size. -#define maxBlockSpacing 2.5 - -// Minimum spacing between characters within a word, as a fraction of -// the font size. -#define minCharSpacing -0.2 - -// Maximum spacing between characters within a word, as a fraction of -// the font size, when there is no obvious extra-wide character -// spacing. -#define maxCharSpacing 0.03 - -// When extra-wide character spacing is detected, the inter-character -// space threshold is set to the minimum inter-character space -// multiplied by this constant. -#define maxWideCharSpacingMul 1.3 - -// Max difference in primary,secondary coordinates (as a fraction of -// the font size) allowed for duplicated text (fake boldface, drop -// shadows) which is to be discarded. -#define dupMaxPriDelta 0.1 -#define dupMaxSecDelta 0.2 - -//------------------------------------------------------------------------ -// TextFontInfo -//------------------------------------------------------------------------ - -TextFontInfo::TextFontInfo(GfxState *state) { - gfxFont = state->getFont(); -#if TEXTOUT_WORD_LIST - fontName = (gfxFont && gfxFont->getOrigName()) - ? gfxFont->getOrigName()->copy() - : (GString *)NULL; -#endif -} - -TextFontInfo::~TextFontInfo() { -#if TEXTOUT_WORD_LIST - if (fontName) { - delete fontName; - } -#endif -} - -GBool TextFontInfo::matches(GfxState *state) { - return state->getFont() == gfxFont; -} - -//------------------------------------------------------------------------ -// TextWord -//------------------------------------------------------------------------ - -TextWord::TextWord(GfxState *state, int rotA, double x0, double y0, - int charPosA, TextFontInfo *fontA, double fontSizeA) { - GfxFont *gfxFont; - double x, y, ascent, descent; - - rot = rotA; - charPos = charPosA; - charLen = 0; - font = fontA; - fontSize = fontSizeA; - state->transform(x0, y0, &x, &y); - if ((gfxFont = font->gfxFont)) { - ascent = gfxFont->getAscent() * fontSize; - descent = gfxFont->getDescent() * fontSize; - } else { - // this means that the PDF file draws text without a current font, - // which should never happen - ascent = 0.95 * fontSize; - descent = -0.35 * fontSize; - } - switch (rot) { - case 0: - yMin = y - ascent; - yMax = y - descent; - if (yMin == yMax) { - // this is a sanity check for a case that shouldn't happen -- but - // if it does happen, we want to avoid dividing by zero later - yMin = y; - yMax = y + 1; - } - base = y; - break; - case 1: - xMin = x + descent; - xMax = x + ascent; - if (xMin == xMax) { - // this is a sanity check for a case that shouldn't happen -- but - // if it does happen, we want to avoid dividing by zero later - xMin = x; - xMax = x + 1; - } - base = x; - break; - case 2: - yMin = y + descent; - yMax = y + ascent; - if (yMin == yMax) { - // this is a sanity check for a case that shouldn't happen -- but - // if it does happen, we want to avoid dividing by zero later - yMin = y; - yMax = y + 1; - } - base = y; - break; - case 3: - xMin = x - ascent; - xMax = x - descent; - if (xMin == xMax) { - // this is a sanity check for a case that shouldn't happen -- but - // if it does happen, we want to avoid dividing by zero later - xMin = x; - xMax = x + 1; - } - base = x; - break; - } - text = NULL; - edge = NULL; - len = size = 0; - spaceAfter = gFalse; - next = NULL; - -#if TEXTOUT_WORD_LIST - GfxRGB rgb; - - if ((state->getRender() & 3) == 1) { - state->getStrokeRGB(&rgb); - } else { - state->getFillRGB(&rgb); - } - colorR = colToDbl(rgb.r); - colorG = colToDbl(rgb.g); - colorB = colToDbl(rgb.b); -#endif -} - -TextWord::~TextWord() { - gfree(text); - gfree(edge); -} - -void TextWord::addChar(GfxState */*state*/, double x, double y, - double dx, double dy, Unicode u) { - if (len == size) { - size += 16; - text = (Unicode *)greallocn(text, size, sizeof(Unicode)); - edge = (double *)greallocn(edge, size + 1, sizeof(double)); - } - text[len] = u; - switch (rot) { - case 0: - if (len == 0) { - xMin = x; - } - edge[len] = x; - xMax = edge[len+1] = x + dx; - break; - case 1: - if (len == 0) { - yMin = y; - } - edge[len] = y; - yMax = edge[len+1] = y + dy; - break; - case 2: - if (len == 0) { - xMax = x; - } - edge[len] = x; - xMin = edge[len+1] = x + dx; - break; - case 3: - if (len == 0) { - yMax = y; - } - edge[len] = y; - yMin = edge[len+1] = y + dy; - break; - } - ++len; -} - -void TextWord::merge(TextWord *word) { - int i; - - if (word->xMin < xMin) { - xMin = word->xMin; - } - if (word->yMin < yMin) { - yMin = word->yMin; - } - if (word->xMax > xMax) { - xMax = word->xMax; - } - if (word->yMax > yMax) { - yMax = word->yMax; - } - if (len + word->len > size) { - size = len + word->len; - text = (Unicode *)greallocn(text, size, sizeof(Unicode)); - edge = (double *)greallocn(edge, size + 1, sizeof(double)); - } - for (i = 0; i < word->len; ++i) { - text[len + i] = word->text[i]; - edge[len + i] = word->edge[i]; - } - edge[len + word->len] = word->edge[word->len]; - len += word->len; - charLen += word->charLen; -} - -inline int TextWord::primaryCmp(TextWord *word) { - double cmp; - - cmp = 0; // make gcc happy - switch (rot) { - case 0: - cmp = xMin - word->xMin; - break; - case 1: - cmp = yMin - word->yMin; - break; - case 2: - cmp = word->xMax - xMax; - break; - case 3: - cmp = word->yMax - yMax; - break; - } - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -double TextWord::primaryDelta(TextWord *word) { - double delta; - - delta = 0; // make gcc happy - switch (rot) { - case 0: - delta = word->xMin - xMax; - break; - case 1: - delta = word->yMin - yMax; - break; - case 2: - delta = xMin - word->xMax; - break; - case 3: - delta = yMin - word->yMax; - break; - } - return delta; -} - -int TextWord::cmpYX(const void *p1, const void *p2) { - TextWord *word1 = *(TextWord **)p1; - TextWord *word2 = *(TextWord **)p2; - double cmp; - - cmp = word1->yMin - word2->yMin; - if (cmp == 0) { - cmp = word1->xMin - word2->xMin; - } - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -#if TEXTOUT_WORD_LIST - -GString *TextWord::getText() { - GString *s; - UnicodeMap *uMap; - char buf[8]; - int n, i; - - s = new GString(); - if (!(uMap = globalParams->getTextEncoding())) { - return s; - } - for (i = 0; i < len; ++i) { - n = uMap->mapUnicode(text[i], buf, sizeof(buf)); - s->append(buf, n); - } - uMap->decRefCnt(); - return s; -} - -#endif // TEXTOUT_WORD_LIST - -//------------------------------------------------------------------------ -// TextPool -//------------------------------------------------------------------------ - -TextPool::TextPool() { - minBaseIdx = 0; - maxBaseIdx = -1; - pool = NULL; - cursor = NULL; - cursorBaseIdx = -1; -} - -TextPool::~TextPool() { - int baseIdx; - TextWord *word, *word2; - - for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) { - for (word = pool[baseIdx - minBaseIdx]; word; word = word2) { - word2 = word->next; - delete word; - } - } - gfree(pool); -} - -int TextPool::getBaseIdx(double base) { - int baseIdx; - - baseIdx = (int)(base / textPoolStep); - if (baseIdx < minBaseIdx) { - return minBaseIdx; - } - if (baseIdx > maxBaseIdx) { - return maxBaseIdx; - } - return baseIdx; -} - -void TextPool::addWord(TextWord *word) { - TextWord **newPool; - int wordBaseIdx, newMinBaseIdx, newMaxBaseIdx, baseIdx; - TextWord *w0, *w1; - - // expand the array if needed - wordBaseIdx = (int)(word->base / textPoolStep); - if (minBaseIdx > maxBaseIdx) { - minBaseIdx = wordBaseIdx - 128; - maxBaseIdx = wordBaseIdx + 128; - pool = (TextWord **)gmallocn(maxBaseIdx - minBaseIdx + 1, - sizeof(TextWord *)); - for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) { - pool[baseIdx - minBaseIdx] = NULL; - } - } else if (wordBaseIdx < minBaseIdx) { - newMinBaseIdx = wordBaseIdx - 128; - newPool = (TextWord **)gmallocn(maxBaseIdx - newMinBaseIdx + 1, - sizeof(TextWord *)); - for (baseIdx = newMinBaseIdx; baseIdx < minBaseIdx; ++baseIdx) { - newPool[baseIdx - newMinBaseIdx] = NULL; - } - memcpy(&newPool[minBaseIdx - newMinBaseIdx], pool, - (maxBaseIdx - minBaseIdx + 1) * sizeof(TextWord *)); - gfree(pool); - pool = newPool; - minBaseIdx = newMinBaseIdx; - } else if (wordBaseIdx > maxBaseIdx) { - newMaxBaseIdx = wordBaseIdx + 128; - pool = (TextWord **)greallocn(pool, newMaxBaseIdx - minBaseIdx + 1, - sizeof(TextWord *)); - for (baseIdx = maxBaseIdx + 1; baseIdx <= newMaxBaseIdx; ++baseIdx) { - pool[baseIdx - minBaseIdx] = NULL; - } - maxBaseIdx = newMaxBaseIdx; - } - - // insert the new word - if (cursor && wordBaseIdx == cursorBaseIdx && - word->primaryCmp(cursor) > 0) { - w0 = cursor; - w1 = cursor->next; - } else { - w0 = NULL; - w1 = pool[wordBaseIdx - minBaseIdx]; - } - for (; w1 && word->primaryCmp(w1) > 0; w0 = w1, w1 = w1->next) ; - word->next = w1; - if (w0) { - w0->next = word; - } else { - pool[wordBaseIdx - minBaseIdx] = word; - } - cursor = word; - cursorBaseIdx = wordBaseIdx; -} - -//------------------------------------------------------------------------ -// TextLine -//------------------------------------------------------------------------ - -TextLine::TextLine(TextBlock *blkA, int rotA, double baseA) { - blk = blkA; - rot = rotA; - xMin = yMin = 0; - xMax = yMax = -1; - base = baseA; - words = lastWord = NULL; - text = NULL; - edge = NULL; - col = NULL; - len = 0; - convertedLen = 0; - hyphenated = gFalse; - next = NULL; -} - -TextLine::~TextLine() { - TextWord *word; - - while (words) { - word = words; - words = words->next; - delete word; - } - gfree(text); - gfree(edge); - gfree(col); -} - -void TextLine::addWord(TextWord *word) { - if (lastWord) { - lastWord->next = word; - } else { - words = word; - } - lastWord = word; - - if (xMin > xMax) { - xMin = word->xMin; - xMax = word->xMax; - yMin = word->yMin; - yMax = word->yMax; - } else { - if (word->xMin < xMin) { - xMin = word->xMin; - } - if (word->xMax > xMax) { - xMax = word->xMax; - } - if (word->yMin < yMin) { - yMin = word->yMin; - } - if (word->yMax > yMax) { - yMax = word->yMax; - } - } -} - -double TextLine::primaryDelta(TextLine *line) { - double delta; - - delta = 0; // make gcc happy - switch (rot) { - case 0: - delta = line->xMin - xMax; - break; - case 1: - delta = line->yMin - yMax; - break; - case 2: - delta = xMin - line->xMax; - break; - case 3: - delta = yMin - line->yMax; - break; - } - return delta; -} - -int TextLine::primaryCmp(TextLine *line) { - double cmp; - - cmp = 0; // make gcc happy - switch (rot) { - case 0: - cmp = xMin - line->xMin; - break; - case 1: - cmp = yMin - line->yMin; - break; - case 2: - cmp = line->xMax - xMax; - break; - case 3: - cmp = line->yMax - yMax; - break; - } - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -int TextLine::secondaryCmp(TextLine *line) { - double cmp; - - cmp = (rot == 0 || rot == 3) ? base - line->base : line->base - base; - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -int TextLine::cmpYX(TextLine *line) { - int cmp; - - if ((cmp = secondaryCmp(line))) { - return cmp; - } - return primaryCmp(line); -} - -int TextLine::cmpXY(const void *p1, const void *p2) { - TextLine *line1 = *(TextLine **)p1; - TextLine *line2 = *(TextLine **)p2; - int cmp; - - if ((cmp = line1->primaryCmp(line2))) { - return cmp; - } - return line1->secondaryCmp(line2); -} - -void TextLine::coalesce(UnicodeMap *uMap) { - TextWord *word0, *word1; - double space, delta, minSpace; - GBool isUnicode; - char buf[8]; - int i, j; - - if (words->next) { - - // compute the inter-word space threshold - if (words->len > 1 || words->next->len > 1) { - minSpace = 0; - } else { - minSpace = words->primaryDelta(words->next); - for (word0 = words->next, word1 = word0->next; - word1 && minSpace > 0; - word0 = word1, word1 = word0->next) { - if (word1->len > 1) { - minSpace = 0; - } - delta = word0->primaryDelta(word1); - if (delta < minSpace) { - minSpace = delta; - } - } - } - if (minSpace <= 0) { - space = maxCharSpacing * words->fontSize; - } else { - space = maxWideCharSpacingMul * minSpace; - } - - // merge words - word0 = words; - word1 = words->next; - while (word1) { - if (word0->primaryDelta(word1) >= space) { - word0->spaceAfter = gTrue; - word0 = word1; - word1 = word1->next; - } else if (word0->font == word1->font && - fabs(word0->fontSize - word1->fontSize) < - maxWordFontSizeDelta * words->fontSize && - word1->charPos == word0->charPos + word0->charLen) { - word0->merge(word1); - word0->next = word1->next; - delete word1; - word1 = word0->next; - } else { - word0 = word1; - word1 = word1->next; - } - } - } - - // build the line text - isUnicode = uMap ? uMap->isUnicode() : gFalse; - len = 0; - for (word1 = words; word1; word1 = word1->next) { - len += word1->len; - if (word1->spaceAfter) { - ++len; - } - } - text = (Unicode *)gmallocn(len, sizeof(Unicode)); - edge = (double *)gmallocn(len + 1, sizeof(double)); - i = 0; - for (word1 = words; word1; word1 = word1->next) { - for (j = 0; j < word1->len; ++j) { - text[i] = word1->text[j]; - edge[i] = word1->edge[j]; - ++i; - } - edge[i] = word1->edge[word1->len]; - if (word1->spaceAfter) { - text[i] = (Unicode)0x0020; - ++i; - } - } - - // compute convertedLen and set up the col array - col = (int *)gmallocn(len + 1, sizeof(int)); - convertedLen = 0; - for (i = 0; i < len; ++i) { - col[i] = convertedLen; - if (isUnicode) { - ++convertedLen; - } else if (uMap) { - convertedLen += uMap->mapUnicode(text[i], buf, sizeof(buf)); - } - } - col[len] = convertedLen; - - // check for hyphen at end of line - //~ need to check for other chars used as hyphens - hyphenated = text[len - 1] == (Unicode)'-'; -} - -//------------------------------------------------------------------------ -// TextLineFrag -//------------------------------------------------------------------------ - -class TextLineFrag { -public: - - TextLine *line; // the line object - int start, len; // offset and length of this fragment - // (in Unicode chars) - double xMin, xMax; // bounding box coordinates - double yMin, yMax; - double base; // baseline virtual coordinate - int col; // first column - - void init(TextLine *lineA, int startA, int lenA); - void computeCoords(GBool oneRot); - - static int cmpYXPrimaryRot(const void *p1, const void *p2); - static int cmpYXLineRot(const void *p1, const void *p2); - static int cmpXYLineRot(const void *p1, const void *p2); -}; - -void TextLineFrag::init(TextLine *lineA, int startA, int lenA) { - line = lineA; - start = startA; - len = lenA; - col = line->col[start]; -} - -void TextLineFrag::computeCoords(GBool oneRot) { - TextBlock *blk; - double d0, d1, d2, d3, d4; - - if (oneRot) { - - switch (line->rot) { - case 0: - xMin = line->edge[start]; - xMax = line->edge[start + len]; - yMin = line->yMin; - yMax = line->yMax; - break; - case 1: - xMin = line->xMin; - xMax = line->xMax; - yMin = line->edge[start]; - yMax = line->edge[start + len]; - break; - case 2: - xMin = line->edge[start + len]; - xMax = line->edge[start]; - yMin = line->yMin; - yMax = line->yMax; - break; - case 3: - xMin = line->xMin; - xMax = line->xMax; - yMin = line->edge[start + len]; - yMax = line->edge[start]; - break; - } - base = line->base; - - } else { - - if (line->rot == 0 && line->blk->page->primaryRot == 0) { - - xMin = line->edge[start]; - xMax = line->edge[start + len]; - yMin = line->yMin; - yMax = line->yMax; - base = line->base; - - } else { - - blk = line->blk; - d0 = line->edge[start]; - d1 = line->edge[start + len]; - d2 = d3 = d4 = 0; // make gcc happy - - switch (line->rot) { - case 0: - d2 = line->yMin; - d3 = line->yMax; - d4 = line->base; - d0 = (d0 - blk->xMin) / (blk->xMax - blk->xMin); - d1 = (d1 - blk->xMin) / (blk->xMax - blk->xMin); - d2 = (d2 - blk->yMin) / (blk->yMax - blk->yMin); - d3 = (d3 - blk->yMin) / (blk->yMax - blk->yMin); - d4 = (d4 - blk->yMin) / (blk->yMax - blk->yMin); - break; - case 1: - d2 = line->xMax; - d3 = line->xMin; - d4 = line->base; - d0 = (d0 - blk->yMin) / (blk->yMax - blk->yMin); - d1 = (d1 - blk->yMin) / (blk->yMax - blk->yMin); - d2 = (blk->xMax - d2) / (blk->xMax - blk->xMin); - d3 = (blk->xMax - d3) / (blk->xMax - blk->xMin); - d4 = (blk->xMax - d4) / (blk->xMax - blk->xMin); - break; - case 2: - d2 = line->yMax; - d3 = line->yMin; - d4 = line->base; - d0 = (blk->xMax - d0) / (blk->xMax - blk->xMin); - d1 = (blk->xMax - d1) / (blk->xMax - blk->xMin); - d2 = (blk->yMax - d2) / (blk->yMax - blk->yMin); - d3 = (blk->yMax - d3) / (blk->yMax - blk->yMin); - d4 = (blk->yMax - d4) / (blk->yMax - blk->yMin); - break; - case 3: - d2 = line->xMin; - d3 = line->xMax; - d4 = line->base; - d0 = (blk->yMax - d0) / (blk->yMax - blk->yMin); - d1 = (blk->yMax - d1) / (blk->yMax - blk->yMin); - d2 = (d2 - blk->xMin) / (blk->xMax - blk->xMin); - d3 = (d3 - blk->xMin) / (blk->xMax - blk->xMin); - d4 = (d4 - blk->xMin) / (blk->xMax - blk->xMin); - break; - } - - switch (line->blk->page->primaryRot) { - case 0: - xMin = blk->xMin + d0 * (blk->xMax - blk->xMin); - xMax = blk->xMin + d1 * (blk->xMax - blk->xMin); - yMin = blk->yMin + d2 * (blk->yMax - blk->yMin); - yMax = blk->yMin + d3 * (blk->yMax - blk->yMin); - base = blk->yMin + base * (blk->yMax - blk->yMin); - break; - case 1: - xMin = blk->xMax - d3 * (blk->xMax - blk->xMin); - xMax = blk->xMax - d2 * (blk->xMax - blk->xMin); - yMin = blk->yMin + d0 * (blk->yMax - blk->yMin); - yMax = blk->yMin + d1 * (blk->yMax - blk->yMin); - base = blk->xMax - d4 * (blk->xMax - blk->xMin); - break; - case 2: - xMin = blk->xMax - d1 * (blk->xMax - blk->xMin); - xMax = blk->xMax - d0 * (blk->xMax - blk->xMin); - yMin = blk->yMax - d3 * (blk->yMax - blk->yMin); - yMax = blk->yMax - d2 * (blk->yMax - blk->yMin); - base = blk->yMax - d4 * (blk->yMax - blk->yMin); - break; - case 3: - xMin = blk->xMin + d2 * (blk->xMax - blk->xMin); - xMax = blk->xMin + d3 * (blk->xMax - blk->xMin); - yMin = blk->yMax - d1 * (blk->yMax - blk->yMin); - yMax = blk->yMax - d0 * (blk->yMax - blk->yMin); - base = blk->xMin + d4 * (blk->xMax - blk->xMin); - break; - } - - } - } -} - -int TextLineFrag::cmpYXPrimaryRot(const void *p1, const void *p2) { - TextLineFrag *frag1 = (TextLineFrag *)p1; - TextLineFrag *frag2 = (TextLineFrag *)p2; - double cmp; - - cmp = 0; // make gcc happy - switch (frag1->line->blk->page->primaryRot) { - case 0: - if (fabs(cmp = frag1->yMin - frag2->yMin) < 0.01) { - cmp = frag1->xMin - frag2->xMin; - } - break; - case 1: - if (fabs(cmp = frag2->xMax - frag1->xMax) < 0.01) { - cmp = frag1->yMin - frag2->yMin; - } - break; - case 2: - if (fabs(cmp = frag2->yMin - frag1->yMin) < 0.01) { - cmp = frag2->xMax - frag1->xMax; - } - break; - case 3: - if (fabs(cmp = frag1->xMax - frag2->xMax) < 0.01) { - cmp = frag2->yMax - frag1->yMax; - } - break; - } - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -int TextLineFrag::cmpYXLineRot(const void *p1, const void *p2) { - TextLineFrag *frag1 = (TextLineFrag *)p1; - TextLineFrag *frag2 = (TextLineFrag *)p2; - double cmp; - - cmp = 0; // make gcc happy - switch (frag1->line->rot) { - case 0: - if ((cmp = frag1->yMin - frag2->yMin) == 0) { - cmp = frag1->xMin - frag2->xMin; - } - break; - case 1: - if ((cmp = frag2->xMax - frag1->xMax) == 0) { - cmp = frag1->yMin - frag2->yMin; - } - break; - case 2: - if ((cmp = frag2->yMin - frag1->yMin) == 0) { - cmp = frag2->xMax - frag1->xMax; - } - break; - case 3: - if ((cmp = frag1->xMax - frag2->xMax) == 0) { - cmp = frag2->yMax - frag1->yMax; - } - break; - } - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -int TextLineFrag::cmpXYLineRot(const void *p1, const void *p2) { - TextLineFrag *frag1 = (TextLineFrag *)p1; - TextLineFrag *frag2 = (TextLineFrag *)p2; - double cmp; - - cmp = 0; // make gcc happy - switch (frag1->line->rot) { - case 0: - if ((cmp = frag1->xMin - frag2->xMin) == 0) { - cmp = frag1->yMin - frag2->yMin; - } - break; - case 1: - if ((cmp = frag1->yMin - frag2->yMin) == 0) { - cmp = frag2->xMax - frag1->xMax; - } - break; - case 2: - if ((cmp = frag2->xMax - frag1->xMax) == 0) { - cmp = frag2->yMin - frag1->yMin; - } - break; - case 3: - if ((cmp = frag2->yMax - frag1->yMax) == 0) { - cmp = frag1->xMax - frag2->xMax; - } - break; - } - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -//------------------------------------------------------------------------ -// TextBlock -//------------------------------------------------------------------------ - -TextBlock::TextBlock(TextPage *pageA, int rotA) { - page = pageA; - rot = rotA; - xMin = yMin = 0; - xMax = yMax = -1; - priMin = 0; - priMax = page->pageWidth; - pool = new TextPool(); - lines = NULL; - curLine = NULL; - next = NULL; - stackNext = NULL; -} - -TextBlock::~TextBlock() { - TextLine *line; - - delete pool; - while (lines) { - line = lines; - lines = lines->next; - delete line; - } -} - -void TextBlock::addWord(TextWord *word) { - pool->addWord(word); - if (xMin > xMax) { - xMin = word->xMin; - xMax = word->xMax; - yMin = word->yMin; - yMax = word->yMax; - } else { - if (word->xMin < xMin) { - xMin = word->xMin; - } - if (word->xMax > xMax) { - xMax = word->xMax; - } - if (word->yMin < yMin) { - yMin = word->yMin; - } - if (word->yMax > yMax) { - yMax = word->yMax; - } - } -} - -void TextBlock::coalesce(UnicodeMap *uMap) { - TextWord *word0, *word1, *word2, *bestWord0, *bestWord1, *lastWord; - TextLine *line, *line0, *line1; - int poolMinBaseIdx, startBaseIdx, minBaseIdx, maxBaseIdx; - int baseIdx, bestWordBaseIdx, idx0, idx1; - double minBase, maxBase; - double fontSize, delta, priDelta, secDelta; - TextLine **lineArray; - GBool found; - int col1, col2; - int i, j, k; - - // discard duplicated text (fake boldface, drop shadows) - for (idx0 = pool->minBaseIdx; idx0 <= pool->maxBaseIdx; ++idx0) { - word0 = pool->getPool(idx0); - while (word0) { - priDelta = dupMaxPriDelta * word0->fontSize; - secDelta = dupMaxSecDelta * word0->fontSize; - if (rot == 0 || rot == 3) { - maxBaseIdx = pool->getBaseIdx(word0->base + secDelta); - } else { - maxBaseIdx = pool->getBaseIdx(word0->base - secDelta); - } - found = gFalse; - word1 = word2 = NULL; // make gcc happy - for (idx1 = idx0; idx1 <= maxBaseIdx; ++idx1) { - if (idx1 == idx0) { - word1 = word0; - word2 = word0->next; - } else { - word1 = NULL; - word2 = pool->getPool(idx1); - } - for (; word2; word1 = word2, word2 = word2->next) { - if (word2->len == word0->len && - !memcmp(word2->text, word0->text, - word0->len * sizeof(Unicode))) { - switch (rot) { - case 0: - case 2: - found = fabs(word0->xMin - word2->xMin) < priDelta && - fabs(word0->xMax - word2->xMax) < priDelta && - fabs(word0->yMin - word2->yMin) < secDelta && - fabs(word0->yMax - word2->yMax) < secDelta; - break; - case 1: - case 3: - found = fabs(word0->xMin - word2->xMin) < secDelta && - fabs(word0->xMax - word2->xMax) < secDelta && - fabs(word0->yMin - word2->yMin) < priDelta && - fabs(word0->yMax - word2->yMax) < priDelta; - break; - } - } - if (found) { - break; - } - } - if (found) { - break; - } - } - if (found) { - if (word1) { - word1->next = word2->next; - } else { - pool->setPool(idx1, word2->next); - } - delete word2; - } else { - word0 = word0->next; - } - } - } - - // build the lines - curLine = NULL; - poolMinBaseIdx = pool->minBaseIdx; - charCount = 0; - nLines = 0; - while (1) { - - // find the first non-empty line in the pool - for (; - poolMinBaseIdx <= pool->maxBaseIdx && !pool->getPool(poolMinBaseIdx); - ++poolMinBaseIdx) ; - if (poolMinBaseIdx > pool->maxBaseIdx) { - break; - } - - // look for the left-most word in the first four lines of the - // pool -- this avoids starting with a superscript word - startBaseIdx = poolMinBaseIdx; - for (baseIdx = poolMinBaseIdx + 1; - baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx; - ++baseIdx) { - if (!pool->getPool(baseIdx)) { - continue; - } - if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx)) - < 0) { - startBaseIdx = baseIdx; - } - } - - // create a new line - word0 = pool->getPool(startBaseIdx); - pool->setPool(startBaseIdx, word0->next); - word0->next = NULL; - line = new TextLine(this, word0->rot, word0->base); - line->addWord(word0); - lastWord = word0; - - // compute the search range - fontSize = word0->fontSize; - minBase = word0->base - maxIntraLineDelta * fontSize; - maxBase = word0->base + maxIntraLineDelta * fontSize; - minBaseIdx = pool->getBaseIdx(minBase); - maxBaseIdx = pool->getBaseIdx(maxBase); - - // find the rest of the words in this line - while (1) { - - // find the left-most word whose baseline is in the range for - // this line - bestWordBaseIdx = 0; - bestWord0 = bestWord1 = NULL; - for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) { - for (word0 = NULL, word1 = pool->getPool(baseIdx); - word1; - word0 = word1, word1 = word1->next) { - if (word1->base >= minBase && - word1->base <= maxBase && - (delta = lastWord->primaryDelta(word1)) >= - minCharSpacing * fontSize) { - if (delta < maxWordSpacing * fontSize && - (!bestWord1 || word1->primaryCmp(bestWord1) < 0)) { - bestWordBaseIdx = baseIdx; - bestWord0 = word0; - bestWord1 = word1; - } - break; - } - } - } - if (!bestWord1) { - break; - } - - // remove it from the pool, and add it to the line - if (bestWord0) { - bestWord0->next = bestWord1->next; - } else { - pool->setPool(bestWordBaseIdx, bestWord1->next); - } - bestWord1->next = NULL; - line->addWord(bestWord1); - lastWord = bestWord1; - } - - // add the line - if (curLine && line->cmpYX(curLine) > 0) { - line0 = curLine; - line1 = curLine->next; - } else { - line0 = NULL; - line1 = lines; - } - for (; - line1 && line->cmpYX(line1) > 0; - line0 = line1, line1 = line1->next) ; - if (line0) { - line0->next = line; - } else { - lines = line; - } - line->next = line1; - curLine = line; - line->coalesce(uMap); - charCount += line->len; - ++nLines; - } - - // sort lines into xy order for column assignment - lineArray = (TextLine **)gmallocn(nLines, sizeof(TextLine *)); - for (line = lines, i = 0; line; line = line->next, ++i) { - lineArray[i] = line; - } - qsort(lineArray, nLines, sizeof(TextLine *), &TextLine::cmpXY); - - // column assignment - nColumns = 0; - for (i = 0; i < nLines; ++i) { - line0 = lineArray[i]; - col1 = 0; - for (j = 0; j < i; ++j) { - line1 = lineArray[j]; - if (line1->primaryDelta(line0) >= 0) { - col2 = line1->col[line1->len] + 1; - } else { - k = 0; // make gcc happy - switch (rot) { - case 0: - for (k = 0; - k < line1->len && - line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]); - ++k) ; - break; - case 1: - for (k = 0; - k < line1->len && - line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]); - ++k) ; - break; - case 2: - for (k = 0; - k < line1->len && - line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]); - ++k) ; - break; - case 3: - for (k = 0; - k < line1->len && - line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]); - ++k) ; - break; - } - col2 = line1->col[k]; - } - if (col2 > col1) { - col1 = col2; - } - } - for (k = 0; k <= line0->len; ++k) { - line0->col[k] += col1; - } - if (line0->col[line0->len] > nColumns) { - nColumns = line0->col[line0->len]; - } - } - gfree(lineArray); -} - -void TextBlock::updatePriMinMax(TextBlock *blk) { - double newPriMin, newPriMax; - GBool gotPriMin, gotPriMax; - - gotPriMin = gotPriMax = gFalse; - newPriMin = newPriMax = 0; // make gcc happy - switch (page->primaryRot) { - case 0: - case 2: - if (blk->yMin < yMax && blk->yMax > yMin) { - if (blk->xMin < xMin) { - newPriMin = blk->xMax; - gotPriMin = gTrue; - } - if (blk->xMax > xMax) { - newPriMax = blk->xMin; - gotPriMax = gTrue; - } - } - break; - case 1: - case 3: - if (blk->xMin < xMax && blk->xMax > xMin) { - if (blk->yMin < yMin) { - newPriMin = blk->yMax; - gotPriMin = gTrue; - } - if (blk->yMax > yMax) { - newPriMax = blk->yMin; - gotPriMax = gTrue; - } - } - break; - } - if (gotPriMin) { - if (newPriMin > xMin) { - newPriMin = xMin; - } - if (newPriMin > priMin) { - priMin = newPriMin; - } - } - if (gotPriMax) { - if (newPriMax < xMax) { - newPriMax = xMax; - } - if (newPriMax < priMax) { - priMax = newPriMax; - } - } -} - -int TextBlock::cmpXYPrimaryRot(const void *p1, const void *p2) { - TextBlock *blk1 = *(TextBlock **)p1; - TextBlock *blk2 = *(TextBlock **)p2; - double cmp; - - cmp = 0; // make gcc happy - switch (blk1->page->primaryRot) { - case 0: - if ((cmp = blk1->xMin - blk2->xMin) == 0) { - cmp = blk1->yMin - blk2->yMin; - } - break; - case 1: - if ((cmp = blk1->yMin - blk2->yMin) == 0) { - cmp = blk2->xMax - blk1->xMax; - } - break; - case 2: - if ((cmp = blk2->xMax - blk1->xMax) == 0) { - cmp = blk2->yMin - blk1->yMin; - } - break; - case 3: - if ((cmp = blk2->yMax - blk1->yMax) == 0) { - cmp = blk1->xMax - blk2->xMax; - } - break; - } - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -int TextBlock::cmpYXPrimaryRot(const void *p1, const void *p2) { - TextBlock *blk1 = *(TextBlock **)p1; - TextBlock *blk2 = *(TextBlock **)p2; - double cmp; - - cmp = 0; // make gcc happy - switch (blk1->page->primaryRot) { - case 0: - if ((cmp = blk1->yMin - blk2->yMin) == 0) { - cmp = blk1->xMin - blk2->xMin; - } - break; - case 1: - if ((cmp = blk2->xMax - blk1->xMax) == 0) { - cmp = blk1->yMin - blk2->yMin; - } - break; - case 2: - if ((cmp = blk2->yMin - blk1->yMin) == 0) { - cmp = blk2->xMax - blk1->xMax; - } - break; - case 3: - if ((cmp = blk1->xMax - blk2->xMax) == 0) { - cmp = blk2->yMax - blk1->yMax; - } - break; - } - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -int TextBlock::primaryCmp(TextBlock *blk) { - double cmp; - - cmp = 0; // make gcc happy - switch (rot) { - case 0: - cmp = xMin - blk->xMin; - break; - case 1: - cmp = yMin - blk->yMin; - break; - case 2: - cmp = blk->xMax - xMax; - break; - case 3: - cmp = blk->yMax - yMax; - break; - } - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -double TextBlock::secondaryDelta(TextBlock *blk) { - double delta; - - delta = 0; // make gcc happy - switch (rot) { - case 0: - delta = blk->yMin - yMax; - break; - case 1: - delta = xMin - blk->xMax; - break; - case 2: - delta = yMin - blk->yMax; - break; - case 3: - delta = blk->xMin - xMax; - break; - } - return delta; -} - -GBool TextBlock::isBelow(TextBlock *blk) { - GBool below; - - below = gFalse; // make gcc happy - switch (page->primaryRot) { - case 0: - below = xMin >= blk->priMin && xMax <= blk->priMax && - yMin > blk->yMin; - break; - case 1: - below = yMin >= blk->priMin && yMax <= blk->priMax && - xMax < blk->xMax; - break; - case 2: - below = xMin >= blk->priMin && xMax <= blk->priMax && - yMax < blk->yMax; - break; - case 3: - below = yMin >= blk->priMin && yMax <= blk->priMax && - xMin > blk->xMin; - break; - } - - return below; -} - -//------------------------------------------------------------------------ -// TextFlow -//------------------------------------------------------------------------ - -TextFlow::TextFlow(TextPage *pageA, TextBlock *blk) { - page = pageA; - xMin = blk->xMin; - xMax = blk->xMax; - yMin = blk->yMin; - yMax = blk->yMax; - priMin = blk->priMin; - priMax = blk->priMax; - blocks = lastBlk = blk; - next = NULL; -} - -TextFlow::~TextFlow() { - TextBlock *blk; - - while (blocks) { - blk = blocks; - blocks = blocks->next; - delete blk; - } -} - -void TextFlow::addBlock(TextBlock *blk) { - if (lastBlk) { - lastBlk->next = blk; - } else { - blocks = blk; - } - lastBlk = blk; - if (blk->xMin < xMin) { - xMin = blk->xMin; - } - if (blk->xMax > xMax) { - xMax = blk->xMax; - } - if (blk->yMin < yMin) { - yMin = blk->yMin; - } - if (blk->yMax > yMax) { - yMax = blk->yMax; - } -} - -GBool TextFlow::blockFits(TextBlock *blk, TextBlock */*prevBlk*/) { - GBool fits; - - // lower blocks must use smaller fonts - if (blk->lines->words->fontSize > lastBlk->lines->words->fontSize) { - return gFalse; - } - - fits = gFalse; // make gcc happy - switch (page->primaryRot) { - case 0: - fits = blk->xMin >= priMin && blk->xMax <= priMax; - break; - case 1: - fits = blk->yMin >= priMin && blk->yMax <= priMax; - break; - case 2: - fits = blk->xMin >= priMin && blk->xMax <= priMax; - break; - case 3: - fits = blk->yMin >= priMin && blk->yMax <= priMax; - break; - } - return fits; -} - -#if TEXTOUT_WORD_LIST - -//------------------------------------------------------------------------ -// TextWordList -//------------------------------------------------------------------------ - -TextWordList::TextWordList(TextPage *text, GBool physLayout) { - TextFlow *flow; - TextBlock *blk; - TextLine *line; - TextWord *word; - TextWord **wordArray; - int nWords, i; - - words = new GList(); - - if (text->rawOrder) { - for (word = text->rawWords; word; word = word->next) { - words->append(word); - } - - } else if (physLayout) { - // this is inefficient, but it's also the least useful of these - // three cases - nWords = 0; - for (flow = text->flows; flow; flow = flow->next) { - for (blk = flow->blocks; blk; blk = blk->next) { - for (line = blk->lines; line; line = line->next) { - for (word = line->words; word; word = word->next) { - ++nWords; - } - } - } - } - wordArray = (TextWord **)gmallocn(nWords, sizeof(TextWord *)); - i = 0; - for (flow = text->flows; flow; flow = flow->next) { - for (blk = flow->blocks; blk; blk = blk->next) { - for (line = blk->lines; line; line = line->next) { - for (word = line->words; word; word = word->next) { - wordArray[i++] = word; - } - } - } - } - qsort(wordArray, nWords, sizeof(TextWord *), &TextWord::cmpYX); - for (i = 0; i < nWords; ++i) { - words->append(wordArray[i]); - } - gfree(wordArray); - - } else { - for (flow = text->flows; flow; flow = flow->next) { - for (blk = flow->blocks; blk; blk = blk->next) { - for (line = blk->lines; line; line = line->next) { - for (word = line->words; word; word = word->next) { - words->append(word); - } - } - } - } - } -} - -TextWordList::~TextWordList() { - delete words; -} - -int TextWordList::getLength() { - return words->getLength(); -} - -TextWord *TextWordList::get(int idx) { - if (idx < 0 || idx >= words->getLength()) { - return NULL; - } - return (TextWord *)words->get(idx); -} - -#endif // TEXTOUT_WORD_LIST - -//------------------------------------------------------------------------ -// TextPage -//------------------------------------------------------------------------ - -TextPage::TextPage(GBool rawOrderA) { - int rot; - - rawOrder = rawOrderA; - curWord = NULL; - charPos = 0; - curFont = NULL; - curFontSize = 0; - nest = 0; - nTinyChars = 0; - lastCharOverlap = gFalse; - if (!rawOrder) { - for (rot = 0; rot < 4; ++rot) { - pools[rot] = new TextPool(); - } - } - flows = NULL; - blocks = NULL; - rawWords = NULL; - rawLastWord = NULL; - fonts = new GList(); - lastFindXMin = lastFindYMin = 0; - haveLastFind = gFalse; -} - -TextPage::~TextPage() { - int rot; - - clear(); - if (!rawOrder) { - for (rot = 0; rot < 4; ++rot) { - delete pools[rot]; - } - } - delete fonts; -} - -void TextPage::startPage(GfxState *state) { - clear(); - if (state) { - pageWidth = state->getPageWidth(); - pageHeight = state->getPageHeight(); - } else { - pageWidth = pageHeight = 0; - } -} - -void TextPage::endPage() { - if (curWord) { - endWord(); - } -} - -void TextPage::clear() { - int rot; - TextFlow *flow; - TextWord *word; - - if (curWord) { - delete curWord; - curWord = NULL; - } - if (rawOrder) { - while (rawWords) { - word = rawWords; - rawWords = rawWords->next; - delete word; - } - } else { - for (rot = 0; rot < 4; ++rot) { - delete pools[rot]; - } - while (flows) { - flow = flows; - flows = flows->next; - delete flow; - } - gfree(blocks); - } - deleteGList(fonts, TextFontInfo); - - curWord = NULL; - charPos = 0; - curFont = NULL; - curFontSize = 0; - nest = 0; - nTinyChars = 0; - if (!rawOrder) { - for (rot = 0; rot < 4; ++rot) { - pools[rot] = new TextPool(); - } - } - flows = NULL; - blocks = NULL; - rawWords = NULL; - rawLastWord = NULL; - fonts = new GList(); -} - -void TextPage::updateFont(GfxState *state) { - GfxFont *gfxFont; - double *fm; - const char *name; - int code, mCode, letterCode, anyCode; - double w; - int i; - - // get the font info object - curFont = NULL; - for (i = 0; i < fonts->getLength(); ++i) { - curFont = (TextFontInfo *)fonts->get(i); - if (curFont->matches(state)) { - break; - } - curFont = NULL; - } - if (!curFont) { - curFont = new TextFontInfo(state); - fonts->append(curFont); - } - - // adjust the font size - gfxFont = state->getFont(); - curFontSize = state->getTransformedFontSize(); - if (gfxFont && gfxFont->getType() == fontType3) { - // This is a hack which makes it possible to deal with some Type 3 - // fonts. The problem is that it's impossible to know what the - // base coordinate system used in the font is without actually - // rendering the font. This code tries to guess by looking at the - // width of the character 'm' (which breaks if the font is a - // subset that doesn't contain 'm'). - mCode = letterCode = anyCode = -1; - for (code = 0; code < 256; ++code) { - name = ((Gfx8BitFont *)gfxFont)->getCharName(code); - if (name && name[0] == 'm' && name[1] == '\0') { - mCode = code; - } - if (letterCode < 0 && name && name[1] == '\0' && - ((name[0] >= 'A' && name[0] <= 'Z') || - (name[0] >= 'a' && name[0] <= 'z'))) { - letterCode = code; - } - if (anyCode < 0 && name && - ((Gfx8BitFont *)gfxFont)->getWidth(code) > 0) { - anyCode = code; - } - } - if (mCode >= 0 && - (w = ((Gfx8BitFont *)gfxFont)->getWidth(mCode)) > 0) { - // 0.6 is a generic average 'm' width -- yes, this is a hack - curFontSize *= w / 0.6; - } else if (letterCode >= 0 && - (w = ((Gfx8BitFont *)gfxFont)->getWidth(letterCode)) > 0) { - // even more of a hack: 0.5 is a generic letter width - curFontSize *= w / 0.5; - } else if (anyCode >= 0 && - (w = ((Gfx8BitFont *)gfxFont)->getWidth(anyCode)) > 0) { - // better than nothing: 0.5 is a generic character width - curFontSize *= w / 0.5; - } - fm = gfxFont->getFontMatrix(); - if (fm[0] != 0) { - curFontSize *= fabs(fm[3] / fm[0]); - } - } -} - -void TextPage::beginWord(GfxState *state, double x0, double y0) { - double *fontm; - double m[4], m2[4]; - int rot; - - // This check is needed because Type 3 characters can contain - // text-drawing operations (when TextPage is being used via - // {X,Win}SplashOutputDev rather than TextOutputDev). - if (curWord) { - ++nest; - return; - } - - // compute the rotation - state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]); - if (state->getFont()->getType() == fontType3) { - fontm = state->getFont()->getFontMatrix(); - m2[0] = fontm[0] * m[0] + fontm[1] * m[2]; - m2[1] = fontm[0] * m[1] + fontm[1] * m[3]; - m2[2] = fontm[2] * m[0] + fontm[3] * m[2]; - m2[3] = fontm[2] * m[1] + fontm[3] * m[3]; - m[0] = m2[0]; - m[1] = m2[1]; - m[2] = m2[2]; - m[3] = m2[3]; - } - if (fabs(m[0] * m[3]) > fabs(m[1] * m[2])) { - rot = (m[3] < 0) ? 0 : 2; - } else { - rot = (m[2] > 0) ? 1 : 3; - } - - curWord = new TextWord(state, rot, x0, y0, charPos, curFont, curFontSize); -} - -void TextPage::addChar(GfxState *state, double x, double y, - double dx, double dy, - CharCode c, int nBytes, Unicode *u, int uLen) { - double x1, y1, w1, h1, dx2, dy2, base, sp, delta; - GBool overlap; - int i; - - // throw away chars that aren't inside the page bounds - state->transform(x, y, &x1, &y1); - if (x1 < 0 || x1 > pageWidth || - y1 < 0 || y1 > pageHeight) { - charPos += nBytes; - return; - } - - // subtract char and word spacing from the dx,dy values - sp = state->getCharSpace(); - if (c == (CharCode)0x20) { - sp += state->getWordSpace(); - } - state->textTransformDelta(sp * state->getHorizScaling(), 0, &dx2, &dy2); - dx -= dx2; - dy -= dy2; - state->transformDelta(dx, dy, &w1, &h1); - - // check the tiny chars limit - if (!globalParams->getTextKeepTinyChars() && - fabs(w1) < 3 && fabs(h1) < 3) { - if (++nTinyChars > 50000) { - charPos += nBytes; - return; - } - } - - // break words at space character - if (uLen == 1 && u[0] == (Unicode)0x20) { - if (curWord) { - ++curWord->charLen; - } - charPos += nBytes; - endWord(); - return; - } - - // start a new word if: - // (1) this character doesn't fall in the right place relative to - // the end of the previous word (this places upper and lower - // constraints on the position deltas along both the primary - // and secondary axes), or - // (2) this character overlaps the previous one (duplicated text), or - // (3) the previous character was an overlap (we want each duplicated - // character to be in a word by itself at this stage) - if (curWord && curWord->len > 0) { - base = sp = delta = 0; // make gcc happy - switch (curWord->rot) { - case 0: - base = y1; - sp = x1 - curWord->xMax; - delta = x1 - curWord->edge[curWord->len - 1]; - break; - case 1: - base = x1; - sp = y1 - curWord->yMax; - delta = y1 - curWord->edge[curWord->len - 1]; - break; - case 2: - base = y1; - sp = curWord->xMin - x1; - delta = curWord->edge[curWord->len - 1] - x1; - break; - case 3: - base = x1; - sp = curWord->yMin - y1; - delta = curWord->edge[curWord->len - 1] - y1; - break; - } - overlap = fabs(delta) < dupMaxPriDelta * curWord->fontSize && - fabs(base - curWord->base) < dupMaxSecDelta * curWord->fontSize; - if (overlap || lastCharOverlap || - sp < -minDupBreakOverlap * curWord->fontSize || - sp > minWordBreakSpace * curWord->fontSize || - fabs(base - curWord->base) > 0.5) { - endWord(); - } - lastCharOverlap = overlap; - } else { - lastCharOverlap = gFalse; - } - - if (uLen != 0) { - // start a new word if needed - if (!curWord) { - beginWord(state, x, y); - } - - // page rotation and/or transform matrices can cause text to be - // drawn in reverse order -- in this case, swap the begin/end - // coordinates and break text into individual chars - if ((curWord->rot == 0 && w1 < 0) || - (curWord->rot == 1 && h1 < 0) || - (curWord->rot == 2 && w1 > 0) || - (curWord->rot == 3 && h1 > 0)) { - endWord(); - beginWord(state, x + dx, y + dy); - x1 += w1; - y1 += h1; - w1 = -w1; - h1 = -h1; - } - - // add the characters to the current word - w1 /= uLen; - h1 /= uLen; - for (i = 0; i < uLen; ++i) { - curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]); - } - } - if (curWord) { - curWord->charLen += nBytes; - } - charPos += nBytes; -} - -void TextPage::endWord() { - // This check is needed because Type 3 characters can contain - // text-drawing operations (when TextPage is being used via - // {X,Win}SplashOutputDev rather than TextOutputDev). - if (nest > 0) { - --nest; - return; - } - - if (curWord) { - addWord(curWord); - curWord = NULL; - } -} - -void TextPage::addWord(TextWord *word) { - // throw away zero-length words -- they don't have valid xMin/xMax - // values, and they're useless anyway - if (word->len == 0) { - delete word; - return; - } - - if (rawOrder) { - if (rawLastWord) { - rawLastWord->next = word; - } else { - rawWords = word; - } - rawLastWord = word; - } else { - pools[word->rot]->addWord(word); - } -} - -void TextPage::coalesce(GBool /*physLayout*/) { - UnicodeMap *uMap; - TextPool *pool; - TextWord *word0, *word1, *word2; - TextLine *line; - TextBlock *blkList, *blkStack, *blk, *lastBlk, *blk0, *blk1; - TextBlock **blkArray; - TextFlow *flow, *lastFlow; - int rot, poolMinBaseIdx, baseIdx, startBaseIdx; - double minBase, maxBase, newMinBase, newMaxBase; - double fontSize, colSpace1, colSpace2, lineSpace, intraLineSpace, blkSpace; - GBool found; - int count[4]; - int lrCount; - int firstBlkIdx, nBlocksLeft; - int col1, col2; - int i, j, n; - - if (rawOrder) { - primaryRot = 0; - primaryLR = gTrue; - return; - } - - uMap = globalParams->getTextEncoding(); - blkList = NULL; - lastBlk = NULL; - nBlocks = 0; - primaryRot = -1; - -#if 0 // for debugging - printf("*** initial words ***\n"); - for (rot = 0; rot < 4; ++rot) { - pool = pools[rot]; - for (baseIdx = pool->minBaseIdx; baseIdx <= pool->maxBaseIdx; ++baseIdx) { - for (word0 = pool->getPool(baseIdx); word0; word0 = word0->next) { - printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f rot=%d '", - word0->xMin, word0->xMax, word0->yMin, word0->yMax, - word0->base, word0->fontSize, rot*90); - for (i = 0; i < word0->len; ++i) { - fputc(word0->text[i] & 0xff, stdout); - } - printf("'\n"); - } - } - } - printf("\n"); -#endif - - //----- assemble the blocks - - //~ add an outer loop for writing mode (vertical text) - - // build blocks for each rotation value - for (rot = 0; rot < 4; ++rot) { - pool = pools[rot]; - poolMinBaseIdx = pool->minBaseIdx; - count[rot] = 0; - - // add blocks until no more words are left - while (1) { - - // find the first non-empty line in the pool - for (; - poolMinBaseIdx <= pool->maxBaseIdx && - !pool->getPool(poolMinBaseIdx); - ++poolMinBaseIdx) ; - if (poolMinBaseIdx > pool->maxBaseIdx) { - break; - } - - // look for the left-most word in the first four lines of the - // pool -- this avoids starting with a superscript word - startBaseIdx = poolMinBaseIdx; - for (baseIdx = poolMinBaseIdx + 1; - baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx; - ++baseIdx) { - if (!pool->getPool(baseIdx)) { - continue; - } - if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx)) - < 0) { - startBaseIdx = baseIdx; - } - } - - // create a new block - word0 = pool->getPool(startBaseIdx); - pool->setPool(startBaseIdx, word0->next); - word0->next = NULL; - blk = new TextBlock(this, rot); - blk->addWord(word0); - - fontSize = word0->fontSize; - minBase = maxBase = word0->base; - colSpace1 = minColSpacing1 * fontSize; - colSpace2 = minColSpacing2 * fontSize; - lineSpace = maxLineSpacingDelta * fontSize; - intraLineSpace = maxIntraLineDelta * fontSize; - - // add words to the block - do { - found = gFalse; - - // look for words on the line above the current top edge of - // the block - newMinBase = minBase; - for (baseIdx = pool->getBaseIdx(minBase); - baseIdx >= pool->getBaseIdx(minBase - lineSpace); - --baseIdx) { - word0 = NULL; - word1 = pool->getPool(baseIdx); - while (word1) { - if (word1->base < minBase && - word1->base >= minBase - lineSpace && - ((rot == 0 || rot == 2) - ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin) - : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) && - fabs(word1->fontSize - fontSize) < - maxBlockFontSizeDelta1 * fontSize) { - word2 = word1; - if (word0) { - word0->next = word1->next; - } else { - pool->setPool(baseIdx, word1->next); - } - word1 = word1->next; - word2->next = NULL; - blk->addWord(word2); - found = gTrue; - newMinBase = word2->base; - } else { - word0 = word1; - word1 = word1->next; - } - } - } - minBase = newMinBase; - - // look for words on the line below the current bottom edge of - // the block - newMaxBase = maxBase; - for (baseIdx = pool->getBaseIdx(maxBase); - baseIdx <= pool->getBaseIdx(maxBase + lineSpace); - ++baseIdx) { - word0 = NULL; - word1 = pool->getPool(baseIdx); - while (word1) { - if (word1->base > maxBase && - word1->base <= maxBase + lineSpace && - ((rot == 0 || rot == 2) - ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin) - : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) && - fabs(word1->fontSize - fontSize) < - maxBlockFontSizeDelta1 * fontSize) { - word2 = word1; - if (word0) { - word0->next = word1->next; - } else { - pool->setPool(baseIdx, word1->next); - } - word1 = word1->next; - word2->next = NULL; - blk->addWord(word2); - found = gTrue; - newMaxBase = word2->base; - } else { - word0 = word1; - word1 = word1->next; - } - } - } - maxBase = newMaxBase; - - // look for words that are on lines already in the block, and - // that overlap the block horizontally - for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); - baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); - ++baseIdx) { - word0 = NULL; - word1 = pool->getPool(baseIdx); - while (word1) { - if (word1->base >= minBase - intraLineSpace && - word1->base <= maxBase + intraLineSpace && - ((rot == 0 || rot == 2) - ? (word1->xMin < blk->xMax + colSpace1 && - word1->xMax > blk->xMin - colSpace1) - : (word1->yMin < blk->yMax + colSpace1 && - word1->yMax > blk->yMin - colSpace1)) && - fabs(word1->fontSize - fontSize) < - maxBlockFontSizeDelta2 * fontSize) { - word2 = word1; - if (word0) { - word0->next = word1->next; - } else { - pool->setPool(baseIdx, word1->next); - } - word1 = word1->next; - word2->next = NULL; - blk->addWord(word2); - found = gTrue; - } else { - word0 = word1; - word1 = word1->next; - } - } - } - - // only check for outlying words (the next two chunks of code) - // if we didn't find anything else - if (found) { - continue; - } - - // scan down the left side of the block, looking for words - // that are near (but not overlapping) the block; if there are - // three or fewer, add them to the block - n = 0; - for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); - baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); - ++baseIdx) { - word1 = pool->getPool(baseIdx); - while (word1) { - if (word1->base >= minBase - intraLineSpace && - word1->base <= maxBase + intraLineSpace && - ((rot == 0 || rot == 2) - ? (word1->xMax <= blk->xMin && - word1->xMax > blk->xMin - colSpace2) - : (word1->yMax <= blk->yMin && - word1->yMax > blk->yMin - colSpace2)) && - fabs(word1->fontSize - fontSize) < - maxBlockFontSizeDelta3 * fontSize) { - ++n; - break; - } - word1 = word1->next; - } - } - if (n > 0 && n <= 3) { - for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); - baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); - ++baseIdx) { - word0 = NULL; - word1 = pool->getPool(baseIdx); - while (word1) { - if (word1->base >= minBase - intraLineSpace && - word1->base <= maxBase + intraLineSpace && - ((rot == 0 || rot == 2) - ? (word1->xMax <= blk->xMin && - word1->xMax > blk->xMin - colSpace2) - : (word1->yMax <= blk->yMin && - word1->yMax > blk->yMin - colSpace2)) && - fabs(word1->fontSize - fontSize) < - maxBlockFontSizeDelta3 * fontSize) { - word2 = word1; - if (word0) { - word0->next = word1->next; - } else { - pool->setPool(baseIdx, word1->next); - } - word1 = word1->next; - word2->next = NULL; - blk->addWord(word2); - if (word2->base < minBase) { - minBase = word2->base; - } else if (word2->base > maxBase) { - maxBase = word2->base; - } - found = gTrue; - break; - } else { - word0 = word1; - word1 = word1->next; - } - } - } - } - - // scan down the right side of the block, looking for words - // that are near (but not overlapping) the block; if there are - // three or fewer, add them to the block - n = 0; - for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); - baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); - ++baseIdx) { - word1 = pool->getPool(baseIdx); - while (word1) { - if (word1->base >= minBase - intraLineSpace && - word1->base <= maxBase + intraLineSpace && - ((rot == 0 || rot == 2) - ? (word1->xMin >= blk->xMax && - word1->xMin < blk->xMax + colSpace2) - : (word1->yMin >= blk->yMax && - word1->yMin < blk->yMax + colSpace2)) && - fabs(word1->fontSize - fontSize) < - maxBlockFontSizeDelta3 * fontSize) { - ++n; - break; - } - word1 = word1->next; - } - } - if (n > 0 && n <= 3) { - for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); - baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); - ++baseIdx) { - word0 = NULL; - word1 = pool->getPool(baseIdx); - while (word1) { - if (word1->base >= minBase - intraLineSpace && - word1->base <= maxBase + intraLineSpace && - ((rot == 0 || rot == 2) - ? (word1->xMin >= blk->xMax && - word1->xMin < blk->xMax + colSpace2) - : (word1->yMin >= blk->yMax && - word1->yMin < blk->yMax + colSpace2)) && - fabs(word1->fontSize - fontSize) < - maxBlockFontSizeDelta3 * fontSize) { - word2 = word1; - if (word0) { - word0->next = word1->next; - } else { - pool->setPool(baseIdx, word1->next); - } - word1 = word1->next; - word2->next = NULL; - blk->addWord(word2); - if (word2->base < minBase) { - minBase = word2->base; - } else if (word2->base > maxBase) { - maxBase = word2->base; - } - found = gTrue; - break; - } else { - word0 = word1; - word1 = word1->next; - } - } - } - } - - } while (found); - - //~ need to compute the primary writing mode (horiz/vert) in - //~ addition to primary rotation - - // coalesce the block, and add it to the list - blk->coalesce(uMap); - if (lastBlk) { - lastBlk->next = blk; - } else { - blkList = blk; - } - lastBlk = blk; - count[rot] += blk->charCount; - if (primaryRot < 0 || count[rot] > count[primaryRot]) { - primaryRot = rot; - } - ++nBlocks; - } - } - -#if 0 // for debugging - printf("*** rotation ***\n"); - for (rot = 0; rot < 4; ++rot) { - printf(" %d: %6d\n", rot, count[rot]); - } - printf(" primary rot = %d\n", primaryRot); - printf("\n"); -#endif - -#if 0 // for debugging - printf("*** blocks ***\n"); - for (blk = blkList; blk; blk = blk->next) { - printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f\n", - blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax); - for (line = blk->lines; line; line = line->next) { - printf(" line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f\n", - line->xMin, line->xMax, line->yMin, line->yMax, line->base); - for (word0 = line->words; word0; word0 = word0->next) { - printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", - word0->xMin, word0->xMax, word0->yMin, word0->yMax, - word0->base, word0->fontSize, word0->spaceAfter); - for (i = 0; i < word0->len; ++i) { - fputc(word0->text[i] & 0xff, stdout); - } - printf("'\n"); - } - } - } - printf("\n"); -#endif - - // determine the primary direction - lrCount = 0; - for (blk = blkList; blk; blk = blk->next) { - for (line = blk->lines; line; line = line->next) { - for (word0 = line->words; word0; word0 = word0->next) { - for (i = 0; i < word0->len; ++i) { - if (unicodeTypeL(word0->text[i])) { - ++lrCount; - } else if (unicodeTypeR(word0->text[i])) { - --lrCount; - } - } - } - } - } - primaryLR = lrCount >= 0; - -#if 0 // for debugging - printf("*** direction ***\n"); - printf("lrCount = %d\n", lrCount); - printf("primaryLR = %d\n", primaryLR); -#endif - - //----- column assignment - - // sort blocks into xy order for column assignment - blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *)); - for (blk = blkList, i = 0; blk; blk = blk->next, ++i) { - blocks[i] = blk; - } - qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot); - - // column assignment - for (i = 0; i < nBlocks; ++i) { - blk0 = blocks[i]; - col1 = 0; - for (j = 0; j < i; ++j) { - blk1 = blocks[j]; - col2 = 0; // make gcc happy - switch (primaryRot) { - case 0: - if (blk0->xMin > blk1->xMax) { - col2 = blk1->col + blk1->nColumns + 3; - } else if (blk1->xMax == blk1->xMin) { - col2 = blk1->col; - } else { - col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) / - (blk1->xMax - blk1->xMin)) * - blk1->nColumns); - } - break; - case 1: - if (blk0->yMin > blk1->yMax) { - col2 = blk1->col + blk1->nColumns + 3; - } else if (blk1->yMax == blk1->yMin) { - col2 = blk1->col; - } else { - col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) / - (blk1->yMax - blk1->yMin)) * - blk1->nColumns); - } - break; - case 2: - if (blk0->xMax < blk1->xMin) { - col2 = blk1->col + blk1->nColumns + 3; - } else if (blk1->xMin == blk1->xMax) { - col2 = blk1->col; - } else { - col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) / - (blk1->xMin - blk1->xMax)) * - blk1->nColumns); - } - break; - case 3: - if (blk0->yMax < blk1->yMin) { - col2 = blk1->col + blk1->nColumns + 3; - } else if (blk1->yMin == blk1->yMax) { - col2 = blk1->col; - } else { - col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) / - (blk1->yMin - blk1->yMax)) * - blk1->nColumns); - } - break; - } - if (col2 > col1) { - col1 = col2; - } - } - blk0->col = col1; - for (line = blk0->lines; line; line = line->next) { - for (j = 0; j <= line->len; ++j) { - line->col[j] += col1; - } - } - } - -#if 0 // for debugging - printf("*** blocks, after column assignment ***\n"); - for (blk = blkList; blk; blk = blk->next) { - printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f col=%d nCols=%d\n", - blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->col, - blk->nColumns); - for (line = blk->lines; line; line = line->next) { - printf(" line:\n"); - for (word0 = line->words; word0; word0 = word0->next) { - printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", - word0->xMin, word0->xMax, word0->yMin, word0->yMax, - word0->base, word0->fontSize, word0->spaceAfter); - for (i = 0; i < word0->len; ++i) { - fputc(word0->text[i] & 0xff, stdout); - } - printf("'\n"); - } - } - } - printf("\n"); -#endif - - //----- reading order sort - - // sort blocks into yx order (in preparation for reading order sort) - qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpYXPrimaryRot); - - // compute space on left and right sides of each block - for (i = 0; i < nBlocks; ++i) { - blk0 = blocks[i]; - for (j = 0; j < nBlocks; ++j) { - blk1 = blocks[j]; - if (blk1 != blk0) { - blk0->updatePriMinMax(blk1); - } - } - } - -#if 0 // for debugging - printf("*** blocks, after yx sort ***\n"); - for (i = 0; i < nBlocks; ++i) { - blk = blocks[i]; - printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f space=%.2f..%.2f\n", - blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, - blk->priMin, blk->priMax); - for (line = blk->lines; line; line = line->next) { - printf(" line:\n"); - for (word0 = line->words; word0; word0 = word0->next) { - printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", - word0->xMin, word0->xMax, word0->yMin, word0->yMax, - word0->base, word0->fontSize, word0->spaceAfter); - for (j = 0; j < word0->len; ++j) { - fputc(word0->text[j] & 0xff, stdout); - } - printf("'\n"); - } - } - } - printf("\n"); -#endif - - // build the flows - //~ this needs to be adjusted for writing mode (vertical text) - //~ this also needs to account for right-to-left column ordering - blkArray = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *)); - memcpy(blkArray, blocks, nBlocks * sizeof(TextBlock *)); - flows = lastFlow = NULL; - firstBlkIdx = 0; - nBlocksLeft = nBlocks; - while (nBlocksLeft > 0) { - - // find the upper-left-most block - for (; !blkArray[firstBlkIdx]; ++firstBlkIdx) ; - i = firstBlkIdx; - blk = blkArray[i]; - for (j = firstBlkIdx + 1; j < nBlocks; ++j) { - blk1 = blkArray[j]; - if (blk1) { - if (blk && blk->secondaryDelta(blk1) > 0) { - break; - } - if (blk1->primaryCmp(blk) < 0) { - i = j; - blk = blk1; - } - } - } - blkArray[i] = NULL; - --nBlocksLeft; - blk->next = NULL; - - // create a new flow, starting with the upper-left-most block - flow = new TextFlow(this, blk); - if (lastFlow) { - lastFlow->next = flow; - } else { - flows = flow; - } - lastFlow = flow; - fontSize = blk->lines->words->fontSize; - - // push the upper-left-most block on the stack - blk->stackNext = NULL; - blkStack = blk; - - // find the other blocks in this flow - while (blkStack) { - - // find the upper-left-most block under (but within - // maxBlockSpacing of) the top block on the stack - blkSpace = maxBlockSpacing * blkStack->lines->words->fontSize; - blk = NULL; - i = -1; - for (j = firstBlkIdx; j < nBlocks; ++j) { - blk1 = blkArray[j]; - if (blk1) { - if (blkStack->secondaryDelta(blk1) > blkSpace) { - break; - } - if (blk && blk->secondaryDelta(blk1) > 0) { - break; - } - if (blk1->isBelow(blkStack) && - (!blk || blk1->primaryCmp(blk) < 0)) { - i = j; - blk = blk1; - } - } - } - - // if a suitable block was found, add it to the flow and push it - // onto the stack - if (blk && flow->blockFits(blk, blkStack)) { - blkArray[i] = NULL; - --nBlocksLeft; - blk->next = NULL; - flow->addBlock(blk); - fontSize = blk->lines->words->fontSize; - blk->stackNext = blkStack; - blkStack = blk; - - // otherwise (if there is no block under the top block or the - // block is not suitable), pop the stack - } else { - blkStack = blkStack->stackNext; - } - } - } - gfree(blkArray); - -#if 0 // for debugging - printf("*** flows ***\n"); - for (flow = flows; flow; flow = flow->next) { - printf("flow: x=%.2f..%.2f y=%.2f..%.2f pri:%.2f..%.2f\n", - flow->xMin, flow->xMax, flow->yMin, flow->yMax, - flow->priMin, flow->priMax); - for (blk = flow->blocks; blk; blk = blk->next) { - printf(" block: rot=%d x=%.2f..%.2f y=%.2f..%.2f pri=%.2f..%.2f\n", - blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, - blk->priMin, blk->priMax); - for (line = blk->lines; line; line = line->next) { - printf(" line:\n"); - for (word0 = line->words; word0; word0 = word0->next) { - printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", - word0->xMin, word0->xMax, word0->yMin, word0->yMax, - word0->base, word0->fontSize, word0->spaceAfter); - for (i = 0; i < word0->len; ++i) { - fputc(word0->text[i] & 0xff, stdout); - } - printf("'\n"); - } - } - } - } - printf("\n"); -#endif - - if (uMap) { - uMap->decRefCnt(); - } -} - -GBool TextPage::findText(Unicode *s, int len, - GBool startAtTop, GBool stopAtBottom, - GBool startAtLast, GBool stopAtLast, - GBool caseSensitive, GBool backward, - double *xMin, double *yMin, - double *xMax, double *yMax) { - TextBlock *blk; - TextLine *line; - Unicode *s2, *txt; - Unicode *p; - int txtSize, m, i, j, k; - double xStart, yStart, xStop, yStop; - double xMin0, yMin0, xMax0, yMax0; - double xMin1, yMin1, xMax1, yMax1; - GBool found; - - //~ needs to handle right-to-left text - - if (rawOrder) { - return gFalse; - } - - // convert the search string to uppercase - if (!caseSensitive) { - s2 = (Unicode *)gmallocn(len, sizeof(Unicode)); - for (i = 0; i < len; ++i) { - s2[i] = unicodeToUpper(s[i]); - } - } else { - s2 = s; - } - - txt = NULL; - txtSize = 0; - - xStart = yStart = xStop = yStop = 0; - if (startAtLast && haveLastFind) { - xStart = lastFindXMin; - yStart = lastFindYMin; - } else if (!startAtTop) { - xStart = *xMin; - yStart = *yMin; - } - if (stopAtLast && haveLastFind) { - xStop = lastFindXMin; - yStop = lastFindYMin; - } else if (!stopAtBottom) { - xStop = *xMax; - yStop = *yMax; - } - - found = gFalse; - xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy - xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy - - for (i = backward ? nBlocks - 1 : 0; - backward ? i >= 0 : i < nBlocks; - i += backward ? -1 : 1) { - blk = blocks[i]; - - // check: is the block above the top limit? - if (!startAtTop && (backward ? blk->yMin > yStart : blk->yMax < yStart)) { - continue; - } - - // check: is the block below the bottom limit? - if (!stopAtBottom && (backward ? blk->yMax < yStop : blk->yMin > yStop)) { - break; - } - - for (line = blk->lines; line; line = line->next) { - - // check: is the line above the top limit? - if (!startAtTop && - (backward ? line->yMin > yStart : line->yMin < yStart)) { - continue; - } - - // check: is the line below the bottom limit? - if (!stopAtBottom && - (backward ? line->yMin < yStop : line->yMin > yStop)) { - continue; - } - - // convert the line to uppercase - m = line->len; - if (!caseSensitive) { - if (m > txtSize) { - txt = (Unicode *)greallocn(txt, m, sizeof(Unicode)); - txtSize = m; - } - for (k = 0; k < m; ++k) { - txt[k] = unicodeToUpper(line->text[k]); - } - } else { - txt = line->text; - } - - // search each position in this line - j = backward ? m - len : 0; - p = txt + j; - while (backward ? j >= 0 : j <= m - len) { - - // compare the strings - for (k = 0; k < len; ++k) { - if (p[k] != s2[k]) { - break; - } - } - - // found it - if (k == len) { - switch (line->rot) { - case 0: - xMin1 = line->edge[j]; - xMax1 = line->edge[j + len]; - yMin1 = line->yMin; - yMax1 = line->yMax; - break; - case 1: - xMin1 = line->xMin; - xMax1 = line->xMax; - yMin1 = line->edge[j]; - yMax1 = line->edge[j + len]; - break; - case 2: - xMin1 = line->edge[j + len]; - xMax1 = line->edge[j]; - yMin1 = line->yMin; - yMax1 = line->yMax; - break; - case 3: - xMin1 = line->xMin; - xMax1 = line->xMax; - yMin1 = line->edge[j + len]; - yMax1 = line->edge[j]; - break; - } - if (backward) { - if ((startAtTop || - yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) && - (stopAtBottom || - yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) { - if (!found || - yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) { - xMin0 = xMin1; - xMax0 = xMax1; - yMin0 = yMin1; - yMax0 = yMax1; - found = gTrue; - } - } - } else { - if ((startAtTop || - yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) && - (stopAtBottom || - yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) { - if (!found || - yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) { - xMin0 = xMin1; - xMax0 = xMax1; - yMin0 = yMin1; - yMax0 = yMax1; - found = gTrue; - } - } - } - } - if (backward) { - --j; - --p; - } else { - ++j; - ++p; - } - } - } - } - - if (!caseSensitive) { - gfree(s2); - gfree(txt); - } - - if (found) { - *xMin = xMin0; - *xMax = xMax0; - *yMin = yMin0; - *yMax = yMax0; - lastFindXMin = xMin0; - lastFindYMin = yMin0; - haveLastFind = gTrue; - return gTrue; - } - - return gFalse; -} - -GString *TextPage::getText(double xMin, double yMin, - double xMax, double yMax) { - GString *s; - UnicodeMap *uMap; - GBool isUnicode; - TextBlock *blk; - TextLine *line; - TextLineFrag *frags; - int nFrags, fragsSize; - TextLineFrag *frag; - char space[8], eol[16]; - int spaceLen, eolLen; - int lastRot; - double x, y; - int col, idx0, idx1, i, j; - GBool multiLine, oneRot; - - s = new GString(); - - if (rawOrder) { - return s; - } - - // get the output encoding - if (!(uMap = globalParams->getTextEncoding())) { - return s; - } - isUnicode = uMap->isUnicode(); - spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); - eolLen = 0; // make gcc happy - switch (globalParams->getTextEOL()) { - case eolUnix: - eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol)); - break; - case eolDOS: - eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); - eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen); - break; - case eolMac: - eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); - break; - } - - //~ writing mode (horiz/vert) - - // collect the line fragments that are in the rectangle - fragsSize = 256; - frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag)); - nFrags = 0; - lastRot = -1; - oneRot = gTrue; - for (i = 0; i < nBlocks; ++i) { - blk = blocks[i]; - if (xMin < blk->xMax && blk->xMin < xMax && - yMin < blk->yMax && blk->yMin < yMax) { - for (line = blk->lines; line; line = line->next) { - if (xMin < line->xMax && line->xMin < xMax && - yMin < line->yMax && line->yMin < yMax) { - idx0 = idx1 = -1; - switch (line->rot) { - case 0: - y = 0.5 * (line->yMin + line->yMax); - if (yMin < y && y < yMax) { - j = 0; - while (j < line->len) { - if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) { - idx0 = j; - break; - } - ++j; - } - j = line->len - 1; - while (j >= 0) { - if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) { - idx1 = j; - break; - } - --j; - } - } - break; - case 1: - x = 0.5 * (line->xMin + line->xMax); - if (xMin < x && x < xMax) { - j = 0; - while (j < line->len) { - if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) { - idx0 = j; - break; - } - ++j; - } - j = line->len - 1; - while (j >= 0) { - if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) { - idx1 = j; - break; - } - --j; - } - } - break; - case 2: - y = 0.5 * (line->yMin + line->yMax); - if (yMin < y && y < yMax) { - j = 0; - while (j < line->len) { - if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) { - idx0 = j; - break; - } - ++j; - } - j = line->len - 1; - while (j >= 0) { - if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) { - idx1 = j; - break; - } - --j; - } - } - break; - case 3: - x = 0.5 * (line->xMin + line->xMax); - if (xMin < x && x < xMax) { - j = 0; - while (j < line->len) { - if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) { - idx0 = j; - break; - } - ++j; - } - j = line->len - 1; - while (j >= 0) { - if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) { - idx1 = j; - break; - } - --j; - } - } - break; - } - if (idx0 >= 0 && idx1 >= 0) { - if (nFrags == fragsSize) { - fragsSize *= 2; - frags = (TextLineFrag *) - greallocn(frags, fragsSize, sizeof(TextLineFrag)); - } - frags[nFrags].init(line, idx0, idx1 - idx0 + 1); - ++nFrags; - if (lastRot >= 0 && line->rot != lastRot) { - oneRot = gFalse; - } - lastRot = line->rot; - } - } - } - } - } - - // sort the fragments and generate the string - if (nFrags > 0) { - - for (i = 0; i < nFrags; ++i) { - frags[i].computeCoords(oneRot); - } - assignColumns(frags, nFrags, oneRot); - - // if all lines in the region have the same rotation, use it; - // otherwise, use the page's primary rotation - if (oneRot) { - qsort(frags, nFrags, sizeof(TextLineFrag), - &TextLineFrag::cmpYXLineRot); - } else { - qsort(frags, nFrags, sizeof(TextLineFrag), - &TextLineFrag::cmpYXPrimaryRot); - } - - col = 0; - multiLine = gFalse; - for (i = 0; i < nFrags; ++i) { - frag = &frags[i]; - - // insert a return - if (frag->col < col || - (i > 0 && fabs(frag->base - frags[i-1].base) > - maxIntraLineDelta * frags[i-1].line->words->fontSize)) { - s->append(eol, eolLen); - col = 0; - multiLine = gTrue; - } - - // column alignment - for (; col < frag->col; ++col) { - s->append(space, spaceLen); - } - - // get the fragment text - col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s); - } - - if (multiLine) { - s->append(eol, eolLen); - } - } - - gfree(frags); - uMap->decRefCnt(); - - return s; -} - -GBool TextPage::findCharRange(int pos, int length, - double *xMin, double *yMin, - double *xMax, double *yMax) { - TextBlock *blk; - TextLine *line; - TextWord *word; - double xMin0, xMax0, yMin0, yMax0; - double xMin1, xMax1, yMin1, yMax1; - GBool first; - int i, j0, j1; - - if (rawOrder) { - return gFalse; - } - - //~ this doesn't correctly handle: - //~ - ranges split across multiple lines (the highlighted region - //~ is the bounding box of all the parts of the range) - //~ - cases where characters don't convert one-to-one into Unicode - first = gTrue; - xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy - xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy - for (i = 0; i < nBlocks; ++i) { - blk = blocks[i]; - for (line = blk->lines; line; line = line->next) { - for (word = line->words; word; word = word->next) { - if (pos < word->charPos + word->charLen && - word->charPos < pos + length) { - j0 = pos - word->charPos; - if (j0 < 0) { - j0 = 0; - } - j1 = pos + length - 1 - word->charPos; - if (j1 >= word->len) { - j1 = word->len - 1; - } - switch (line->rot) { - case 0: - xMin1 = word->edge[j0]; - xMax1 = word->edge[j1 + 1]; - yMin1 = word->yMin; - yMax1 = word->yMax; - break; - case 1: - xMin1 = word->xMin; - xMax1 = word->xMax; - yMin1 = word->edge[j0]; - yMax1 = word->edge[j1 + 1]; - break; - case 2: - xMin1 = word->edge[j1 + 1]; - xMax1 = word->edge[j0]; - yMin1 = word->yMin; - yMax1 = word->yMax; - break; - case 3: - xMin1 = word->xMin; - xMax1 = word->xMax; - yMin1 = word->edge[j1 + 1]; - yMax1 = word->edge[j0]; - break; - } - if (first || xMin1 < xMin0) { - xMin0 = xMin1; - } - if (first || xMax1 > xMax0) { - xMax0 = xMax1; - } - if (first || yMin1 < yMin0) { - yMin0 = yMin1; - } - if (first || yMax1 > yMax0) { - yMax0 = yMax1; - } - first = gFalse; - } - } - } - } - if (!first) { - *xMin = xMin0; - *xMax = xMax0; - *yMin = yMin0; - *yMax = yMax0; - return gTrue; - } - return gFalse; -} - -void TextPage::dump(void *outputStream, TextOutputFunc outputFunc, - GBool physLayout) { - UnicodeMap *uMap; - TextFlow *flow; - TextBlock *blk; - TextLine *line; - TextLineFrag *frags; - TextWord *word; - int nFrags, fragsSize; - TextLineFrag *frag; - char space[8], eol[16], eop[8]; - int spaceLen, eolLen, eopLen; - GBool pageBreaks; - GString *s; - int col, i, d, n; - - // get the output encoding - if (!(uMap = globalParams->getTextEncoding())) { - return; - } - spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); - eolLen = 0; // make gcc happy - switch (globalParams->getTextEOL()) { - case eolUnix: - eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol)); - break; - case eolDOS: - eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); - eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen); - break; - case eolMac: - eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); - break; - } - eopLen = uMap->mapUnicode(0x0c, eop, sizeof(eop)); - pageBreaks = globalParams->getTextPageBreaks(); - - //~ writing mode (horiz/vert) - - // output the page in raw (content stream) order - if (rawOrder) { - - for (word = rawWords; word; word = word->next) { - s = new GString(); - dumpFragment(word->text, word->len, uMap, s); - (*outputFunc)(outputStream, s->getCString(), s->getLength()); - delete s; - if (word->next && - fabs(word->next->base - word->base) < - maxIntraLineDelta * word->fontSize) { - if (word->next->xMin > word->xMax + minWordSpacing * word->fontSize) { - (*outputFunc)(outputStream, space, spaceLen); - } - } else { - (*outputFunc)(outputStream, eol, eolLen); - } - } - - // output the page, maintaining the original physical layout - } else if (physLayout) { - - // collect the line fragments for the page and sort them - fragsSize = 256; - frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag)); - nFrags = 0; - for (i = 0; i < nBlocks; ++i) { - blk = blocks[i]; - for (line = blk->lines; line; line = line->next) { - if (nFrags == fragsSize) { - fragsSize *= 2; - frags = (TextLineFrag *)greallocn(frags, - fragsSize, sizeof(TextLineFrag)); - } - frags[nFrags].init(line, 0, line->len); - frags[nFrags].computeCoords(gTrue); - ++nFrags; - } - } - qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpYXPrimaryRot); - -#if 0 // for debugging - printf("*** line fragments ***\n"); - for (i = 0; i < nFrags; ++i) { - frag = &frags[i]; - printf("frag: x=%.2f..%.2f y=%.2f..%.2f base=%.2f '", - frag->xMin, frag->xMax, frag->yMin, frag->yMax, frag->base); - for (n = 0; n < frag->len; ++n) { - fputc(frag->line->text[frag->start + n] & 0xff, stdout); - } - printf("'\n"); - } - printf("\n"); -#endif - - // generate output - col = 0; - for (i = 0; i < nFrags; ++i) { - frag = &frags[i]; - - // column alignment - for (; col < frag->col; ++col) { - (*outputFunc)(outputStream, space, spaceLen); - } - - // print the line - s = new GString(); - col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s); - (*outputFunc)(outputStream, s->getCString(), s->getLength()); - delete s; - - // print one or more returns if necessary - if (i == nFrags - 1 || - frags[i+1].col < col || - fabs(frags[i+1].base - frag->base) > - maxIntraLineDelta * frag->line->words->fontSize) { - if (i < nFrags - 1) { - d = (int)((frags[i+1].base - frag->base) / - frag->line->words->fontSize); - if (d < 1) { - d = 1; - } else if (d > 5) { - d = 5; - } - } else { - d = 1; - } - for (; d > 0; --d) { - (*outputFunc)(outputStream, eol, eolLen); - } - col = 0; - } - } - - gfree(frags); - - // output the page, "undoing" the layout - } else { - for (flow = flows; flow; flow = flow->next) { - for (blk = flow->blocks; blk; blk = blk->next) { - for (line = blk->lines; line; line = line->next) { - n = line->len; - if (line->hyphenated && (line->next || blk->next)) { - --n; - } - s = new GString(); - dumpFragment(line->text, n, uMap, s); - (*outputFunc)(outputStream, s->getCString(), s->getLength()); - delete s; - if (!line->hyphenated) { - if (line->next) { - (*outputFunc)(outputStream, space, spaceLen); - } else if (blk->next) { - //~ this is a bit of a kludge - we should really do a more - //~ intelligent determination of paragraphs - if (blk->next->lines->words->fontSize == - blk->lines->words->fontSize) { - (*outputFunc)(outputStream, space, spaceLen); - } else { - (*outputFunc)(outputStream, eol, eolLen); - } - } - } - } - } - (*outputFunc)(outputStream, eol, eolLen); - (*outputFunc)(outputStream, eol, eolLen); - } - } - - // end of page - if (pageBreaks) { - (*outputFunc)(outputStream, eop, eopLen); - } - - uMap->decRefCnt(); -} - -void TextPage::assignColumns(TextLineFrag *frags, int nFrags, GBool oneRot) { - TextLineFrag *frag0, *frag1; - int rot, col1, col2, i, j, k; - - // all text in the region has the same rotation -- recompute the - // column numbers based only on the text in the region - if (oneRot) { - qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpXYLineRot); - rot = frags[0].line->rot; - for (i = 0; i < nFrags; ++i) { - frag0 = &frags[i]; - col1 = 0; - for (j = 0; j < i; ++j) { - frag1 = &frags[j]; - col2 = 0; // make gcc happy - switch (rot) { - case 0: - if (frag0->xMin >= frag1->xMax) { - col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - - frag1->line->col[frag1->start]) + 1; - } else { - for (k = frag1->start; - k < frag1->start + frag1->len && - frag0->xMin >= 0.5 * (frag1->line->edge[k] + - frag1->line->edge[k+1]); - ++k) ; - col2 = frag1->col + - frag1->line->col[k] - frag1->line->col[frag1->start]; - } - break; - case 1: - if (frag0->yMin >= frag1->yMax) { - col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - - frag1->line->col[frag1->start]) + 1; - } else { - for (k = frag1->start; - k < frag1->start + frag1->len && - frag0->yMin >= 0.5 * (frag1->line->edge[k] + - frag1->line->edge[k+1]); - ++k) ; - col2 = frag1->col + - frag1->line->col[k] - frag1->line->col[frag1->start]; - } - break; - case 2: - if (frag0->xMax <= frag1->xMin) { - col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - - frag1->line->col[frag1->start]) + 1; - } else { - for (k = frag1->start; - k < frag1->start + frag1->len && - frag0->xMax <= 0.5 * (frag1->line->edge[k] + - frag1->line->edge[k+1]); - ++k) ; - col2 = frag1->col + - frag1->line->col[k] - frag1->line->col[frag1->start]; - } - break; - case 3: - if (frag0->yMax <= frag1->yMin) { - col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - - frag1->line->col[frag1->start]) + 1; - } else { - for (k = frag1->start; - k < frag1->start + frag1->len && - frag0->yMax <= 0.5 * (frag1->line->edge[k] + - frag1->line->edge[k+1]); - ++k) ; - col2 = frag1->col + - frag1->line->col[k] - frag1->line->col[frag1->start]; - } - break; - } - if (col2 > col1) { - col1 = col2; - } - } - frag0->col = col1; - } - - // the region includes text at different rotations -- use the - // globally assigned column numbers, offset by the minimum column - // number (i.e., shift everything over to column 0) - } else { - col1 = frags[0].col; - for (i = 1; i < nFrags; ++i) { - if (frags[i].col < col1) { - col1 = frags[i].col; - } - } - for (i = 0; i < nFrags; ++i) { - frags[i].col -= col1; - } - } -} - -int TextPage::dumpFragment(Unicode *text, int len, UnicodeMap *uMap, - GString *s) { - char lre[8], rle[8], popdf[8], buf[8]; - int lreLen, rleLen, popdfLen, n; - int nCols, i, j, k; - - nCols = 0; - - if (uMap->isUnicode()) { - - lreLen = uMap->mapUnicode(0x202a, lre, sizeof(lre)); - rleLen = uMap->mapUnicode(0x202b, rle, sizeof(rle)); - popdfLen = uMap->mapUnicode(0x202c, popdf, sizeof(popdf)); - - if (primaryLR) { - - i = 0; - while (i < len) { - // output a left-to-right section - for (j = i; j < len && !unicodeTypeR(text[j]); ++j) ; - for (k = i; k < j; ++k) { - n = uMap->mapUnicode(text[k], buf, sizeof(buf)); - s->append(buf, n); - ++nCols; - } - i = j; - // output a right-to-left section - for (j = i; j < len && !unicodeTypeL(text[j]); ++j) ; - if (j > i) { - s->append(rle, rleLen); - for (k = j - 1; k >= i; --k) { - n = uMap->mapUnicode(text[k], buf, sizeof(buf)); - s->append(buf, n); - ++nCols; - } - s->append(popdf, popdfLen); - i = j; - } - } - - } else { - - s->append(rle, rleLen); - i = len - 1; - while (i >= 0) { - // output a right-to-left section - for (j = i; j >= 0 && !unicodeTypeL(text[j]); --j) ; - for (k = i; k > j; --k) { - n = uMap->mapUnicode(text[k], buf, sizeof(buf)); - s->append(buf, n); - ++nCols; - } - i = j; - // output a left-to-right section - for (j = i; j >= 0 && !unicodeTypeR(text[j]); --j) ; - if (j < i) { - s->append(lre, lreLen); - for (k = j + 1; k <= i; ++k) { - n = uMap->mapUnicode(text[k], buf, sizeof(buf)); - s->append(buf, n); - ++nCols; - } - s->append(popdf, popdfLen); - i = j; - } - } - s->append(popdf, popdfLen); - - } - - } else { - for (i = 0; i < len; ++i) { - n = uMap->mapUnicode(text[i], buf, sizeof(buf)); - s->append(buf, n); - nCols += n; - } - } - - return nCols; -} - -#if TEXTOUT_WORD_LIST -TextWordList *TextPage::makeWordList(GBool physLayout) { - return new TextWordList(this, physLayout); -} -#endif - -//------------------------------------------------------------------------ -// TextOutputDev -//------------------------------------------------------------------------ - -static void outputToFile(void *stream, char *text, int len) { - fwrite(text, 1, len, (FILE *)stream); -} - -TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA, - GBool rawOrderA, GBool append) { - text = NULL; - physLayout = physLayoutA; - rawOrder = rawOrderA; - ok = gTrue; - - // open file - needClose = gFalse; - if (fileName) { - if (!strcmp(fileName, "-")) { - outputStream = stdout; -#ifdef WIN32 - // keep DOS from munging the end-of-line characters - setmode(fileno(stdout), O_BINARY); -#endif - } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) { - needClose = gTrue; - } else { - error(-1, "Couldn't open text file '%s'", fileName); - ok = gFalse; - return; - } - outputFunc = &outputToFile; - } else { - outputStream = NULL; - } - - // set up text object - text = new TextPage(rawOrderA); -} - -TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream, - GBool physLayoutA, GBool rawOrderA) { - outputFunc = func; - outputStream = stream; - needClose = gFalse; - physLayout = physLayoutA; - rawOrder = rawOrderA; - text = new TextPage(rawOrderA); - ok = gTrue; -} - -TextOutputDev::~TextOutputDev() { - if (needClose) { -#ifdef MACOS - ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); -#endif - fclose((FILE *)outputStream); - } - if (text) { - delete text; - } -} - -void TextOutputDev::startPage(int /*pageNum*/, GfxState *state) { - text->startPage(state); -} - -void TextOutputDev::endPage() { - text->endPage(); - text->coalesce(physLayout); - if (outputStream) { - text->dump(outputStream, outputFunc, physLayout); - } -} - -void TextOutputDev::updateFont(GfxState *state) { - text->updateFont(state); -} - -void TextOutputDev::beginString(GfxState */*state*/, GString */*s*/) { -} - -void TextOutputDev::endString(GfxState */*state*/) { -} - -void TextOutputDev::drawChar(GfxState *state, double x, double y, - double dx, double dy, - double /*originX*/, double /*originY*/, - CharCode c, int nBytes, Unicode *u, int uLen) { - text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen); -} - -GBool TextOutputDev::findText(Unicode *s, int len, - GBool startAtTop, GBool stopAtBottom, - GBool startAtLast, GBool stopAtLast, - GBool caseSensitive, GBool backward, - double *xMin, double *yMin, - double *xMax, double *yMax) { - return text->findText(s, len, startAtTop, stopAtBottom, - startAtLast, stopAtLast, caseSensitive, backward, - xMin, yMin, xMax, yMax); -} - -GString *TextOutputDev::getText(double xMin, double yMin, - double xMax, double yMax) { - return text->getText(xMin, yMin, xMax, yMax); -} - -GBool TextOutputDev::findCharRange(int pos, int length, - double *xMin, double *yMin, - double *xMax, double *yMax) { - return text->findCharRange(pos, length, xMin, yMin, xMax, yMax); -} - -#if TEXTOUT_WORD_LIST -TextWordList *TextOutputDev::makeWordList() { - return text->makeWordList(physLayout); -} -#endif - -TextPage *TextOutputDev::takeText() { - TextPage *ret; - - ret = text; - text = new TextPage(rawOrder); - return ret; -} diff --git a/xpdf/xpdf/TextOutputDev.h b/xpdf/xpdf/TextOutputDev.h deleted file mode 100644 index 10fb4c804..000000000 --- a/xpdf/xpdf/TextOutputDev.h +++ /dev/null @@ -1,587 +0,0 @@ -//======================================================================== -// -// TextOutputDev.h -// -// Copyright 1997-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef TEXTOUTPUTDEV_H -#define TEXTOUTPUTDEV_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include "gtypes.h" -#include "GfxFont.h" -#include "OutputDev.h" - -class GString; -class GList; -class GfxFont; -class GfxState; -class UnicodeMap; - -class TextWord; -class TextPool; -class TextLine; -class TextLineFrag; -class TextBlock; -class TextFlow; -class TextWordList; -class TextPage; - -//------------------------------------------------------------------------ - -typedef void (*TextOutputFunc)(void *stream, char *text, int len); - -//------------------------------------------------------------------------ -// TextFontInfo -//------------------------------------------------------------------------ - -class TextFontInfo { -public: - - TextFontInfo(GfxState *state); - ~TextFontInfo(); - - GBool matches(GfxState *state); - -private: - - GfxFont *gfxFont; -#if TEXTOUT_WORD_LIST - GString *fontName; -#endif - - friend class TextWord; - friend class TextPage; -}; - -//------------------------------------------------------------------------ -// TextWord -//------------------------------------------------------------------------ - -class TextWord { -public: - - // Constructor. - TextWord(GfxState *state, int rotA, double x0, double y0, - int charPosA, TextFontInfo *fontA, double fontSize); - - // Destructor. - ~TextWord(); - - // Add a character to the word. - void addChar(GfxState *state, double x, double y, - double dx, double dy, Unicode u); - - // Merge onto the end of . - void merge(TextWord *word); - - // Compares to , returning -1 (<), 0 (=), or +1 (>), - // based on a primary-axis comparison, e.g., x ordering if rot=0. - int primaryCmp(TextWord *word); - - // Return the distance along the primary axis between and - // . - double primaryDelta(TextWord *word); - - static int cmpYX(const void *p1, const void *p2); - -#if TEXTOUT_WORD_LIST - int getLength() { return len; } - Unicode getChar(int idx) { return text[idx]; } - GString *getText(); - GString *getFontName() { return font->fontName; } - void getColor(double *r, double *g, double *b) - { *r = colorR; *g = colorG; *b = colorB; } - void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA) - { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } - double getFontSize() { return fontSize; } - int getRotation() { return rot; } - int getCharPos() { return charPos; } - int getCharLen() { return charLen; } -#endif - -private: - - int rot; // rotation, multiple of 90 degrees - // (0, 1, 2, or 3) - double xMin, xMax; // bounding box x coordinates - double yMin, yMax; // bounding box y coordinates - double base; // baseline x or y coordinate - Unicode *text; // the text - double *edge; // "near" edge x or y coord of each char - // (plus one extra entry for the last char) - int len; // length of text and edge arrays - int size; // size of text and edge arrays - int charPos; // character position (within content stream) - int charLen; // number of content stream characters in - // this word - TextFontInfo *font; // font information - double fontSize; // font size - GBool spaceAfter; // set if there is a space between this - // word and the next word on the line - TextWord *next; // next word in line - -#if TEXTOUT_WORD_LIST - double colorR, // word color - colorG, - colorB; -#endif - - friend class TextPool; - friend class TextLine; - friend class TextBlock; - friend class TextFlow; - friend class TextWordList; - friend class TextPage; -}; - -//------------------------------------------------------------------------ -// TextPool -//------------------------------------------------------------------------ - -class TextPool { -public: - - TextPool(); - ~TextPool(); - - TextWord *getPool(int baseIdx) { return pool[baseIdx - minBaseIdx]; } - void setPool(int baseIdx, TextWord *p) { pool[baseIdx - minBaseIdx] = p; } - - int getBaseIdx(double base); - - void addWord(TextWord *word); - -private: - - int minBaseIdx; // min baseline bucket index - int maxBaseIdx; // max baseline bucket index - TextWord **pool; // array of linked lists, one for each - // baseline value (multiple of 4 pts) - TextWord *cursor; // pointer to last-accessed word - int cursorBaseIdx; // baseline bucket index of last-accessed word - - friend class TextBlock; - friend class TextPage; -}; - -//------------------------------------------------------------------------ -// TextLine -//------------------------------------------------------------------------ - -class TextLine { -public: - - TextLine(TextBlock *blkA, int rotA, double baseA); - ~TextLine(); - - void addWord(TextWord *word); - - // Return the distance along the primary axis between and - // . - double primaryDelta(TextLine *line); - - // Compares to , returning -1 (<), 0 (=), or +1 (>), - // based on a primary-axis comparison, e.g., x ordering if rot=0. - int primaryCmp(TextLine *line); - - // Compares to , returning -1 (<), 0 (=), or +1 (>), - // based on a secondary-axis comparison of the baselines, e.g., y - // ordering if rot=0. - int secondaryCmp(TextLine *line); - - int cmpYX(TextLine *line); - - static int cmpXY(const void *p1, const void *p2); - - void coalesce(UnicodeMap *uMap); - -private: - - TextBlock *blk; // parent block - int rot; // text rotation - double xMin, xMax; // bounding box x coordinates - double yMin, yMax; // bounding box y coordinates - double base; // baseline x or y coordinate - TextWord *words; // words in this line - TextWord *lastWord; // last word in this line - Unicode *text; // Unicode text of the line, including - // spaces between words - double *edge; // "near" edge x or y coord of each char - // (plus one extra entry for the last char) - int *col; // starting column number of each Unicode char - int len; // number of Unicode chars - int convertedLen; // total number of converted characters - GBool hyphenated; // set if last char is a hyphen - TextLine *next; // next line in block - - friend class TextLineFrag; - friend class TextBlock; - friend class TextFlow; - friend class TextWordList; - friend class TextPage; -}; - -//------------------------------------------------------------------------ -// TextBlock -//------------------------------------------------------------------------ - -class TextBlock { -public: - - TextBlock(TextPage *pageA, int rotA); - ~TextBlock(); - - void addWord(TextWord *word); - - void coalesce(UnicodeMap *uMap); - - // Update this block's priMin and priMax values, looking at . - void updatePriMinMax(TextBlock *blk); - - static int cmpXYPrimaryRot(const void *p1, const void *p2); - - static int cmpYXPrimaryRot(const void *p1, const void *p2); - - int primaryCmp(TextBlock *blk); - - double secondaryDelta(TextBlock *blk); - - // Returns true if is below , relative to the page's - // primary rotation. - GBool isBelow(TextBlock *blk); - -private: - - TextPage *page; // the parent page - int rot; // text rotation - double xMin, xMax; // bounding box x coordinates - double yMin, yMax; // bounding box y coordinates - double priMin, priMax; // whitespace bounding box along primary axis - - TextPool *pool; // pool of words (used only until lines - // are built) - TextLine *lines; // linked list of lines - TextLine *curLine; // most recently added line - int nLines; // number of lines - int charCount; // number of characters in the block - int col; // starting column - int nColumns; // number of columns in the block - - TextBlock *next; - TextBlock *stackNext; - - friend class TextLine; - friend class TextLineFrag; - friend class TextFlow; - friend class TextWordList; - friend class TextPage; -}; - -//------------------------------------------------------------------------ -// TextFlow -//------------------------------------------------------------------------ - -class TextFlow { -public: - - TextFlow(TextPage *pageA, TextBlock *blk); - ~TextFlow(); - - // Add a block to the end of this flow. - void addBlock(TextBlock *blk); - - // Returns true if fits below in the flow, i.e., (1) - // it uses a font no larger than the last block added to the flow, - // and (2) it fits within the flow's [priMin, priMax] along the - // primary axis. - GBool blockFits(TextBlock *blk, TextBlock *prevBlk); - -private: - - TextPage *page; // the parent page - double xMin, xMax; // bounding box x coordinates - double yMin, yMax; // bounding box y coordinates - double priMin, priMax; // whitespace bounding box along primary axis - TextBlock *blocks; // blocks in flow - TextBlock *lastBlk; // last block in this flow - TextFlow *next; - - friend class TextWordList; - friend class TextPage; -}; - -#if TEXTOUT_WORD_LIST - -//------------------------------------------------------------------------ -// TextWordList -//------------------------------------------------------------------------ - -class TextWordList { -public: - - // Build a flat word list, in content stream order (if - // text->rawOrder is true), physical layout order (if - // is true and text->rawOrder is false), or reading order (if both - // flags are false). - TextWordList(TextPage *text, GBool physLayout); - - ~TextWordList(); - - // Return the number of words on the list. - int getLength(); - - // Return the th word from the list. - TextWord *get(int idx); - -private: - - GList *words; -}; - -#endif // TEXTOUT_WORD_LIST - -//------------------------------------------------------------------------ -// TextPage -//------------------------------------------------------------------------ - -class TextPage { -public: - - // Constructor. - TextPage(GBool rawOrderA); - - // Destructor. - ~TextPage(); - - // Start a new page. - void startPage(GfxState *state); - - // End the current page. - void endPage(); - - // Update the current font. - void updateFont(GfxState *state); - - // Begin a new word. - void beginWord(GfxState *state, double x0, double y0); - - // Add a character to the current word. - void addChar(GfxState *state, double x, double y, - double dx, double dy, - CharCode c, int nBytes, Unicode *u, int uLen); - - // End the current word, sorting it into the list of words. - void endWord(); - - // Add a word, sorting it into the list of words. - void addWord(TextWord *word); - - // Coalesce strings that look like parts of the same line. - void coalesce(GBool physLayout); - - // Find a string. If is true, starts looking at the - // top of the page; else if is true, starts looking - // immediately after the last find result; else starts looking at - // ,. If is true, stops looking at the - // bottom of the page; else if is true, stops looking - // just before the last find result; else stops looking at - // ,. - GBool findText(Unicode *s, int len, - GBool startAtTop, GBool stopAtBottom, - GBool startAtLast, GBool stopAtLast, - GBool caseSensitive, GBool backward, - double *xMin, double *yMin, - double *xMax, double *yMax); - - // Get the text which is inside the specified rectangle. - GString *getText(double xMin, double yMin, - double xMax, double yMax); - - // Find a string by character position and length. If found, sets - // the text bounding rectangle and returns true; otherwise returns - // false. - GBool findCharRange(int pos, int length, - double *xMin, double *yMin, - double *xMax, double *yMax); - - // Dump contents of page to a file. - void dump(void *outputStream, TextOutputFunc outputFunc, - GBool physLayout); - -#if TEXTOUT_WORD_LIST - // Build a flat word list, in content stream order (if - // this->rawOrder is true), physical layout order (if - // is true and this->rawOrder is false), or reading order (if both - // flags are false). - TextWordList *makeWordList(GBool physLayout); -#endif - -private: - - void clear(); - void assignColumns(TextLineFrag *frags, int nFrags, int rot); - int dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GString *s); - - GBool rawOrder; // keep text in content stream order - - double pageWidth, pageHeight; // width and height of current page - TextWord *curWord; // currently active string - int charPos; // next character position (within content - // stream) - TextFontInfo *curFont; // current font - double curFontSize; // current font size - int nest; // current nesting level (for Type 3 fonts) - int nTinyChars; // number of "tiny" chars seen so far - GBool lastCharOverlap; // set if the last added char overlapped the - // previous char - - TextPool *pools[4]; // a "pool" of TextWords for each rotation - TextFlow *flows; // linked list of flows - TextBlock **blocks; // array of blocks, in yx order - int nBlocks; // number of blocks - int primaryRot; // primary rotation - GBool primaryLR; // primary direction (true means L-to-R, - // false means R-to-L) - TextWord *rawWords; // list of words, in raw order (only if - // rawOrder is set) - TextWord *rawLastWord; // last word on rawWords list - - GList *fonts; // all font info objects used on this - // page [TextFontInfo] - - double lastFindXMin, // coordinates of the last "find" result - lastFindYMin; - GBool haveLastFind; - - friend class TextLine; - friend class TextLineFrag; - friend class TextBlock; - friend class TextFlow; - friend class TextWordList; -}; - -//------------------------------------------------------------------------ -// TextOutputDev -//------------------------------------------------------------------------ - -class TextOutputDev: public OutputDev { -public: - - // Open a text output file. If is NULL, no file is - // written (this is useful, e.g., for searching text). If - // is true, the original physical layout of the text - // is maintained. If is true, the text is kept in - // content stream order. - TextOutputDev(char *fileName, GBool physLayoutA, - GBool rawOrderA, GBool append); - - // Create a TextOutputDev which will write to a generic stream. If - // is true, the original physical layout of the text - // is maintained. If is true, the text is kept in - // content stream order. - TextOutputDev(TextOutputFunc func, void *stream, - GBool physLayoutA, GBool rawOrderA); - - // Destructor. - virtual ~TextOutputDev(); - - // Check if file was successfully created. - virtual GBool isOk() { return ok; } - - //---- get info about output device - - // Does this device use upside-down coordinates? - // (Upside-down means (0,0) is the top left corner of the page.) - virtual GBool upsideDown() { return gTrue; } - - // Does this device use drawChar() or drawString()? - virtual GBool useDrawChar() { return gTrue; } - - // Does this device use beginType3Char/endType3Char? Otherwise, - // text in Type 3 fonts will be drawn with drawChar/drawString. - virtual GBool interpretType3Chars() { return gFalse; } - - // Does this device need non-text content? - virtual GBool needNonText() { return gFalse; } - - //----- initialization and control - - // Start a page. - virtual void startPage(int pageNum, GfxState *state); - - // End a page. - virtual void endPage(); - - //----- update text state - virtual void updateFont(GfxState *state); - - //----- text drawing - virtual void beginString(GfxState *state, GString *s); - virtual void endString(GfxState *state); - virtual void drawChar(GfxState *state, double x, double y, - double dx, double dy, - double originX, double originY, - CharCode c, int nBytes, Unicode *u, int uLen); - - //----- special access - - // Find a string. If is true, starts looking at the - // top of the page; else if is true, starts looking - // immediately after the last find result; else starts looking at - // ,. If is true, stops looking at the - // bottom of the page; else if is true, stops looking - // just before the last find result; else stops looking at - // ,. - GBool findText(Unicode *s, int len, - GBool startAtTop, GBool stopAtBottom, - GBool startAtLast, GBool stopAtLast, - GBool caseSensitive, GBool backward, - double *xMin, double *yMin, - double *xMax, double *yMax); - - // Get the text which is inside the specified rectangle. - GString *getText(double xMin, double yMin, - double xMax, double yMax); - - // Find a string by character position and length. If found, sets - // the text bounding rectangle and returns true; otherwise returns - // false. - GBool findCharRange(int pos, int length, - double *xMin, double *yMin, - double *xMax, double *yMax); - -#if TEXTOUT_WORD_LIST - // Build a flat word list, in content stream order (if - // this->rawOrder is true), physical layout order (if - // this->physLayout is true and this->rawOrder is false), or reading - // order (if both flags are false). - TextWordList *makeWordList(); -#endif - - // Returns the TextPage object for the last rasterized page, - // transferring ownership to the caller. - TextPage *takeText(); - -private: - - TextOutputFunc outputFunc; // output function - void *outputStream; // output stream - GBool needClose; // need to close the output file? - // (only if outputStream is a FILE*) - TextPage *text; // text for the current page - GBool physLayout; // maintain original physical layout when - // dumping text - GBool rawOrder; // keep text in content stream order - GBool ok; // set up ok? -}; - -#endif diff --git a/xpdf/xpdf/UGString.cc b/xpdf/xpdf/UGString.cc deleted file mode 100644 index f99234eb4..000000000 --- a/xpdf/xpdf/UGString.cc +++ /dev/null @@ -1,86 +0,0 @@ -//======================================================================== -// -// UGString.cc -// -// Unicode string -// -// Copyright 2005 Albert Astals Cid -// -//======================================================================== - -#include - -#include "gmem.h" -#include "GString.h" -#include "PDFDocEncoding.h" -#include "UGString.h" - -UGString::UGString(Unicode *u, int l) -{ - s = u; - length = l; -} - -UGString::UGString(GString &str) -{ - if ((str.getChar(0) & 0xff) == 0xfe && (str.getChar(1) & 0xff) == 0xff) - { - length = (str.getLength() - 2) / 2; - s = (Unicode *)gmallocn(length, sizeof(Unicode)); - for (int j = 0; j < length; ++j) { - s[j] = ((str.getChar(2 + 2*j) & 0xff) << 8) | (str.getChar(3 + 2*j) & 0xff); - } - } else - initChar(str); -} - -UGString::UGString(const UGString &str) -{ - length = str.length; - s = (Unicode *)gmallocn(length, sizeof(Unicode)); - memcpy(s, str.s, length * sizeof(Unicode)); -} - -UGString::UGString(const char *str) -{ - GString aux(str); - initChar(aux); -} - -void UGString::initChar(GString &str) -{ - length = str.getLength(); - s = (Unicode *)gmallocn(length, sizeof(Unicode)); - for (int j = 0; j < length; ++j) { - s[j] = pdfDocEncoding[str.getChar(j) & 0xff]; - } -} - -UGString::~UGString() -{ - gfree(s); -} - -int UGString::cmp(UGString *str) const -{ - int n1, n2, i, x; - Unicode *p1, *p2; - - n1 = length; - n2 = str->length; - for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) { - x = *p1 - *p2; - if (x != 0) { - return x; - } - } - return n1 - n2; -} - -const char *UGString::getCString() const -{ - char *res = new char[length + 1]; - for (int i = 0; i < length; i++) res[i] = s[i]; - res[length] = '\0'; - return res; -} diff --git a/xpdf/xpdf/UGString.h b/xpdf/xpdf/UGString.h deleted file mode 100644 index 9a03b65a2..000000000 --- a/xpdf/xpdf/UGString.h +++ /dev/null @@ -1,55 +0,0 @@ -//======================================================================== -// -// UGString.h -// -// Unicode string -// -// Copyright 2005 Albert Astals Cid -// -//======================================================================== - -#ifndef UGSTRING_H -#define UGSTRING_H - -#include "CharTypes.h" - -class GString; - -class UGString -{ -public: - // Create an unicode string - UGString(Unicode *u, int l); - - // Create a unicode string from . - UGString(GString &str); - - // Copy the unicode string - UGString(const UGString &str); - - // Create a unicode string from . - UGString(const char *str); - - // Destructor. - ~UGString(); - - // Get length. - int getLength() const { return length; } - - // Compare two strings: -1:< 0:= +1:> - int cmp(UGString *str) const; - - // get the unicode - Unicode *unicode() const { return s; } - - // get the const char* - const char *getCString() const; - -private: - void initChar(GString &str); - - int length; - Unicode *s; -}; - -#endif diff --git a/xpdf/xpdf/UTF8.h b/xpdf/xpdf/UTF8.h deleted file mode 100644 index 8536dbf94..000000000 --- a/xpdf/xpdf/UTF8.h +++ /dev/null @@ -1,56 +0,0 @@ -//======================================================================== -// -// UTF8.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -static int mapUTF8(Unicode u, char *buf, int bufSize) { - if (u <= 0x0000007f) { - if (bufSize < 1) { - return 0; - } - buf[0] = (char)u; - return 1; - } else if (u <= 0x000007ff) { - if (bufSize < 2) { - return 0; - } - buf[0] = (char)(0xc0 + (u >> 6)); - buf[1] = (char)(0x80 + (u & 0x3f)); - return 2; - } else if (u <= 0x0000ffff) { - if (bufSize < 3) { - return 0; - } - buf[0] = (char)(0xe0 + (u >> 12)); - buf[1] = (char)(0x80 + ((u >> 6) & 0x3f)); - buf[2] = (char)(0x80 + (u & 0x3f)); - return 3; - } else if (u <= 0x0010ffff) { - if (bufSize < 4) { - return 0; - } - buf[0] = (char)(0xf0 + (u >> 18)); - buf[1] = (char)(0x80 + ((u >> 12) & 0x3f)); - buf[2] = (char)(0x80 + ((u >> 6) & 0x3f)); - buf[3] = (char)(0x80 + (u & 0x3f)); - return 4; - } else { - return 0; - } -} - -static int mapUCS2(Unicode u, char *buf, int bufSize) { - if (u <= 0xffff) { - if (bufSize < 2) { - return 0; - } - buf[0] = (char)((u >> 8) & 0xff); - buf[1] = (char)(u & 0xff); - return 2; - } else { - return 0; - } -} diff --git a/xpdf/xpdf/UnicodeMap.cc b/xpdf/xpdf/UnicodeMap.cc deleted file mode 100644 index 1aa916110..000000000 --- a/xpdf/xpdf/UnicodeMap.cc +++ /dev/null @@ -1,293 +0,0 @@ -//======================================================================== -// -// UnicodeMap.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "gfile.h" -#include "GString.h" -#include "GList.h" -#include "Error.h" -#include "GlobalParams.h" -#include "UnicodeMap.h" - -//------------------------------------------------------------------------ - -#define maxExtCode 16 - -struct UnicodeMapExt { - Unicode u; // Unicode char - char code[maxExtCode]; - Guint nBytes; -}; - -//------------------------------------------------------------------------ - -UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { - FILE *f; - UnicodeMap *map; - UnicodeMapRange *range; - UnicodeMapExt *eMap; - int size, eMapsSize; - char buf[256]; - int line, nBytes, i, x; - char *tok1, *tok2, *tok3; - - if (!(f = globalParams->getUnicodeMapFile(encodingNameA))) { - error(-1, "Couldn't find unicodeMap file for the '%s' encoding", - encodingNameA->getCString()); - return NULL; - } - - map = new UnicodeMap(encodingNameA->copy()); - - size = 8; - map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange)); - eMapsSize = 0; - - line = 1; - while (getLine(buf, sizeof(buf), f)) { - if ((tok1 = strtok(buf, " \t\r\n")) && - (tok2 = strtok(NULL, " \t\r\n"))) { - if (!(tok3 = strtok(NULL, " \t\r\n"))) { - tok3 = tok2; - tok2 = tok1; - } - nBytes = strlen(tok3) / 2; - if (nBytes <= 4) { - if (map->len == size) { - size *= 2; - map->ranges = (UnicodeMapRange *) - greallocn(map->ranges, size, sizeof(UnicodeMapRange)); - } - range = &map->ranges[map->len]; - sscanf(tok1, "%x", &range->start); - sscanf(tok2, "%x", &range->end); - sscanf(tok3, "%x", &range->code); - range->nBytes = nBytes; - ++map->len; - } else if (tok2 == tok1) { - if (map->eMapsLen == eMapsSize) { - eMapsSize += 16; - map->eMaps = (UnicodeMapExt *) - greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt)); - } - eMap = &map->eMaps[map->eMapsLen]; - sscanf(tok1, "%x", &eMap->u); - for (i = 0; i < nBytes; ++i) { - sscanf(tok3 + i*2, "%2x", &x); - eMap->code[i] = (char)x; - } - eMap->nBytes = nBytes; - ++map->eMapsLen; - } else { - error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding", - line, encodingNameA->getCString()); - } - } else { - error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding", - line, encodingNameA->getCString()); - } - ++line; - } - - fclose(f); - - return map; -} - -UnicodeMap::UnicodeMap(GString *encodingNameA) { - encodingName = encodingNameA; - unicodeOut = gFalse; - kind = unicodeMapUser; - ranges = NULL; - len = 0; - eMaps = NULL; - eMapsLen = 0; - refCnt = 1; -#if MULTITHREADED - gInitMutex(&mutex); -#endif -} - -UnicodeMap::UnicodeMap(const char *encodingNameA, GBool unicodeOutA, - UnicodeMapRange *rangesA, int lenA) { - encodingName = new GString(encodingNameA); - unicodeOut = unicodeOutA; - kind = unicodeMapResident; - ranges = rangesA; - len = lenA; - eMaps = NULL; - eMapsLen = 0; - refCnt = 1; -#if MULTITHREADED - gInitMutex(&mutex); -#endif -} - -UnicodeMap::UnicodeMap(const char *encodingNameA, GBool unicodeOutA, - UnicodeMapFunc funcA) { - encodingName = new GString(encodingNameA); - unicodeOut = unicodeOutA; - kind = unicodeMapFunc; - func = funcA; - eMaps = NULL; - eMapsLen = 0; - refCnt = 1; -#if MULTITHREADED - gInitMutex(&mutex); -#endif -} - -UnicodeMap::~UnicodeMap() { - delete encodingName; - if (kind == unicodeMapUser && ranges) { - gfree(ranges); - } - if (eMaps) { - gfree(eMaps); - } -#if MULTITHREADED - gDestroyMutex(&mutex); -#endif -} - -void UnicodeMap::incRefCnt() { -#if MULTITHREADED - gLockMutex(&mutex); -#endif - ++refCnt; -#if MULTITHREADED - gUnlockMutex(&mutex); -#endif -} - -void UnicodeMap::decRefCnt() { - GBool done; - -#if MULTITHREADED - gLockMutex(&mutex); -#endif - done = --refCnt == 0; -#if MULTITHREADED - gUnlockMutex(&mutex); -#endif - if (done) { - delete this; - } -} - -GBool UnicodeMap::match(GString *encodingNameA) { - return !encodingName->cmp(encodingNameA); -} - -int UnicodeMap::mapUnicode(Unicode u, char *buf, int bufSize) { - int a, b, m, n, i, j; - Guint code; - - if (kind == unicodeMapFunc) { - return (*func)(u, buf, bufSize); - } - - a = 0; - b = len; - if (u >= ranges[a].start) { - // invariant: ranges[a].start <= u < ranges[b].start - while (b - a > 1) { - m = (a + b) / 2; - if (u >= ranges[m].start) { - a = m; - } else if (u < ranges[m].start) { - b = m; - } - } - if (u <= ranges[a].end) { - n = ranges[a].nBytes; - if (n > bufSize) { - return 0; - } - code = ranges[a].code + (u - ranges[a].start); - for (i = n - 1; i >= 0; --i) { - buf[i] = (char)(code & 0xff); - code >>= 8; - } - return n; - } - } - - for (i = 0; i < eMapsLen; ++i) { - if (eMaps[i].u == u) { - n = eMaps[i].nBytes; - for (j = 0; j < n; ++j) { - buf[j] = eMaps[i].code[j]; - } - return n; - } - } - - return 0; -} - -//------------------------------------------------------------------------ - -UnicodeMapCache::UnicodeMapCache() { - int i; - - for (i = 0; i < unicodeMapCacheSize; ++i) { - cache[i] = NULL; - } -} - -UnicodeMapCache::~UnicodeMapCache() { - int i; - - for (i = 0; i < unicodeMapCacheSize; ++i) { - if (cache[i]) { - cache[i]->decRefCnt(); - } - } -} - -UnicodeMap *UnicodeMapCache::getUnicodeMap(GString *encodingName) { - UnicodeMap *map; - int i, j; - - if (cache[0] && cache[0]->match(encodingName)) { - cache[0]->incRefCnt(); - return cache[0]; - } - for (i = 1; i < unicodeMapCacheSize; ++i) { - if (cache[i] && cache[i]->match(encodingName)) { - map = cache[i]; - for (j = i; j >= 1; --j) { - cache[j] = cache[j - 1]; - } - cache[0] = map; - map->incRefCnt(); - return map; - } - } - if ((map = UnicodeMap::parse(encodingName))) { - if (cache[unicodeMapCacheSize - 1]) { - cache[unicodeMapCacheSize - 1]->decRefCnt(); - } - for (j = unicodeMapCacheSize - 1; j >= 1; --j) { - cache[j] = cache[j - 1]; - } - cache[0] = map; - map->incRefCnt(); - return map; - } - return NULL; -} diff --git a/xpdf/xpdf/UnicodeMap.h b/xpdf/xpdf/UnicodeMap.h deleted file mode 100644 index 66c482ca7..000000000 --- a/xpdf/xpdf/UnicodeMap.h +++ /dev/null @@ -1,123 +0,0 @@ -//======================================================================== -// -// UnicodeMap.h -// -// Mapping from Unicode to an encoding. -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef UNICODEMAP_H -#define UNICODEMAP_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "CharTypes.h" - -#if MULTITHREADED -#include "GMutex.h" -#endif - -class GString; - -//------------------------------------------------------------------------ - -enum UnicodeMapKind { - unicodeMapUser, // read from a file - unicodeMapResident, // static list of ranges - unicodeMapFunc // function pointer -}; - -typedef int (*UnicodeMapFunc)(Unicode u, char *buf, int bufSize); - -struct UnicodeMapRange { - Unicode start, end; // range of Unicode chars - Guint code, nBytes; // first output code -}; - -struct UnicodeMapExt; - -//------------------------------------------------------------------------ - -class UnicodeMap { -public: - - // Create the UnicodeMap specified by . Sets the - // initial reference count to 1. Returns NULL on failure. - static UnicodeMap *parse(GString *encodingNameA); - - // Create a resident UnicodeMap. - UnicodeMap(const char *encodingNameA, GBool unicodeOutA, - UnicodeMapRange *rangesA, int lenA); - - // Create a resident UnicodeMap that uses a function instead of a - // list of ranges. - UnicodeMap(const char *encodingNameA, GBool unicodeOutA, - UnicodeMapFunc funcA); - - ~UnicodeMap(); - - void incRefCnt(); - void decRefCnt(); - - GString *getEncodingName() { return encodingName; } - - GBool isUnicode() { return unicodeOut; } - - // Return true if this UnicodeMap matches the specified - // . - GBool match(GString *encodingNameA); - - // Map Unicode to the target encoding. Fills in with the - // output and returns the number of bytes used. Output will be - // truncated at bytes. No string terminator is written. - // Returns 0 if no mapping is found. - int mapUnicode(Unicode u, char *buf, int bufSize); - -private: - - UnicodeMap(GString *encodingNameA); - - GString *encodingName; - UnicodeMapKind kind; - GBool unicodeOut; - union { - UnicodeMapRange *ranges; // (user, resident) - UnicodeMapFunc func; // (func) - }; - int len; // (user, resident) - UnicodeMapExt *eMaps; // (user) - int eMapsLen; // (user) - int refCnt; -#if MULTITHREADED - GMutex mutex; -#endif -}; - -//------------------------------------------------------------------------ - -#define unicodeMapCacheSize 4 - -class UnicodeMapCache { -public: - - UnicodeMapCache(); - ~UnicodeMapCache(); - - // Get the UnicodeMap for . Increments its reference - // count; there will be one reference for the cache plus one for the - // caller of this function. Returns NULL on failure. - UnicodeMap *getUnicodeMap(GString *encodingName); - -private: - - UnicodeMap *cache[unicodeMapCacheSize]; -}; - -#endif diff --git a/xpdf/xpdf/UnicodeMapTables.h b/xpdf/xpdf/UnicodeMapTables.h deleted file mode 100644 index 9c5103461..000000000 --- a/xpdf/xpdf/UnicodeMapTables.h +++ /dev/null @@ -1,361 +0,0 @@ -//======================================================================== -// -// UnicodeMapTables.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -static UnicodeMapRange latin1UnicodeMapRanges[] = { - { 0x000a, 0x000a, 0x0a, 1 }, - { 0x000c, 0x000d, 0x0c, 1 }, - { 0x0020, 0x007e, 0x20, 1 }, - { 0x00a0, 0x00a0, 0x20, 1 }, - { 0x00a1, 0x00ac, 0xa1, 1 }, - { 0x00ae, 0x00ff, 0xae, 1 }, - { 0x010c, 0x010c, 0x43, 1 }, - { 0x010d, 0x010d, 0x63, 1 }, - { 0x0131, 0x0131, 0x69, 1 }, - { 0x0141, 0x0141, 0x4c, 1 }, - { 0x0142, 0x0142, 0x6c, 1 }, - { 0x0152, 0x0152, 0x4f45, 2 }, - { 0x0153, 0x0153, 0x6f65, 2 }, - { 0x0160, 0x0160, 0x53, 1 }, - { 0x0161, 0x0161, 0x73, 1 }, - { 0x0178, 0x0178, 0x59, 1 }, - { 0x017d, 0x017d, 0x5a, 1 }, - { 0x017e, 0x017e, 0x7a, 1 }, - { 0x02c6, 0x02c6, 0x5e, 1 }, - { 0x02da, 0x02da, 0xb0, 1 }, - { 0x02dc, 0x02dc, 0x7e, 1 }, - { 0x2013, 0x2013, 0xad, 1 }, - { 0x2014, 0x2014, 0x2d2d, 2 }, - { 0x2018, 0x2018, 0x60, 1 }, - { 0x2019, 0x2019, 0x27, 1 }, - { 0x201a, 0x201a, 0x2c, 1 }, - { 0x201c, 0x201c, 0x22, 1 }, - { 0x201d, 0x201d, 0x22, 1 }, - { 0x201e, 0x201e, 0x2c2c, 2 }, - { 0x2022, 0x2022, 0xb7, 1 }, - { 0x2026, 0x2026, 0x2e2e2e, 3 }, - { 0x2039, 0x2039, 0x3c, 1 }, - { 0x203a, 0x203a, 0x3e, 1 }, - { 0x2044, 0x2044, 0x2f, 1 }, - { 0x2122, 0x2122, 0x544d, 2 }, - { 0x2212, 0x2212, 0x2d, 1 }, - { 0xf6f9, 0xf6f9, 0x4c, 1 }, - { 0xf6fa, 0xf6fa, 0x4f45, 2 }, - { 0xf6fc, 0xf6fc, 0xb0, 1 }, - { 0xf6fd, 0xf6fd, 0x53, 1 }, - { 0xf6fe, 0xf6fe, 0x7e, 1 }, - { 0xf6ff, 0xf6ff, 0x5a, 1 }, - { 0xf721, 0xf721, 0x21, 1 }, - { 0xf724, 0xf724, 0x24, 1 }, - { 0xf726, 0xf726, 0x26, 1 }, - { 0xf730, 0xf739, 0x30, 1 }, - { 0xf73f, 0xf73f, 0x3f, 1 }, - { 0xf761, 0xf77a, 0x41, 1 }, - { 0xf7a1, 0xf7a2, 0xa1, 1 }, - { 0xf7bf, 0xf7bf, 0xbf, 1 }, - { 0xf7e0, 0xf7f6, 0xc0, 1 }, - { 0xf7f8, 0xf7fe, 0xd8, 1 }, - { 0xf7ff, 0xf7ff, 0x59, 1 }, - { 0xfb00, 0xfb00, 0x6666, 2 }, - { 0xfb01, 0xfb01, 0x6669, 2 }, - { 0xfb02, 0xfb02, 0x666c, 2 }, - { 0xfb03, 0xfb03, 0x666669, 3 }, - { 0xfb04, 0xfb04, 0x66666c, 3 } -}; -#define latin1UnicodeMapLen (sizeof(latin1UnicodeMapRanges) / sizeof(UnicodeMapRange)) - -static UnicodeMapRange ascii7UnicodeMapRanges[] = { - { 0x000a, 0x000a, 0x0a, 1 }, - { 0x000c, 0x000d, 0x0c, 1 }, - { 0x0020, 0x005f, 0x20, 1 }, - { 0x0061, 0x007e, 0x61, 1 }, - { 0x00a6, 0x00a6, 0x7c, 1 }, - { 0x00a9, 0x00a9, 0x286329, 3 }, - { 0x00ae, 0x00ae, 0x285229, 3 }, - { 0x00b7, 0x00b7, 0x2a, 1 }, - { 0x00bc, 0x00bc, 0x312f34, 3 }, - { 0x00bd, 0x00bd, 0x312f32, 3 }, - { 0x00be, 0x00be, 0x332f34, 3 }, - { 0x00c0, 0x00c0, 0x41, 1 }, - { 0x00c1, 0x00c1, 0x41, 1 }, - { 0x00c2, 0x00c2, 0x41, 1 }, - { 0x00c3, 0x00c3, 0x41, 1 }, - { 0x00c4, 0x00c4, 0x41, 1 }, - { 0x00c5, 0x00c5, 0x41, 1 }, - { 0x00c6, 0x00c6, 0x4145, 2 }, - { 0x00c7, 0x00c7, 0x43, 1 }, - { 0x00c8, 0x00c8, 0x45, 1 }, - { 0x00c9, 0x00c9, 0x45, 1 }, - { 0x00ca, 0x00ca, 0x45, 1 }, - { 0x00cb, 0x00cb, 0x45, 1 }, - { 0x00cc, 0x00cc, 0x49, 1 }, - { 0x00cd, 0x00cd, 0x49, 1 }, - { 0x00ce, 0x00ce, 0x49, 1 }, - { 0x00cf, 0x00cf, 0x49, 1 }, - { 0x00d1, 0x00d2, 0x4e, 1 }, - { 0x00d3, 0x00d3, 0x4f, 1 }, - { 0x00d4, 0x00d4, 0x4f, 1 }, - { 0x00d5, 0x00d5, 0x4f, 1 }, - { 0x00d6, 0x00d6, 0x4f, 1 }, - { 0x00d7, 0x00d7, 0x78, 1 }, - { 0x00d8, 0x00d8, 0x4f, 1 }, - { 0x00d9, 0x00d9, 0x55, 1 }, - { 0x00da, 0x00da, 0x55, 1 }, - { 0x00db, 0x00db, 0x55, 1 }, - { 0x00dc, 0x00dc, 0x55, 1 }, - { 0x00dd, 0x00dd, 0x59, 1 }, - { 0x00e0, 0x00e0, 0x61, 1 }, - { 0x00e1, 0x00e1, 0x61, 1 }, - { 0x00e2, 0x00e2, 0x61, 1 }, - { 0x00e3, 0x00e3, 0x61, 1 }, - { 0x00e4, 0x00e4, 0x61, 1 }, - { 0x00e5, 0x00e5, 0x61, 1 }, - { 0x00e6, 0x00e6, 0x6165, 2 }, - { 0x00e7, 0x00e7, 0x63, 1 }, - { 0x00e8, 0x00e8, 0x65, 1 }, - { 0x00e9, 0x00e9, 0x65, 1 }, - { 0x00ea, 0x00ea, 0x65, 1 }, - { 0x00eb, 0x00eb, 0x65, 1 }, - { 0x00ec, 0x00ec, 0x69, 1 }, - { 0x00ed, 0x00ed, 0x69, 1 }, - { 0x00ee, 0x00ee, 0x69, 1 }, - { 0x00ef, 0x00ef, 0x69, 1 }, - { 0x00f1, 0x00f2, 0x6e, 1 }, - { 0x00f3, 0x00f3, 0x6f, 1 }, - { 0x00f4, 0x00f4, 0x6f, 1 }, - { 0x00f5, 0x00f5, 0x6f, 1 }, - { 0x00f6, 0x00f6, 0x6f, 1 }, - { 0x00f7, 0x00f7, 0x2f, 1 }, - { 0x00f8, 0x00f8, 0x6f, 1 }, - { 0x00f9, 0x00f9, 0x75, 1 }, - { 0x00fa, 0x00fa, 0x75, 1 }, - { 0x00fb, 0x00fb, 0x75, 1 }, - { 0x00fc, 0x00fc, 0x75, 1 }, - { 0x00fd, 0x00fd, 0x79, 1 }, - { 0x00ff, 0x00ff, 0x79, 1 }, - { 0x0131, 0x0131, 0x69, 1 }, - { 0x0141, 0x0141, 0x4c, 1 }, - { 0x0152, 0x0152, 0x4f45, 2 }, - { 0x0153, 0x0153, 0x6f65, 2 }, - { 0x0160, 0x0160, 0x53, 1 }, - { 0x0178, 0x0178, 0x59, 1 }, - { 0x017d, 0x017d, 0x5a, 1 }, - { 0x2013, 0x2013, 0x2d, 1 }, - { 0x2014, 0x2014, 0x2d2d, 2 }, - { 0x2018, 0x2018, 0x60, 1 }, - { 0x2019, 0x2019, 0x27, 1 }, - { 0x201c, 0x201c, 0x22, 1 }, - { 0x201d, 0x201d, 0x22, 1 }, - { 0x2022, 0x2022, 0x2a, 1 }, - { 0x2026, 0x2026, 0x2e2e2e, 3 }, - { 0x2122, 0x2122, 0x544d, 2 }, - { 0x2212, 0x2212, 0x2d, 1 }, - { 0xf6f9, 0xf6f9, 0x4c, 1 }, - { 0xf6fa, 0xf6fa, 0x4f45, 2 }, - { 0xf6fd, 0xf6fd, 0x53, 1 }, - { 0xf6fe, 0xf6fe, 0x7e, 1 }, - { 0xf6ff, 0xf6ff, 0x5a, 1 }, - { 0xf721, 0xf721, 0x21, 1 }, - { 0xf724, 0xf724, 0x24, 1 }, - { 0xf726, 0xf726, 0x26, 1 }, - { 0xf730, 0xf739, 0x30, 1 }, - { 0xf73f, 0xf73f, 0x3f, 1 }, - { 0xf761, 0xf77a, 0x41, 1 }, - { 0xf7e0, 0xf7e0, 0x41, 1 }, - { 0xf7e1, 0xf7e1, 0x41, 1 }, - { 0xf7e2, 0xf7e2, 0x41, 1 }, - { 0xf7e3, 0xf7e3, 0x41, 1 }, - { 0xf7e4, 0xf7e4, 0x41, 1 }, - { 0xf7e5, 0xf7e5, 0x41, 1 }, - { 0xf7e6, 0xf7e6, 0x4145, 2 }, - { 0xf7e7, 0xf7e7, 0x43, 1 }, - { 0xf7e8, 0xf7e8, 0x45, 1 }, - { 0xf7e9, 0xf7e9, 0x45, 1 }, - { 0xf7ea, 0xf7ea, 0x45, 1 }, - { 0xf7eb, 0xf7eb, 0x45, 1 }, - { 0xf7ec, 0xf7ec, 0x49, 1 }, - { 0xf7ed, 0xf7ed, 0x49, 1 }, - { 0xf7ee, 0xf7ee, 0x49, 1 }, - { 0xf7ef, 0xf7ef, 0x49, 1 }, - { 0xf7f1, 0xf7f2, 0x4e, 1 }, - { 0xf7f3, 0xf7f3, 0x4f, 1 }, - { 0xf7f4, 0xf7f4, 0x4f, 1 }, - { 0xf7f5, 0xf7f5, 0x4f, 1 }, - { 0xf7f6, 0xf7f6, 0x4f, 1 }, - { 0xf7f8, 0xf7f8, 0x4f, 1 }, - { 0xf7f9, 0xf7f9, 0x55, 1 }, - { 0xf7fa, 0xf7fa, 0x55, 1 }, - { 0xf7fb, 0xf7fb, 0x55, 1 }, - { 0xf7fc, 0xf7fc, 0x55, 1 }, - { 0xf7fd, 0xf7fd, 0x59, 1 }, - { 0xf7ff, 0xf7ff, 0x59, 1 }, - { 0xfb00, 0xfb00, 0x6666, 2 }, - { 0xfb01, 0xfb01, 0x6669, 2 }, - { 0xfb02, 0xfb02, 0x666c, 2 }, - { 0xfb03, 0xfb03, 0x666669, 3 }, - { 0xfb04, 0xfb04, 0x66666c, 3 } -}; -#define ascii7UnicodeMapLen (sizeof(ascii7UnicodeMapRanges) / sizeof(UnicodeMapRange)) - -static UnicodeMapRange symbolUnicodeMapRanges[] = { - { 0x0020, 0x0021, 0x20, 1 }, - { 0x0023, 0x0023, 0x23, 1 }, - { 0x0025, 0x0026, 0x25, 1 }, - { 0x0028, 0x0029, 0x28, 1 }, - { 0x002b, 0x002c, 0x2b, 1 }, - { 0x002e, 0x003f, 0x2e, 1 }, - { 0x005b, 0x005b, 0x5b, 1 }, - { 0x005d, 0x005d, 0x5d, 1 }, - { 0x005f, 0x005f, 0x5f, 1 }, - { 0x007b, 0x007d, 0x7b, 1 }, - { 0x00ac, 0x00ac, 0xd8, 1 }, - { 0x00b0, 0x00b1, 0xb0, 1 }, - { 0x00b5, 0x00b5, 0x6d, 1 }, - { 0x00d7, 0x00d7, 0xb4, 1 }, - { 0x00f7, 0x00f7, 0xb8, 1 }, - { 0x0192, 0x0192, 0xa6, 1 }, - { 0x0391, 0x0392, 0x41, 1 }, - { 0x0393, 0x0393, 0x47, 1 }, - { 0x0395, 0x0395, 0x45, 1 }, - { 0x0396, 0x0396, 0x5a, 1 }, - { 0x0397, 0x0397, 0x48, 1 }, - { 0x0398, 0x0398, 0x51, 1 }, - { 0x0399, 0x0399, 0x49, 1 }, - { 0x039a, 0x039d, 0x4b, 1 }, - { 0x039e, 0x039e, 0x58, 1 }, - { 0x039f, 0x03a0, 0x4f, 1 }, - { 0x03a1, 0x03a1, 0x52, 1 }, - { 0x03a3, 0x03a5, 0x53, 1 }, - { 0x03a6, 0x03a6, 0x46, 1 }, - { 0x03a7, 0x03a7, 0x43, 1 }, - { 0x03a8, 0x03a8, 0x59, 1 }, - { 0x03b1, 0x03b2, 0x61, 1 }, - { 0x03b3, 0x03b3, 0x67, 1 }, - { 0x03b4, 0x03b5, 0x64, 1 }, - { 0x03b6, 0x03b6, 0x7a, 1 }, - { 0x03b7, 0x03b7, 0x68, 1 }, - { 0x03b8, 0x03b8, 0x71, 1 }, - { 0x03b9, 0x03b9, 0x69, 1 }, - { 0x03ba, 0x03bb, 0x6b, 1 }, - { 0x03bd, 0x03bd, 0x6e, 1 }, - { 0x03be, 0x03be, 0x78, 1 }, - { 0x03bf, 0x03c0, 0x6f, 1 }, - { 0x03c1, 0x03c1, 0x72, 1 }, - { 0x03c2, 0x03c2, 0x56, 1 }, - { 0x03c3, 0x03c5, 0x73, 1 }, - { 0x03c6, 0x03c6, 0x66, 1 }, - { 0x03c7, 0x03c7, 0x63, 1 }, - { 0x03c8, 0x03c8, 0x79, 1 }, - { 0x03c9, 0x03c9, 0x77, 1 }, - { 0x03d1, 0x03d1, 0x4a, 1 }, - { 0x03d2, 0x03d2, 0xa1, 1 }, - { 0x03d5, 0x03d5, 0x6a, 1 }, - { 0x03d6, 0x03d6, 0x76, 1 }, - { 0x2022, 0x2022, 0xb7, 1 }, - { 0x2026, 0x2026, 0xbc, 1 }, - { 0x2032, 0x2032, 0xa2, 1 }, - { 0x2033, 0x2033, 0xb2, 1 }, - { 0x2044, 0x2044, 0xa4, 1 }, - { 0x2111, 0x2111, 0xc1, 1 }, - { 0x2118, 0x2118, 0xc3, 1 }, - { 0x211c, 0x211c, 0xc2, 1 }, - { 0x2126, 0x2126, 0x57, 1 }, - { 0x2135, 0x2135, 0xc0, 1 }, - { 0x2190, 0x2193, 0xac, 1 }, - { 0x2194, 0x2194, 0xab, 1 }, - { 0x21b5, 0x21b5, 0xbf, 1 }, - { 0x21d0, 0x21d3, 0xdc, 1 }, - { 0x21d4, 0x21d4, 0xdb, 1 }, - { 0x2200, 0x2200, 0x22, 1 }, - { 0x2202, 0x2202, 0xb6, 1 }, - { 0x2203, 0x2203, 0x24, 1 }, - { 0x2205, 0x2205, 0xc6, 1 }, - { 0x2206, 0x2206, 0x44, 1 }, - { 0x2207, 0x2207, 0xd1, 1 }, - { 0x2208, 0x2209, 0xce, 1 }, - { 0x220b, 0x220b, 0x27, 1 }, - { 0x220f, 0x220f, 0xd5, 1 }, - { 0x2211, 0x2211, 0xe5, 1 }, - { 0x2212, 0x2212, 0x2d, 1 }, - { 0x2217, 0x2217, 0x2a, 1 }, - { 0x221a, 0x221a, 0xd6, 1 }, - { 0x221d, 0x221d, 0xb5, 1 }, - { 0x221e, 0x221e, 0xa5, 1 }, - { 0x2220, 0x2220, 0xd0, 1 }, - { 0x2227, 0x2228, 0xd9, 1 }, - { 0x2229, 0x222a, 0xc7, 1 }, - { 0x222b, 0x222b, 0xf2, 1 }, - { 0x2234, 0x2234, 0x5c, 1 }, - { 0x223c, 0x223c, 0x7e, 1 }, - { 0x2245, 0x2245, 0x40, 1 }, - { 0x2248, 0x2248, 0xbb, 1 }, - { 0x2260, 0x2261, 0xb9, 1 }, - { 0x2264, 0x2264, 0xa3, 1 }, - { 0x2265, 0x2265, 0xb3, 1 }, - { 0x2282, 0x2282, 0xcc, 1 }, - { 0x2283, 0x2283, 0xc9, 1 }, - { 0x2284, 0x2284, 0xcb, 1 }, - { 0x2286, 0x2286, 0xcd, 1 }, - { 0x2287, 0x2287, 0xca, 1 }, - { 0x2295, 0x2295, 0xc5, 1 }, - { 0x2297, 0x2297, 0xc4, 1 }, - { 0x22a5, 0x22a5, 0x5e, 1 }, - { 0x22c5, 0x22c5, 0xd7, 1 }, - { 0x2320, 0x2320, 0xf3, 1 }, - { 0x2321, 0x2321, 0xf5, 1 }, - { 0x2329, 0x2329, 0xe1, 1 }, - { 0x232a, 0x232a, 0xf1, 1 }, - { 0x25ca, 0x25ca, 0xe0, 1 }, - { 0x2660, 0x2660, 0xaa, 1 }, - { 0x2663, 0x2663, 0xa7, 1 }, - { 0x2665, 0x2665, 0xa9, 1 }, - { 0x2666, 0x2666, 0xa8, 1 }, - { 0xf6d9, 0xf6d9, 0xd3, 1 }, - { 0xf6da, 0xf6da, 0xd2, 1 }, - { 0xf6db, 0xf6db, 0xd4, 1 }, - { 0xf8e5, 0xf8e5, 0x60, 1 }, - { 0xf8e6, 0xf8e7, 0xbd, 1 }, - { 0xf8e8, 0xf8ea, 0xe2, 1 }, - { 0xf8eb, 0xf8f4, 0xe6, 1 }, - { 0xf8f5, 0xf8f5, 0xf4, 1 }, - { 0xf8f6, 0xf8fe, 0xf6, 1 } -}; -#define symbolUnicodeMapLen (sizeof(symbolUnicodeMapRanges) / sizeof(UnicodeMapRange)) - -static UnicodeMapRange zapfDingbatsUnicodeMapRanges[] = { - { 0x0020, 0x0020, 0x20, 1 }, - { 0x2192, 0x2192, 0xd5, 1 }, - { 0x2194, 0x2195, 0xd6, 1 }, - { 0x2460, 0x2469, 0xac, 1 }, - { 0x25a0, 0x25a0, 0x6e, 1 }, - { 0x25b2, 0x25b2, 0x73, 1 }, - { 0x25bc, 0x25bc, 0x74, 1 }, - { 0x25c6, 0x25c6, 0x75, 1 }, - { 0x25cf, 0x25cf, 0x6c, 1 }, - { 0x25d7, 0x25d7, 0x77, 1 }, - { 0x2605, 0x2605, 0x48, 1 }, - { 0x260e, 0x260e, 0x25, 1 }, - { 0x261b, 0x261b, 0x2a, 1 }, - { 0x261e, 0x261e, 0x2b, 1 }, - { 0x2660, 0x2660, 0xab, 1 }, - { 0x2663, 0x2663, 0xa8, 1 }, - { 0x2665, 0x2665, 0xaa, 1 }, - { 0x2666, 0x2666, 0xa9, 1 }, - { 0x2701, 0x2704, 0x21, 1 }, - { 0x2706, 0x2709, 0x26, 1 }, - { 0x270c, 0x2727, 0x2c, 1 }, - { 0x2729, 0x274b, 0x49, 1 }, - { 0x274d, 0x274d, 0x6d, 1 }, - { 0x274f, 0x2752, 0x6f, 1 }, - { 0x2756, 0x2756, 0x76, 1 }, - { 0x2758, 0x275e, 0x78, 1 }, - { 0x2761, 0x2767, 0xa1, 1 }, - { 0x2776, 0x2794, 0xb6, 1 }, - { 0x2798, 0x27af, 0xd8, 1 }, - { 0x27b1, 0x27be, 0xf1, 1 } -}; -#define zapfDingbatsUnicodeMapLen (sizeof(zapfDingbatsUnicodeMapRanges) / sizeof(UnicodeMapRange)) diff --git a/xpdf/xpdf/UnicodeTypeTable.cc b/xpdf/xpdf/UnicodeTypeTable.cc deleted file mode 100644 index d658e24cc..000000000 --- a/xpdf/xpdf/UnicodeTypeTable.cc +++ /dev/null @@ -1,949 +0,0 @@ -//======================================================================== -// -// UnicodeTypeTable.cc -// -// Copyright 2004 Glyph & Cog, LLC -// -//======================================================================== - -#include -#include "CharTypes.h" -#include "UnicodeTypeTable.h" - -struct UnicodeMapTableEntry { - const char *vector; - char type; -}; - -struct UnicodeCaseTableVector { - Unicode codes[256]; -}; - -static UnicodeMapTableEntry typeTable[256] = { - { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNLNNNNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL", 'X' }, - { NULL, 'L' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLNNNNNNNNNNNNNNLLNNNNNNNNNNNNNNLLLLLNNNNNNNNNLNNNNNNNNNNNNNNNNN", 'X' }, - { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLNNNNNNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRNRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' }, - { "RRRRNNNNNNNNNRNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNRNNNNNNNRRNNNNNNNRRNNNNNNNNNNRRRRRR", 'X' }, - { "RRRRRRRRRRRRRRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, - { NULL, 'N' }, - { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLNNNNLLLLLLLLLLLLLNNLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNLLLLLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLNNLLLLLLLNNNNN", 'X' }, - { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLNNNNNNNNNNNNNNNN", 'X' }, - { "NNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLNLNNNLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNNNNLLLLLLLNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNLNNNNNLNNLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLNLLNNNNNNNNNNNLLLLLLLNLNLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, - { "NNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLNNNNNLLLLLLNLLLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNNNLLLLLLLLLLLNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLNNNLLLLLLLLLLLLLNNN", 'X' }, - { "NNNNNNNNNNNNNNLRNNNNNNNNNNNNNNNNNNNNNNNNNNLRNLRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, - { "NNLNNNNLNNLLLLLLLLLLNLNNNLLLLLNNNNNNLNLNLNLLLLNLLLNLLLLLLLNNLLLLNNNNNLLLLLNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, - { NULL, 'N' }, - { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, - { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, - { NULL, 'N' }, - { NULL, 'N' }, - { NULL, 'N' }, - { NULL, 'L' }, - { NULL, 'N' }, - { NULL, 'N' }, - { NULL, 'N' }, - { NULL, 'N' }, - { NULL, 'N' }, - { NULL, 'N' }, - { NULL, 'N' }, - { "NNNNNLLLNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNNNNNNNLLLLLNNLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLL", 'X' }, - { NULL, 'L' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN", 'X' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { NULL, 'L' }, - { "LLLLLLLLLLLLLLLLLLLLLLLLRRRRRRNRRRRRRRRRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' }, - { NULL, 'R' }, - { "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' }, - { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' }, - { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLL", 'X' } -}; - -static UnicodeCaseTableVector caseTable00 = {{ - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, - 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, - 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x03bc, 0x00b6, 0x00b7, - 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, - 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, - 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, - 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00d7, - 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00df, - 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, - 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, - 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, - 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff -}}; -static UnicodeCaseTableVector caseTable01 = {{ - 0x0101, 0x0101, 0x0103, 0x0103, 0x0105, 0x0105, 0x0107, 0x0107, - 0x0109, 0x0109, 0x010b, 0x010b, 0x010d, 0x010d, 0x010f, 0x010f, - 0x0111, 0x0111, 0x0113, 0x0113, 0x0115, 0x0115, 0x0117, 0x0117, - 0x0119, 0x0119, 0x011b, 0x011b, 0x011d, 0x011d, 0x011f, 0x011f, - 0x0121, 0x0121, 0x0123, 0x0123, 0x0125, 0x0125, 0x0127, 0x0127, - 0x0129, 0x0129, 0x012b, 0x012b, 0x012d, 0x012d, 0x012f, 0x012f, - 0x0130, 0x0131, 0x0133, 0x0133, 0x0135, 0x0135, 0x0137, 0x0137, - 0x0138, 0x013a, 0x013a, 0x013c, 0x013c, 0x013e, 0x013e, 0x0140, - 0x0140, 0x0142, 0x0142, 0x0144, 0x0144, 0x0146, 0x0146, 0x0148, - 0x0148, 0x0149, 0x014b, 0x014b, 0x014d, 0x014d, 0x014f, 0x014f, - 0x0151, 0x0151, 0x0153, 0x0153, 0x0155, 0x0155, 0x0157, 0x0157, - 0x0159, 0x0159, 0x015b, 0x015b, 0x015d, 0x015d, 0x015f, 0x015f, - 0x0161, 0x0161, 0x0163, 0x0163, 0x0165, 0x0165, 0x0167, 0x0167, - 0x0169, 0x0169, 0x016b, 0x016b, 0x016d, 0x016d, 0x016f, 0x016f, - 0x0171, 0x0171, 0x0173, 0x0173, 0x0175, 0x0175, 0x0177, 0x0177, - 0x00ff, 0x017a, 0x017a, 0x017c, 0x017c, 0x017e, 0x017e, 0x0073, - 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, - 0x0188, 0x0256, 0x0257, 0x018c, 0x018c, 0x018d, 0x01dd, 0x0259, - 0x025b, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, - 0x0199, 0x0199, 0x019a, 0x019b, 0x026f, 0x0272, 0x019e, 0x0275, - 0x01a1, 0x01a1, 0x01a3, 0x01a3, 0x01a5, 0x01a5, 0x0280, 0x01a8, - 0x01a8, 0x0283, 0x01aa, 0x01ab, 0x01ad, 0x01ad, 0x0288, 0x01b0, - 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b4, 0x01b6, 0x01b6, 0x0292, - 0x01b9, 0x01b9, 0x01ba, 0x01bb, 0x01bd, 0x01bd, 0x01be, 0x01bf, - 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c6, 0x01c6, 0x01c6, 0x01c9, - 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01cc, 0x01ce, 0x01ce, 0x01d0, - 0x01d0, 0x01d2, 0x01d2, 0x01d4, 0x01d4, 0x01d6, 0x01d6, 0x01d8, - 0x01d8, 0x01da, 0x01da, 0x01dc, 0x01dc, 0x01dd, 0x01df, 0x01df, - 0x01e1, 0x01e1, 0x01e3, 0x01e3, 0x01e5, 0x01e5, 0x01e7, 0x01e7, - 0x01e9, 0x01e9, 0x01eb, 0x01eb, 0x01ed, 0x01ed, 0x01ef, 0x01ef, - 0x01f0, 0x01f3, 0x01f3, 0x01f3, 0x01f5, 0x01f5, 0x0195, 0x01bf, - 0x01f9, 0x01f9, 0x01fb, 0x01fb, 0x01fd, 0x01fd, 0x01ff, 0x01ff -}}; -static UnicodeCaseTableVector caseTable02 = {{ - 0x0201, 0x0201, 0x0203, 0x0203, 0x0205, 0x0205, 0x0207, 0x0207, - 0x0209, 0x0209, 0x020b, 0x020b, 0x020d, 0x020d, 0x020f, 0x020f, - 0x0211, 0x0211, 0x0213, 0x0213, 0x0215, 0x0215, 0x0217, 0x0217, - 0x0219, 0x0219, 0x021b, 0x021b, 0x021d, 0x021d, 0x021f, 0x021f, - 0x019e, 0x0221, 0x0223, 0x0223, 0x0225, 0x0225, 0x0227, 0x0227, - 0x0229, 0x0229, 0x022b, 0x022b, 0x022d, 0x022d, 0x022f, 0x022f, - 0x0231, 0x0231, 0x0233, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237, - 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, - 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, - 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f, - 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, - 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, - 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, - 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, - 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, - 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, - 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, - 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, - 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, - 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, - 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, - 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, - 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7, - 0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, - 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, - 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, - 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, - 0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df, - 0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7, - 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, - 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, - 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff -}}; -static UnicodeCaseTableVector caseTable03 = {{ - 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, - 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, - 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, - 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, - 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, - 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, - 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, - 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, - 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x03b9, 0x0346, 0x0347, - 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, - 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, - 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, - 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, - 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, - 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, - 0x0378, 0x0379, 0x037a, 0x037b, 0x037c, 0x037d, 0x037e, 0x037f, - 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x03ac, 0x0387, - 0x03ad, 0x03ae, 0x03af, 0x038b, 0x03cc, 0x038d, 0x03cd, 0x03ce, - 0x0390, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, - 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, - 0x03c0, 0x03c1, 0x03a2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, - 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03ac, 0x03ad, 0x03ae, 0x03af, - 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, - 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, - 0x03c0, 0x03c1, 0x03c3, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, - 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x03cf, - 0x03b2, 0x03b8, 0x03d2, 0x03d3, 0x03d4, 0x03c6, 0x03c0, 0x03d7, - 0x03d9, 0x03d9, 0x03db, 0x03db, 0x03dd, 0x03dd, 0x03df, 0x03df, - 0x03e1, 0x03e1, 0x03e3, 0x03e3, 0x03e5, 0x03e5, 0x03e7, 0x03e7, - 0x03e9, 0x03e9, 0x03eb, 0x03eb, 0x03ed, 0x03ed, 0x03ef, 0x03ef, - 0x03ba, 0x03c1, 0x03f2, 0x03f3, 0x03b8, 0x03b5, 0x03f6, 0x03f8, - 0x03f8, 0x03f2, 0x03fb, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff -}}; -static UnicodeCaseTableVector caseTable04 = {{ - 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, - 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, - 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, - 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, - 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, - 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, - 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, - 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, - 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, - 0x0469, 0x0469, 0x046b, 0x046b, 0x046d, 0x046d, 0x046f, 0x046f, - 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0477, 0x0477, - 0x0479, 0x0479, 0x047b, 0x047b, 0x047d, 0x047d, 0x047f, 0x047f, - 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, - 0x0488, 0x0489, 0x048b, 0x048b, 0x048d, 0x048d, 0x048f, 0x048f, - 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, - 0x0499, 0x0499, 0x049b, 0x049b, 0x049d, 0x049d, 0x049f, 0x049f, - 0x04a1, 0x04a1, 0x04a3, 0x04a3, 0x04a5, 0x04a5, 0x04a7, 0x04a7, - 0x04a9, 0x04a9, 0x04ab, 0x04ab, 0x04ad, 0x04ad, 0x04af, 0x04af, - 0x04b1, 0x04b1, 0x04b3, 0x04b3, 0x04b5, 0x04b5, 0x04b7, 0x04b7, - 0x04b9, 0x04b9, 0x04bb, 0x04bb, 0x04bd, 0x04bd, 0x04bf, 0x04bf, - 0x04c0, 0x04c2, 0x04c2, 0x04c4, 0x04c4, 0x04c6, 0x04c6, 0x04c8, - 0x04c8, 0x04ca, 0x04ca, 0x04cc, 0x04cc, 0x04ce, 0x04ce, 0x04cf, - 0x04d1, 0x04d1, 0x04d3, 0x04d3, 0x04d5, 0x04d5, 0x04d7, 0x04d7, - 0x04d9, 0x04d9, 0x04db, 0x04db, 0x04dd, 0x04dd, 0x04df, 0x04df, - 0x04e1, 0x04e1, 0x04e3, 0x04e3, 0x04e5, 0x04e5, 0x04e7, 0x04e7, - 0x04e9, 0x04e9, 0x04eb, 0x04eb, 0x04ed, 0x04ed, 0x04ef, 0x04ef, - 0x04f1, 0x04f1, 0x04f3, 0x04f3, 0x04f5, 0x04f5, 0x04f6, 0x04f7, - 0x04f9, 0x04f9, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff -}}; -static UnicodeCaseTableVector caseTable05 = {{ - 0x0501, 0x0501, 0x0503, 0x0503, 0x0505, 0x0505, 0x0507, 0x0507, - 0x0509, 0x0509, 0x050b, 0x050b, 0x050d, 0x050d, 0x050f, 0x050f, - 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, - 0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f, - 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, - 0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f, - 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, - 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f, - 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, - 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, - 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, - 0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f, - 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, - 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f, - 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, - 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, - 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, - 0x0588, 0x0589, 0x058a, 0x058b, 0x058c, 0x058d, 0x058e, 0x058f, - 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, - 0x0598, 0x0599, 0x059a, 0x059b, 0x059c, 0x059d, 0x059e, 0x059f, - 0x05a0, 0x05a1, 0x05a2, 0x05a3, 0x05a4, 0x05a5, 0x05a6, 0x05a7, - 0x05a8, 0x05a9, 0x05aa, 0x05ab, 0x05ac, 0x05ad, 0x05ae, 0x05af, - 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7, - 0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf, - 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05c4, 0x05c5, 0x05c6, 0x05c7, - 0x05c8, 0x05c9, 0x05ca, 0x05cb, 0x05cc, 0x05cd, 0x05ce, 0x05cf, - 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, - 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, - 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, - 0x05e8, 0x05e9, 0x05ea, 0x05eb, 0x05ec, 0x05ed, 0x05ee, 0x05ef, - 0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0x05f5, 0x05f6, 0x05f7, - 0x05f8, 0x05f9, 0x05fa, 0x05fb, 0x05fc, 0x05fd, 0x05fe, 0x05ff -}}; -static UnicodeCaseTableVector caseTable1e = {{ - 0x1e01, 0x1e01, 0x1e03, 0x1e03, 0x1e05, 0x1e05, 0x1e07, 0x1e07, - 0x1e09, 0x1e09, 0x1e0b, 0x1e0b, 0x1e0d, 0x1e0d, 0x1e0f, 0x1e0f, - 0x1e11, 0x1e11, 0x1e13, 0x1e13, 0x1e15, 0x1e15, 0x1e17, 0x1e17, - 0x1e19, 0x1e19, 0x1e1b, 0x1e1b, 0x1e1d, 0x1e1d, 0x1e1f, 0x1e1f, - 0x1e21, 0x1e21, 0x1e23, 0x1e23, 0x1e25, 0x1e25, 0x1e27, 0x1e27, - 0x1e29, 0x1e29, 0x1e2b, 0x1e2b, 0x1e2d, 0x1e2d, 0x1e2f, 0x1e2f, - 0x1e31, 0x1e31, 0x1e33, 0x1e33, 0x1e35, 0x1e35, 0x1e37, 0x1e37, - 0x1e39, 0x1e39, 0x1e3b, 0x1e3b, 0x1e3d, 0x1e3d, 0x1e3f, 0x1e3f, - 0x1e41, 0x1e41, 0x1e43, 0x1e43, 0x1e45, 0x1e45, 0x1e47, 0x1e47, - 0x1e49, 0x1e49, 0x1e4b, 0x1e4b, 0x1e4d, 0x1e4d, 0x1e4f, 0x1e4f, - 0x1e51, 0x1e51, 0x1e53, 0x1e53, 0x1e55, 0x1e55, 0x1e57, 0x1e57, - 0x1e59, 0x1e59, 0x1e5b, 0x1e5b, 0x1e5d, 0x1e5d, 0x1e5f, 0x1e5f, - 0x1e61, 0x1e61, 0x1e63, 0x1e63, 0x1e65, 0x1e65, 0x1e67, 0x1e67, - 0x1e69, 0x1e69, 0x1e6b, 0x1e6b, 0x1e6d, 0x1e6d, 0x1e6f, 0x1e6f, - 0x1e71, 0x1e71, 0x1e73, 0x1e73, 0x1e75, 0x1e75, 0x1e77, 0x1e77, - 0x1e79, 0x1e79, 0x1e7b, 0x1e7b, 0x1e7d, 0x1e7d, 0x1e7f, 0x1e7f, - 0x1e81, 0x1e81, 0x1e83, 0x1e83, 0x1e85, 0x1e85, 0x1e87, 0x1e87, - 0x1e89, 0x1e89, 0x1e8b, 0x1e8b, 0x1e8d, 0x1e8d, 0x1e8f, 0x1e8f, - 0x1e91, 0x1e91, 0x1e93, 0x1e93, 0x1e95, 0x1e95, 0x1e96, 0x1e97, - 0x1e98, 0x1e99, 0x1e9a, 0x1e61, 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f, - 0x1ea1, 0x1ea1, 0x1ea3, 0x1ea3, 0x1ea5, 0x1ea5, 0x1ea7, 0x1ea7, - 0x1ea9, 0x1ea9, 0x1eab, 0x1eab, 0x1ead, 0x1ead, 0x1eaf, 0x1eaf, - 0x1eb1, 0x1eb1, 0x1eb3, 0x1eb3, 0x1eb5, 0x1eb5, 0x1eb7, 0x1eb7, - 0x1eb9, 0x1eb9, 0x1ebb, 0x1ebb, 0x1ebd, 0x1ebd, 0x1ebf, 0x1ebf, - 0x1ec1, 0x1ec1, 0x1ec3, 0x1ec3, 0x1ec5, 0x1ec5, 0x1ec7, 0x1ec7, - 0x1ec9, 0x1ec9, 0x1ecb, 0x1ecb, 0x1ecd, 0x1ecd, 0x1ecf, 0x1ecf, - 0x1ed1, 0x1ed1, 0x1ed3, 0x1ed3, 0x1ed5, 0x1ed5, 0x1ed7, 0x1ed7, - 0x1ed9, 0x1ed9, 0x1edb, 0x1edb, 0x1edd, 0x1edd, 0x1edf, 0x1edf, - 0x1ee1, 0x1ee1, 0x1ee3, 0x1ee3, 0x1ee5, 0x1ee5, 0x1ee7, 0x1ee7, - 0x1ee9, 0x1ee9, 0x1eeb, 0x1eeb, 0x1eed, 0x1eed, 0x1eef, 0x1eef, - 0x1ef1, 0x1ef1, 0x1ef3, 0x1ef3, 0x1ef5, 0x1ef5, 0x1ef7, 0x1ef7, - 0x1ef9, 0x1ef9, 0x1efa, 0x1efb, 0x1efc, 0x1efd, 0x1efe, 0x1eff -}}; -static UnicodeCaseTableVector caseTable1f = {{ - 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, - 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, - 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f16, 0x1f17, - 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f1e, 0x1f1f, - 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, - 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, - 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, - 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, - 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f46, 0x1f47, - 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f4e, 0x1f4f, - 0x1f50, 0x1f51, 0x1f52, 0x1f53, 0x1f54, 0x1f55, 0x1f56, 0x1f57, - 0x1f58, 0x1f51, 0x1f5a, 0x1f53, 0x1f5c, 0x1f55, 0x1f5e, 0x1f57, - 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, - 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, - 0x1f70, 0x1f71, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1f76, 0x1f77, - 0x1f78, 0x1f79, 0x1f7a, 0x1f7b, 0x1f7c, 0x1f7d, 0x1f7e, 0x1f7f, - 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, - 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, - 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, - 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, - 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, - 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, - 0x1fb0, 0x1fb1, 0x1fb2, 0x1fb3, 0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7, - 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0x1fbd, 0x03b9, 0x1fbf, - 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, 0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7, - 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0x1fcd, 0x1fce, 0x1fcf, - 0x1fd0, 0x1fd1, 0x1fd2, 0x1fd3, 0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7, - 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf, - 0x1fe0, 0x1fe1, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe5, 0x1fe6, 0x1fe7, - 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1fed, 0x1fee, 0x1fef, - 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3, 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, - 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0x1ffd, 0x1ffe, 0x1fff -}}; -static UnicodeCaseTableVector caseTable21 = {{ - 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, - 0x2108, 0x2109, 0x210a, 0x210b, 0x210c, 0x210d, 0x210e, 0x210f, - 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, - 0x2118, 0x2119, 0x211a, 0x211b, 0x211c, 0x211d, 0x211e, 0x211f, - 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x03c9, 0x2127, - 0x2128, 0x2129, 0x006b, 0x00e5, 0x212c, 0x212d, 0x212e, 0x212f, - 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, - 0x2138, 0x2139, 0x213a, 0x213b, 0x213c, 0x213d, 0x213e, 0x213f, - 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, - 0x2148, 0x2149, 0x214a, 0x214b, 0x214c, 0x214d, 0x214e, 0x214f, - 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, - 0x2158, 0x2159, 0x215a, 0x215b, 0x215c, 0x215d, 0x215e, 0x215f, - 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, - 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, - 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, - 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, - 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, - 0x2188, 0x2189, 0x218a, 0x218b, 0x218c, 0x218d, 0x218e, 0x218f, - 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, - 0x2198, 0x2199, 0x219a, 0x219b, 0x219c, 0x219d, 0x219e, 0x219f, - 0x21a0, 0x21a1, 0x21a2, 0x21a3, 0x21a4, 0x21a5, 0x21a6, 0x21a7, - 0x21a8, 0x21a9, 0x21aa, 0x21ab, 0x21ac, 0x21ad, 0x21ae, 0x21af, - 0x21b0, 0x21b1, 0x21b2, 0x21b3, 0x21b4, 0x21b5, 0x21b6, 0x21b7, - 0x21b8, 0x21b9, 0x21ba, 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf, - 0x21c0, 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7, - 0x21c8, 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf, - 0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x21d5, 0x21d6, 0x21d7, - 0x21d8, 0x21d9, 0x21da, 0x21db, 0x21dc, 0x21dd, 0x21de, 0x21df, - 0x21e0, 0x21e1, 0x21e2, 0x21e3, 0x21e4, 0x21e5, 0x21e6, 0x21e7, - 0x21e8, 0x21e9, 0x21ea, 0x21eb, 0x21ec, 0x21ed, 0x21ee, 0x21ef, - 0x21f0, 0x21f1, 0x21f2, 0x21f3, 0x21f4, 0x21f5, 0x21f6, 0x21f7, - 0x21f8, 0x21f9, 0x21fa, 0x21fb, 0x21fc, 0x21fd, 0x21fe, 0x21ff -}}; -static UnicodeCaseTableVector caseTable24 = {{ - 0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407, - 0x2408, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x240e, 0x240f, - 0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417, - 0x2418, 0x2419, 0x241a, 0x241b, 0x241c, 0x241d, 0x241e, 0x241f, - 0x2420, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427, - 0x2428, 0x2429, 0x242a, 0x242b, 0x242c, 0x242d, 0x242e, 0x242f, - 0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437, - 0x2438, 0x2439, 0x243a, 0x243b, 0x243c, 0x243d, 0x243e, 0x243f, - 0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447, - 0x2448, 0x2449, 0x244a, 0x244b, 0x244c, 0x244d, 0x244e, 0x244f, - 0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457, - 0x2458, 0x2459, 0x245a, 0x245b, 0x245c, 0x245d, 0x245e, 0x245f, - 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, - 0x2468, 0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, - 0x2470, 0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0x2477, - 0x2478, 0x2479, 0x247a, 0x247b, 0x247c, 0x247d, 0x247e, 0x247f, - 0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487, - 0x2488, 0x2489, 0x248a, 0x248b, 0x248c, 0x248d, 0x248e, 0x248f, - 0x2490, 0x2491, 0x2492, 0x2493, 0x2494, 0x2495, 0x2496, 0x2497, - 0x2498, 0x2499, 0x249a, 0x249b, 0x249c, 0x249d, 0x249e, 0x249f, - 0x24a0, 0x24a1, 0x24a2, 0x24a3, 0x24a4, 0x24a5, 0x24a6, 0x24a7, - 0x24a8, 0x24a9, 0x24aa, 0x24ab, 0x24ac, 0x24ad, 0x24ae, 0x24af, - 0x24b0, 0x24b1, 0x24b2, 0x24b3, 0x24b4, 0x24b5, 0x24d0, 0x24d1, - 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9, - 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1, - 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9, - 0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, - 0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, - 0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, - 0x24e8, 0x24e9, 0x24ea, 0x24eb, 0x24ec, 0x24ed, 0x24ee, 0x24ef, - 0x24f0, 0x24f1, 0x24f2, 0x24f3, 0x24f4, 0x24f5, 0x24f6, 0x24f7, - 0x24f8, 0x24f9, 0x24fa, 0x24fb, 0x24fc, 0x24fd, 0x24fe, 0x24ff -}}; -static UnicodeCaseTableVector caseTableff = {{ - 0xff00, 0xff01, 0xff02, 0xff03, 0xff04, 0xff05, 0xff06, 0xff07, - 0xff08, 0xff09, 0xff0a, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f, - 0xff10, 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17, - 0xff18, 0xff19, 0xff1a, 0xff1b, 0xff1c, 0xff1d, 0xff1e, 0xff1f, - 0xff20, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, - 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, - 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, - 0xff58, 0xff59, 0xff5a, 0xff3b, 0xff3c, 0xff3d, 0xff3e, 0xff3f, - 0xff40, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, - 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, - 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, - 0xff58, 0xff59, 0xff5a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f, - 0xff60, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, - 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, - 0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77, - 0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f, - 0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87, - 0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f, - 0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97, - 0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f, - 0xffa0, 0xffa1, 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7, - 0xffa8, 0xffa9, 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf, - 0xffb0, 0xffb1, 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7, - 0xffb8, 0xffb9, 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf, - 0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, - 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf, - 0xffd0, 0xffd1, 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7, - 0xffd8, 0xffd9, 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf, - 0xffe0, 0xffe1, 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7, - 0xffe8, 0xffe9, 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef, - 0xfff0, 0xfff1, 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7, - 0xfff8, 0xfff9, 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff -}}; -static UnicodeCaseTableVector *caseTable[256] = { - &caseTable00, - &caseTable01, - &caseTable02, - &caseTable03, - &caseTable04, - &caseTable05, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - &caseTable1e, - &caseTable1f, - NULL, - &caseTable21, - NULL, - NULL, - &caseTable24, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - &caseTableff -}; - -static inline char getType(Unicode c) { - int i; - char type; - - if (c > 0xffff) { - type = 'X'; - } else { - i = (c >> 8) & 0xff; - if ((type = typeTable[i].type) == 'X') { - type = typeTable[i].vector[c & 0xff]; - } - } - return type; -} - -GBool unicodeTypeL(Unicode c) { - return getType(c) == 'L'; -} - -GBool unicodeTypeR(Unicode c) { - return getType(c) == 'R'; -} - -Unicode unicodeToUpper(Unicode c) { - int i; - - if (c > 0xffff) { - return c; - } - i = (c >> 8) & 0xff; - if (caseTable[i]) { - return caseTable[i]->codes[c & 0xff]; - } - return c; -} - diff --git a/xpdf/xpdf/UnicodeTypeTable.h b/xpdf/xpdf/UnicodeTypeTable.h deleted file mode 100644 index 7103dbddf..000000000 --- a/xpdf/xpdf/UnicodeTypeTable.h +++ /dev/null @@ -1,20 +0,0 @@ -//======================================================================== -// -// UnicodeTypeTable.h -// -// Copyright 2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef UNICODETYPETABLE_H -#define UNICODETYPETABLE_H - -#include "gtypes.h" - -extern GBool unicodeTypeL(Unicode c); - -extern GBool unicodeTypeR(Unicode c); - -extern Unicode unicodeToUpper(Unicode c); - -#endif diff --git a/xpdf/xpdf/XRef.cc b/xpdf/xpdf/XRef.cc deleted file mode 100644 index aac0e29c9..000000000 --- a/xpdf/xpdf/XRef.cc +++ /dev/null @@ -1,906 +0,0 @@ -//======================================================================== -// -// XRef.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include "gmem.h" -#include "Object.h" -#include "Stream.h" -#include "Lexer.h" -#include "Parser.h" -#include "Dict.h" -#include "Error.h" -#include "ErrorCodes.h" -#include "UGString.h" -#include "XRef.h" - -//------------------------------------------------------------------------ - -#define xrefSearchSize 1024 // read this many bytes at end of file - // to look for 'startxref' - -//------------------------------------------------------------------------ -// Permission bits -//------------------------------------------------------------------------ - -#define permPrint (1<<2) -#define permChange (1<<3) -#define permCopy (1<<4) -#define permNotes (1<<5) -#define defPermFlags 0xfffc - -//------------------------------------------------------------------------ -// ObjectStream -//------------------------------------------------------------------------ - -class ObjectStream { -public: - - // Create an object stream, using object number , - // generation 0. - ObjectStream(XRef *xref, int objStrNumA); - - ~ObjectStream(); - - // Return the object number of this object stream. - int getObjStrNum() { return objStrNum; } - - // Get the th object from this stream, which should be - // object number , generation 0. - Object *getObject(int objIdx, int objNum, Object *obj); - -private: - - int objStrNum; // object number of the object stream - int nObjects; // number of objects in the stream - Object *objs; // the objects (length = nObjects) - int *objNums; // the object numbers (length = nObjects) -}; - -ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { - Stream *str; - Parser *parser; - int *offsets; - Object objStr, obj1, obj2; - int first, i; - - objStrNum = objStrNumA; - nObjects = 0; - objs = NULL; - objNums = NULL; - - if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) { - goto err1; - } - - if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) { - obj1.free(); - goto err1; - } - nObjects = obj1.getInt(); - obj1.free(); - if (nObjects <= 0) { - goto err1; - } - - if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) { - obj1.free(); - goto err1; - } - first = obj1.getInt(); - obj1.free(); - if (first < 0) { - goto err1; - } - - objs = new Object[nObjects]; - objNums = (int *)gmallocn(nObjects, sizeof(int)); - offsets = (int *)gmallocn(nObjects, sizeof(int)); - - // parse the header: object numbers and offsets - objStr.streamReset(); - obj1.initNull(); - str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first); - parser = new Parser(xref, new Lexer(xref, str)); - for (i = 0; i < nObjects; ++i) { - parser->getObj(&obj1); - parser->getObj(&obj2); - if (!obj1.isInt() || !obj2.isInt()) { - obj1.free(); - obj2.free(); - delete parser; - gfree(offsets); - goto err1; - } - objNums[i] = obj1.getInt(); - offsets[i] = obj2.getInt(); - obj1.free(); - obj2.free(); - if (objNums[i] < 0 || offsets[i] < 0 || - (i > 0 && offsets[i] < offsets[i-1])) { - delete parser; - gfree(offsets); - goto err1; - } - } - while (str->getChar() != EOF) ; - delete parser; - - // skip to the first object - this shouldn't be necessary because - // the First key is supposed to be equal to offsets[0], but just in - // case... - for (i = first; i < offsets[0]; ++i) { - objStr.getStream()->getChar(); - } - - // parse the objects - for (i = 0; i < nObjects; ++i) { - obj1.initNull(); - if (i == nObjects - 1) { - str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0); - } else { - str = new EmbedStream(objStr.getStream(), &obj1, gTrue, - offsets[i+1] - offsets[i]); - } - parser = new Parser(xref, new Lexer(xref, str)); - parser->getObj(&objs[i]); - while (str->getChar() != EOF) ; - delete parser; - } - - gfree(offsets); - - err1: - objStr.free(); - return; -} - -ObjectStream::~ObjectStream() { - int i; - - if (objs) { - for (i = 0; i < nObjects; ++i) { - objs[i].free(); - } - delete[] objs; - } - gfree(objNums); -} - -Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { - if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) { - return obj->initNull(); - } - return objs[objIdx].copy(obj); -} - -//------------------------------------------------------------------------ -// XRef -//------------------------------------------------------------------------ - -XRef::XRef(BaseStream *strA) { - Guint pos; - Object obj; - - ok = gTrue; - errCode = errNone; - size = 0; - entries = NULL; - streamEnds = NULL; - streamEndsLen = 0; - objStr = NULL; - - encrypted = gFalse; - permFlags = defPermFlags; - ownerPasswordOk = gFalse; - - // read the trailer - str = strA; - start = str->getStart(); - pos = getStartXref(); - - // if there was a problem with the 'startxref' position, try to - // reconstruct the xref table - if (pos == 0) { - if (!(ok = constructXRef())) { - errCode = errDamaged; - return; - } - - // read the xref table - } else { - while (readXRef(&pos)) ; - - // if there was a problem with the xref table, - // try to reconstruct it - if (!ok) { - if (!(ok = constructXRef())) { - errCode = errDamaged; - return; - } - } - } - - // get the root dictionary (catalog) object - trailerDict.dictLookupNF("Root", &obj); - if (obj.isRef()) { - rootNum = obj.getRefNum(); - rootGen = obj.getRefGen(); - obj.free(); - } else { - obj.free(); - if (!(ok = constructXRef())) { - errCode = errDamaged; - return; - } - } - - // now set the trailer dictionary's xref pointer so we can fetch - // indirect objects from it - trailerDict.getDict()->setXRef(this); -} - -XRef::~XRef() { - gfree(entries); - trailerDict.free(); - if (streamEnds) { - gfree(streamEnds); - } - if (objStr) { - delete objStr; - } -} - -// Read the 'startxref' position. -Guint XRef::getStartXref() { - char buf[xrefSearchSize+1]; - char *p; - int c, n, i; - - // read last xrefSearchSize bytes - str->setPos(xrefSearchSize, -1); - for (n = 0; n < xrefSearchSize; ++n) { - if ((c = str->getChar()) == EOF) { - break; - } - buf[n] = c; - } - buf[n] = '\0'; - - // find startxref - for (i = n - 9; i >= 0; --i) { - if (!strncmp(&buf[i], "startxref", 9)) { - break; - } - } - if (i < 0) { - return 0; - } - for (p = &buf[i+9]; isspace(*p); ++p) ; - lastXRefPos = strToUnsigned(p); - - return lastXRefPos; -} - -// Read one xref table section. Also reads the associated trailer -// dictionary, and returns the prev pointer (if any). -GBool XRef::readXRef(Guint *pos) { - Parser *parser; - Object obj; - GBool more; - - // start up a parser, parse one token - obj.initNull(); - parser = new Parser(NULL, - new Lexer(NULL, - str->makeSubStream(start + *pos, gFalse, 0, &obj))); - parser->getObj(&obj); - - // parse an old-style xref table - if (obj.isCmd("xref")) { - obj.free(); - more = readXRefTable(parser, pos); - - // parse an xref stream - } else if (obj.isInt()) { - obj.free(); - if (!parser->getObj(&obj)->isInt()) { - goto err1; - } - obj.free(); - if (!parser->getObj(&obj)->isCmd("obj")) { - goto err1; - } - obj.free(); - if (!parser->getObj(&obj)->isStream()) { - goto err1; - } - more = readXRefStream(obj.getStream(), pos); - obj.free(); - - } else { - goto err1; - } - - delete parser; - return more; - - err1: - obj.free(); - delete parser; - ok = gFalse; - return gFalse; -} - -GBool XRef::readXRefTable(Parser *parser, Guint *pos) { - XRefEntry entry; - GBool more; - Object obj, obj2; - Guint pos2; - int first, n, newSize, i; - - while (1) { - parser->getObj(&obj); - if (obj.isCmd("trailer")) { - obj.free(); - break; - } - if (!obj.isInt()) { - goto err1; - } - first = obj.getInt(); - obj.free(); - if (!parser->getObj(&obj)->isInt()) { - goto err1; - } - n = obj.getInt(); - obj.free(); - if (first < 0 || n < 0 || first + n < 0) { - goto err1; - } - if (first + n > size) { - for (newSize = size ? 2 * size : 1024; - first + n > newSize && newSize > 0; - newSize <<= 1) ; - if (newSize < 0) { - goto err1; - } - entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); - for (i = size; i < newSize; ++i) { - entries[i].offset = 0xffffffff; - entries[i].type = xrefEntryFree; - } - size = newSize; - } - for (i = first; i < first + n; ++i) { - if (!parser->getObj(&obj)->isInt()) { - goto err1; - } - entry.offset = (Guint)obj.getInt(); - obj.free(); - if (!parser->getObj(&obj)->isInt()) { - goto err1; - } - entry.gen = obj.getInt(); - obj.free(); - parser->getObj(&obj); - if (obj.isCmd("n")) { - entry.type = xrefEntryUncompressed; - } else if (obj.isCmd("f")) { - entry.type = xrefEntryFree; - } else { - goto err1; - } - obj.free(); - if (entries[i].offset == 0xffffffff) { - entries[i] = entry; - // PDF files of patents from the IBM Intellectual Property - // Network have a bug: the xref table claims to start at 1 - // instead of 0. - if (i == 1 && first == 1 && - entries[1].offset == 0 && entries[1].gen == 65535 && - entries[1].type == xrefEntryFree) { - i = first = 0; - entries[0] = entries[1]; - entries[1].offset = 0xffffffff; - } - } - } - } - - // read the trailer dictionary - if (!parser->getObj(&obj)->isDict()) { - goto err1; - } - - // get the 'Prev' pointer - obj.getDict()->lookupNF("Prev", &obj2); - if (obj2.isInt()) { - *pos = (Guint)obj2.getInt(); - more = gTrue; - } else if (obj2.isRef()) { - // certain buggy PDF generators generate "/Prev NNN 0 R" instead - // of "/Prev NNN" - *pos = (Guint)obj2.getRefNum(); - more = gTrue; - } else { - more = gFalse; - } - obj2.free(); - - // save the first trailer dictionary - if (trailerDict.isNone()) { - obj.copy(&trailerDict); - } - - // check for an 'XRefStm' key - if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) { - pos2 = (Guint)obj2.getInt(); - readXRef(&pos2); - if (!ok) { - obj2.free(); - goto err1; - } - } - obj2.free(); - - obj.free(); - return more; - - err1: - obj.free(); - ok = gFalse; - return gFalse; -} - -GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { - Dict *dict; - int w[3]; - GBool more; - Object obj, obj2, idx; - int newSize, first, n, i; - - dict = xrefStr->getDict(); - - if (!dict->lookupNF("Size", &obj)->isInt()) { - goto err1; - } - newSize = obj.getInt(); - obj.free(); - if (newSize < 0) { - goto err1; - } - if (newSize > size) { - entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); - for (i = size; i < newSize; ++i) { - entries[i].offset = 0xffffffff; - entries[i].type = xrefEntryFree; - } - size = newSize; - } - - if (!dict->lookupNF("W", &obj)->isArray() || - obj.arrayGetLength() < 3) { - goto err1; - } - for (i = 0; i < 3; ++i) { - if (!obj.arrayGet(i, &obj2)->isInt()) { - obj2.free(); - goto err1; - } - w[i] = obj2.getInt(); - obj2.free(); - if (w[i] < 0 || w[i] > 4) { - goto err1; - } - } - obj.free(); - - xrefStr->reset(); - dict->lookupNF("Index", &idx); - if (idx.isArray()) { - for (i = 0; i+1 < idx.arrayGetLength(); i += 2) { - if (!idx.arrayGet(i, &obj)->isInt()) { - idx.free(); - goto err1; - } - first = obj.getInt(); - obj.free(); - if (!idx.arrayGet(i+1, &obj)->isInt()) { - idx.free(); - goto err1; - } - n = obj.getInt(); - obj.free(); - if (first < 0 || n < 0 || - !readXRefStreamSection(xrefStr, w, first, n)) { - idx.free(); - goto err0; - } - } - } else { - if (!readXRefStreamSection(xrefStr, w, 0, newSize)) { - idx.free(); - goto err0; - } - } - idx.free(); - - dict->lookupNF("Prev", &obj); - if (obj.isInt()) { - *pos = (Guint)obj.getInt(); - more = gTrue; - } else { - more = gFalse; - } - obj.free(); - if (trailerDict.isNone()) { - trailerDict.initDict(dict); - } - - return more; - - err1: - obj.free(); - err0: - ok = gFalse; - return gFalse; -} - -GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { - Guint offset; - int type, gen, c, newSize, i, j; - - if (first + n < 0) { - return gFalse; - } - if (first + n > size) { - for (newSize = size ? 2 * size : 1024; - first + n > newSize && newSize > 0; - newSize <<= 1) ; - if (newSize < 0) { - return gFalse; - } - entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); - for (i = size; i < newSize; ++i) { - entries[i].offset = 0xffffffff; - entries[i].type = xrefEntryFree; - } - size = newSize; - } - for (i = first; i < first + n; ++i) { - if (w[0] == 0) { - type = 1; - } else { - for (type = 0, j = 0; j < w[0]; ++j) { - if ((c = xrefStr->getChar()) == EOF) { - return gFalse; - } - type = (type << 8) + c; - } - } - for (offset = 0, j = 0; j < w[1]; ++j) { - if ((c = xrefStr->getChar()) == EOF) { - return gFalse; - } - offset = (offset << 8) + c; - } - for (gen = 0, j = 0; j < w[2]; ++j) { - if ((c = xrefStr->getChar()) == EOF) { - return gFalse; - } - gen = (gen << 8) + c; - } - if (entries[i].offset == 0xffffffff) { - switch (type) { - case 0: - entries[i].offset = offset; - entries[i].gen = gen; - entries[i].type = xrefEntryFree; - break; - case 1: - entries[i].offset = offset; - entries[i].gen = gen; - entries[i].type = xrefEntryUncompressed; - break; - case 2: - entries[i].offset = offset; - entries[i].gen = gen; - entries[i].type = xrefEntryCompressed; - break; - default: - return gFalse; - } - } - } - - return gTrue; -} - -// Attempt to construct an xref table for a damaged file. -GBool XRef::constructXRef() { - Parser *parser; - Object newTrailerDict, obj; - char buf[256]; - Guint pos; - int num, gen; - int newSize; - int streamEndsSize; - char *p; - int i; - GBool gotRoot; - - gfree(entries); - size = 0; - entries = NULL; - - error(0, "PDF file is damaged - attempting to reconstruct xref table..."); - gotRoot = gFalse; - streamEndsLen = streamEndsSize = 0; - - str->reset(); - while (1) { - pos = str->getPos(); - if (!str->getLine(buf, 256)) { - break; - } - p = buf; - - // got trailer dictionary - if (!strncmp(p, "trailer", 7)) { - obj.initNull(); - parser = new Parser(NULL, - new Lexer(NULL, - str->makeSubStream(pos + 7, gFalse, 0, &obj))); - parser->getObj(&newTrailerDict); - if (newTrailerDict.isDict()) { - newTrailerDict.dictLookupNF("Root", &obj); - if (obj.isRef()) { - rootNum = obj.getRefNum(); - rootGen = obj.getRefGen(); - if (!trailerDict.isNone()) { - trailerDict.free(); - } - newTrailerDict.copy(&trailerDict); - gotRoot = gTrue; - } - obj.free(); - } - newTrailerDict.free(); - delete parser; - - // look for object - } else if (isdigit(*p)) { - num = atoi(p); - if (num > 0) { - do { - ++p; - } while (*p && isdigit(*p)); - if (isspace(*p)) { - do { - ++p; - } while (*p && isspace(*p)); - if (isdigit(*p)) { - gen = atoi(p); - do { - ++p; - } while (*p && isdigit(*p)); - if (isspace(*p)) { - do { - ++p; - } while (*p && isspace(*p)); - if (!strncmp(p, "obj", 3)) { - if (num >= size) { - newSize = (num + 1 + 255) & ~255; - if (newSize < 0) { - error(-1, "Bad object number"); - return gFalse; - } - entries = (XRefEntry *) - greallocn(entries, newSize, sizeof(XRefEntry)); - for (i = size; i < newSize; ++i) { - entries[i].offset = 0xffffffff; - entries[i].type = xrefEntryFree; - } - size = newSize; - } - if (entries[num].type == xrefEntryFree || - gen >= entries[num].gen) { - entries[num].offset = pos - start; - entries[num].gen = gen; - entries[num].type = xrefEntryUncompressed; - } - } - } - } - } - } - - } else if (!strncmp(p, "endstream", 9)) { - if (streamEndsLen == streamEndsSize) { - streamEndsSize += 64; - streamEnds = (Guint *)greallocn(streamEnds, - streamEndsSize, sizeof(int)); - } - streamEnds[streamEndsLen++] = pos; - } - } - - if (gotRoot) - return gTrue; - - error(-1, "Couldn't find trailer dictionary"); - return gFalse; -} - -void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA, - Guchar *fileKeyA, int keyLengthA, int encVersionA) { - int i; - - encrypted = gTrue; - permFlags = permFlagsA; - ownerPasswordOk = ownerPasswordOkA; - if (keyLengthA <= 16) { - keyLength = keyLengthA; - } else { - keyLength = 16; - } - for (i = 0; i < keyLength; ++i) { - fileKey[i] = fileKeyA[i]; - } - encVersion = encVersionA; -} - -GBool XRef::okToPrint(GBool ignoreOwnerPW) { - return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint); -} - -GBool XRef::okToChange(GBool ignoreOwnerPW) { - return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange); -} - -GBool XRef::okToCopy(GBool ignoreOwnerPW) { - return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy); -} - -GBool XRef::okToAddNotes(GBool ignoreOwnerPW) { - return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes); -} - -Object *XRef::fetch(int num, int gen, Object *obj) { - XRefEntry *e; - Parser *parser; - Object obj1, obj2, obj3; - - // check for bogus ref - this can happen in corrupted PDF files - if (num < 0 || num >= size) { - goto err; - } - - e = &entries[num]; - switch (e->type) { - - case xrefEntryUncompressed: - if (e->gen != gen) { - goto err; - } - obj1.initNull(); - parser = new Parser(this, - new Lexer(this, - str->makeSubStream(start + e->offset, gFalse, 0, &obj1))); - parser->getObj(&obj1); - parser->getObj(&obj2); - parser->getObj(&obj3); - if (!obj1.isInt() || obj1.getInt() != num || - !obj2.isInt() || obj2.getInt() != gen || - !obj3.isCmd("obj")) { - obj1.free(); - obj2.free(); - obj3.free(); - delete parser; - goto err; - } - parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, - num, gen); - obj1.free(); - obj2.free(); - obj3.free(); - delete parser; - break; - - case xrefEntryCompressed: - if (gen != 0) { - goto err; - } - if (!objStr || objStr->getObjStrNum() != (int)e->offset) { - if (objStr) { - delete objStr; - } - objStr = new ObjectStream(this, e->offset); - } - objStr->getObject(e->gen, num, obj); - break; - - default: - goto err; - } - - return obj; - - err: - return obj->initNull(); -} - -Object *XRef::getDocInfo(Object *obj) { - return trailerDict.dictLookup("Info", obj); -} - -// Added for the pdftex project. -Object *XRef::getDocInfoNF(Object *obj) { - return trailerDict.dictLookupNF("Info", obj); -} - -GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) { - int a, b, m; - - if (streamEndsLen == 0 || - streamStart > streamEnds[streamEndsLen - 1]) { - return gFalse; - } - - a = -1; - b = streamEndsLen - 1; - // invariant: streamEnds[a] < streamStart <= streamEnds[b] - while (b - a > 1) { - m = (a + b) / 2; - if (streamStart <= streamEnds[m]) { - b = m; - } else { - a = m; - } - } - *streamEnd = streamEnds[b]; - return gTrue; -} - -int XRef::getNumEntry(int offset) const -{ - int res = -1; - int resOffset = -1; - XRefEntry e; - for (int i = 0; i < size; ++i) - { - e = entries[i]; - if (e.offset < offset && e.offset > resOffset) - { - res = i; - resOffset = e.offset; - } - } - return res; -} - -Guint XRef::strToUnsigned(char *s) { - Guint x; - char *p; - int i; - - x = 0; - for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) { - x = 10 * x + (*p - '0'); - } - return x; -} diff --git a/xpdf/xpdf/XRef.h b/xpdf/xpdf/XRef.h deleted file mode 100644 index 633141aa0..000000000 --- a/xpdf/xpdf/XRef.h +++ /dev/null @@ -1,134 +0,0 @@ -//======================================================================== -// -// XRef.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef XREF_H -#define XREF_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "Object.h" - -class Dict; -class Stream; -class Parser; -class ObjectStream; - -//------------------------------------------------------------------------ -// XRef -//------------------------------------------------------------------------ - -enum XRefEntryType { - xrefEntryFree, - xrefEntryUncompressed, - xrefEntryCompressed -}; - -struct XRefEntry { - Guint offset; - int gen; - XRefEntryType type; -}; - -class XRef { -public: - - // Constructor. Read xref table from stream. - XRef(BaseStream *strA); - - // Destructor. - ~XRef(); - - // Is xref table valid? - GBool isOk() { return ok; } - - // Get the error code (if isOk() returns false). - int getErrorCode() { return errCode; } - - // Set the encryption parameters. - void setEncryption(int permFlagsA, GBool ownerPasswordOkA, - Guchar *fileKeyA, int keyLengthA, int encVersionA); - - // Is the file encrypted? - GBool isEncrypted() { return encrypted; } - - // Check various permissions. - GBool okToPrint(GBool ignoreOwnerPW = gFalse); - GBool okToChange(GBool ignoreOwnerPW = gFalse); - GBool okToCopy(GBool ignoreOwnerPW = gFalse); - GBool okToAddNotes(GBool ignoreOwnerPW = gFalse); - - // Get catalog object. - Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); } - - // Fetch an indirect reference. - Object *fetch(int num, int gen, Object *obj); - - // Return the document's Info dictionary (if any). - Object *getDocInfo(Object *obj); - Object *getDocInfoNF(Object *obj); - - // Return the number of objects in the xref table. - int getNumObjects() { return size; } - - // Return the offset of the last xref table. - Guint getLastXRefPos() { return lastXRefPos; } - - // Return the catalog object reference. - int getRootNum() { return rootNum; } - int getRootGen() { return rootGen; } - - // Get end position for a stream in a damaged file. - // Returns false if unknown or file is not damaged. - GBool getStreamEnd(Guint streamStart, Guint *streamEnd); - - // Retuns the entry that belongs to the offset - int getNumEntry(int offset) const; - - // Direct access. - int getSize() { return size; } - XRefEntry *getEntry(int i) { return &entries[i]; } - Object *getTrailerDict() { return &trailerDict; } - -private: - - BaseStream *str; // input stream - Guint start; // offset in file (to allow for garbage - // at beginning of file) - XRefEntry *entries; // xref entries - int size; // size of array - int rootNum, rootGen; // catalog dict - GBool ok; // true if xref table is valid - int errCode; // error code (if is false) - Object trailerDict; // trailer dictionary - Guint lastXRefPos; // offset of last xref table - Guint *streamEnds; // 'endstream' positions - only used in - // damaged files - int streamEndsLen; // number of valid entries in streamEnds - ObjectStream *objStr; // cached object stream - GBool encrypted; // true if file is encrypted - int permFlags; // permission bits - GBool ownerPasswordOk; // true if owner password is correct - Guchar fileKey[16]; // file decryption key - int keyLength; // length of key, in bytes - int encVersion; // encryption algorithm - - Guint getStartXref(); - GBool readXRef(Guint *pos); - GBool readXRefTable(Parser *parser, Guint *pos); - GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n); - GBool readXRefStream(Stream *xrefStr, Guint *pos); - GBool constructXRef(); - Guint strToUnsigned(char *s); -}; - -#endif diff --git a/xpdf/xpdf/xpdf_config.h b/xpdf/xpdf/xpdf_config.h deleted file mode 100644 index bf6baf4bf..000000000 --- a/xpdf/xpdf/xpdf_config.h +++ /dev/null @@ -1,110 +0,0 @@ -//======================================================================== -// -// config.h -// -// Copyright 1996-2004 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef CONFIG_H -#define CONFIG_H - -//------------------------------------------------------------------------ -// version -//------------------------------------------------------------------------ - -// xpdf version -#define xpdfVersion "3.00" -#define xpdfVersionNum 3.00 -#define xpdfMajorVersion 3 -#define xpdfMinorVersion 0 -#define xpdfMajorVersionStr "3" -#define xpdfMinorVersionStr "0" - -// supported PDF version -#define supportedPDFVersionStr "1.5" -#define supportedPDFVersionNum 1.5 - -// copyright notice -#define xpdfCopyright "Copyright 1996-2004 Glyph & Cog, LLC" - -// Windows resource file stuff -#define winxpdfVersion "WinXpdf 3.00" -#define xpdfCopyrightAmp "Copyright 1996-2004 Glyph && Cog, LLC" - -//------------------------------------------------------------------------ -// paper size -//------------------------------------------------------------------------ - -// default paper size (in points) for PostScript output -#ifdef A4_PAPER -#define defPaperWidth 595 // ISO A4 (210x297 mm) -#define defPaperHeight 842 -#else -#define defPaperWidth 612 // American letter (8.5x11") -#define defPaperHeight 792 -#endif - -//------------------------------------------------------------------------ -// config file (xpdfrc) path -//------------------------------------------------------------------------ - -// user config file name, relative to the user's home directory -#if defined(VMS) || (defined(WIN32) && !defined(__CYGWIN32__)) -#define xpdfUserConfigFile "xpdfrc" -#else -#define xpdfUserConfigFile ".xpdfrc" -#endif - -// system config file name (set via the configure script) -#ifdef SYSTEM_XPDFRC -#define xpdfSysConfigFile SYSTEM_XPDFRC -#else -// under Windows, we get the directory with the executable and then -// append this file name -#define xpdfSysConfigFile "xpdfrc" -#endif - -//------------------------------------------------------------------------ -// X-related constants -//------------------------------------------------------------------------ - -// default maximum size of color cube to allocate -#define defaultRGBCube 5 - -// number of fonts (combined t1lib, FreeType, X server) to cache -#define xOutFontCacheSize 64 - -// number of Type 3 fonts to cache -#define xOutT3FontCacheSize 8 - -//------------------------------------------------------------------------ -// popen -//------------------------------------------------------------------------ - -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define popen _popen -#define pclose _pclose -#endif - -#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(MACOS) -#define POPEN_READ_MODE "rb" -#else -#define POPEN_READ_MODE "r" -#endif - -//------------------------------------------------------------------------ -// Win32 stuff -//------------------------------------------------------------------------ - -#ifdef CDECL -#undef CDECL -#endif - -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define CDECL __cdecl -#else -#define CDECL -#endif - -#endif From 6d74a16bcae396996a90b3ece2a81330a68a66bb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 5 Mar 2006 22:25:40 +0000 Subject: [PATCH 219/245] we no longer have xpdf svn path=/trunk/KDE/kdegraphics/kpdf/; revision=516090 --- AUTHORS | 2 -- 1 file changed, 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index e0aae2a72..55b672e33 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,5 +2,3 @@ Albert Astals Cid Enrico Ros Wilco Greven Christophe Devriese - -XPdf is written by Glyph & Cog, LLC From d81d2ccde832763d2e13d4811765c5c2844c9df6 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 5 Mar 2006 22:28:55 +0000 Subject: [PATCH 220/245] as said no more xpdf svn path=/trunk/KDE/kdegraphics/kpdf/; revision=516091 --- shell/Makefile.am | 2 +- shell/main.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/shell/Makefile.am b/shell/Makefile.am index e8416ef1d..b0e0857fa 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -1,4 +1,4 @@ -INCLUDES = -I$(srcdir)/xpdf -I$(srcdir)/xpdf/goo -I$(top_builddir)/kpdf $(all_includes) $(FREETYPE_CFLAGS) +INCLUDES = -I$(top_builddir)/kpdf $(all_includes) METASOURCES = AUTO diff --git a/shell/main.cpp b/shell/main.cpp index 2cfbdbf89..26b91316c 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -19,7 +19,7 @@ #include static const char description[] = -I18N_NOOP("kpdf, a kde pdf viewer based on xpdf"); +I18N_NOOP("kpdf, a kde pdf viewer based on poppler"); static const char version[] = "0.5"; @@ -45,7 +45,6 @@ int main(int argc, char** argv) about.addAuthor("Albert Astals Cid", I18N_NOOP("Current mantainer"), "astals11@terra.es"); about.addAuthor("Enrico Ros", 0, "eros.kde@email.it"); - about.addCredit("Derek Noonburg", I18N_NOOP("Xpdf author"), 0, "http://www.foolabs.com/xpdf/"); about.addCredit("Marco Martin", I18N_NOOP("Icon"), 0, "m4rt@libero.it"); KCmdLineArgs::init(argc, argv, &about); From 389fe486666a79d8c58cd8f4f47fec27477c97b7 Mon Sep 17 00:00:00 2001 From: Fabio Pedretti Date: Fri, 10 Mar 2006 16:51:09 +0000 Subject: [PATCH 221/245] Losslessly optimize file size of *.png files in /trunk/KDE/kdegraphics with optipng -o5 and advdef -z -4. Losslessly optimize file size of *.svgz files in /trunk/KDE/kdegraphics with advdef -z -4. For more info see bug 122897. svn path=/trunk/KDE/kdegraphics/kpdf/; revision=517323 --- README.internals.png | Bin 43015 -> 33807 bytes doc/configure.png | Bin 11240 -> 10543 bytes hi128-app-kpdf.png | Bin 14500 -> 13702 bytes hi16-app-kpdf.png | Bin 766 -> 766 bytes hi22-app-kpdf.png | Bin 1184 -> 1148 bytes hi32-app-kpdf.png | Bin 2101 -> 2031 bytes hi48-app-kpdf.png | Bin 3452 -> 3285 bytes hi64-app-kpdf.png | Bin 5842 -> 5511 bytes hisc-app-kpdf.svgz | Bin 11018 -> 9787 bytes 9 files changed, 0 insertions(+), 0 deletions(-) diff --git a/README.internals.png b/README.internals.png index 9215317328c104a1cfed0a43f930db62f6fc2ab6..8a9769f1b7205555bde44b158f648bdef972fe68 100644 GIT binary patch literal 33807 zcmZ^~WmMe16F1rxcXxMpcZcFo+*#aRi?zt&?p~z07H9Fr-QC^Y_44~a&pG$Lxi2;+ zXEI49lljg}KFNlwD9IqfeSxGT< zujSKh7;VgjPXC^Q%PA&h7iJ6x`<(@0#q)e%)Zm={w1=5;c&}|j_y&>05_y9d`Nm~`G+hc3 zI;h*2HLa<4BY!I*kUf9w`=fHDViY10(h(w2K3p}sMJ+G4qz`G?SPkp`^x-mo>OvdQ z^7=R~;%7&Ee+YZ%x*v=b%TRPAc@_y3!%O@Q+xm;v1G)JQPXSd#>I<=-qvKWpq(oJv z#E zkBj-38-;#q>!#@mOdv$#48v~9TQcxVusG};tleqz7qx2=j)xdO_xz@&rv3v%kqF)D zc7*-@4|}`%T^rV@XKyc~O}#UA?N-~ZY7S-s68#ao^YsG(pKPWApJGY4KY*pwt0TBt<|dOa)ec~u7*a3_51L$n6-EE z>T=Vo1P)HB|2Ve=vje45CSTIqV?y5Ij%jY&gMHxN*O#v==c{Jf(DL(Iri}}qthW6az z-NK;^ljfjrZf`d6<_ti8I$Ny6s>T&NVIqzQZkKH&$lj|4x_TFfQI7qvB$XLxqM*J z;D@P&k!ceZ4yV;evop6+U1R5Ncwbwpo+W=zZP`jaZm!ikCKV)u@uFO-3u#+_XF{wfSV zDYP@<4+TcohKnp62cZ8%S>RVO(uUgWSOnI^&-K@NtE=d|=P&CyJ?{Ku6Co>GE9Yf~L{k`2EJS(@u9>Pe(6`qf1d5%H>I8io-0%*zI|_-|{4_ zy`{{=aSY~{IUdZe5%TbDaR-%GEN1LQr{CljtG#so3IyZB9RvcYLjQ zqcw#rH&RaNq8Fu2jWK^^Q#SI!d(Wk|qAT?_dvO)hb5Z+jjZ2vC@gjfXj(c0d-vT@# z7H#W$|1yhXo+Iqjf^CZ%#1++D@)tl_5}>sbPPSBi3~+imJno)&)~WDQg}4GIo+)e? zIdzgL&0>kHHrV7$+)~crpI3r)J9389CmM2Fxj`lW{#^ntc?n7sOJ1u?&HuBLR-&XN zEhtRf`x&yFda|a@>6BU|=u(FR4HAz!Vw@~JI#L!n%TX7$^QOxz=(A4C=D%;VcghUM zPstP93MWv`b7!(!dCG=KhG8snrZqq|qCAS@WAxv@dskbMh&TQLsa`F+>ju(X`E-{F z^%nBT;!{hS)zw>_w;;=zf%>MV7zm-xb>CRbw8VUKBDur|_uEAmjdrIY?kk_iDZl^2 z@OL|PF#A(&yY(n0IvIl=e>+(0SE?7G@clW4Pib%{>Un)iA$Q#D?ofc2@;IWHEc37Z zx2yb(eKFa-0w8ex_v5>&l4Gw(q%Y!?@~GRAz9|Nu-T9Zfr<;*!%b3IBu|FrCC+%i3 z^oi0lY}wyw#dN&QpBQXm{_Z8u1dRoImYEyxZ%)pP&-q;3nZTBnkWjH#FFkj-)B(f2&UKkD6(BsOS{x@<0E5X|zAufPfjUulF+3@N&TYj5tW9ta2|VblHaDt!&Aw znnNs#w(BitXXe+ccODgh&)D*5+_Vt=9p8c@WNp_aN|5vLX^L&4xe#Ue_=X1g0Ra@^ zk4o16hp&E;2tgJDti=52HD3Wg#)%l}OjtQ0;wqBCdzyIbqE#`=G`kh~)`$*jLS+t{SXqn+wYevd{L@@-aEj&))5 z_l5Z%QyWvE61493@xiwiNg2^EYCXm#E(~Mi{(W1b7lM&0wmvt9Q$N(yX`$(3Tj(zBaipeOlIwMohS|)Go zUcz8W4s0!NHN&ENjX*pI9*bsQL$xT$y4_fyl@4Rn*ehxgb4c4*$}C}tjH2IAo7D1_ z@C611X*H#5lxuQTdXJSPm1RqLvQVANY}p@$r<_?(Q4wXuAtfcH zXgfYQm{!%5Bji(30S^xkizrv*qZu2|kl~+3o#gz+78I9Qw}C@0 zJdjI=eYxnA8b^VK`MPPZR8Y5r;1%5+MPiVN-*gC!#mCo7NbXm$HbweK2tMuBd}vOykv;?aFV+Rpiz3I1T+31=2%B3VDSQ zB7oAwZ)$ZbjrKuk2X&ScHa0fF;$&CI;DZ~oq1#)x@4W2n30=lW<)r{Isb^HRn4@1% z)soZmu*&qzL1ANyoO9q|MGt-Zohe7FN4TN26EYX7kzxAa&(-(X(r}MD|GLnvX#gr^ zcW#IFy*1nMOI-N={Y6R#!s+@V#r1ofbGQVH&i^^RQx69}n$K=IAv>O}7H#XMzg3Lw z;79+{ zI#b@%Nh#%KZkqMNyn;CB{8RI9G!q6bSt*z|BRJsGjdv)q7pSvS$?>1kt^jQ0PLXY|GJ*q%r4x%MX@W zmc`+DCvDk7Pf5f^LU@`#UP0`#R2|Qq6Oow&a%0%%?15JP$-A*`VAeCwHU*Ky5K=E# zbjUOFr z`DD_9tZ*w-%s)c^s-swe1U0A^`~x*Dr#GLE+V;xUnshhpfj_AyqO>>N_b)cq&GeoK zh_^^Y!WrB*BTxvPy03TBlXn6?IIhDzzmSPHu(7e`sz#_tx#oJ&60?f_^J&5*!}CVL zd0+fciVh7OI9~&8;X7(-Vy}Mb+qnw!Oe-s+|Bl|@9p_|XLO##>o2#M-SU1Q}3xyL9 zNT+a7Ic5d-=}dJDDxVdQVcU(Eg1sVf{_;`pWaJWH3!&ev%OX> zwHW~x)QBMfxq>WxY5l*G)ZaWkr?$YG#x-|e*<-j?ORui4^F21_56wqXLV!RAQt#p_ z_2QzUA3EK~)ZY^_uu|myYJ(x?YotBpAf|G4IT|X7=fm|d4I_my7S;~fkJ?|EOWV|* z&ukZkPLcD1-=B4XjVEwa_0>QU87@p-%|QzMcsR~U*3MJi+o=`!y2qZLEP@ULckL|0 zGj|6bebi1fwyo3Zmm1}(N)n!{$M zC3jnk)XX4lo9iU3o8wo61-Cxy)ge6dOGFw z(RRghEjOS5 zlLwoan6Q{@sa~o1w;MxEt*1fE&R(?d2F>>55DRzLU=RcpN?-S95O;^aIqweV&eb|Q ztD=E4nX+f931A=_Y2Q@~l2Q8mpkHo(nM_e$g^pw3lVM>KMZ|{SW7Y)*$i^D|d^ciS zRa%o=PbbWDDpaBmLX4&Pfd|ZP))l2iJ)g@SpG?2=Tf9HZOdU@*tDFcl*?BnNu4=hH zuR>^2R?g@=O%*~z19|%LEG+06Aq;ylwTs0G%JCt>sql!)jPQA7xE1q1%?f_tj2<29 zAnUiXo9%fbKnvj4MX!Ra*%9akHbX(?_>TVOoRc{)5_@J>qJ7K2Syer>BSniv4-~^wtXUT}m$<(cph*jPU65uT?Yw@8&!YNYyNJZ#+Jh z-!wHE-nT-2VT^Bn!QaQ4WuQ+^{+MPA{g>&%ahCD7h%dh+L}x+4Sx!_+6;oXr4@-R( zb(S*pG>{^Z9gdwLa2OGW7pCK*x?Qk1$UP=_KkmfOt1;4je*L_C!vB7xsehJAO**~a z_V>xzV*5q&QRG98T$R=zLHDqA>LM@GTFp zWt<22{YRKJKeeMHvYLf+)YPcUT%YbYFRosdw)#5&0p_O0>t=uKl_}WoNrvi6r@98& zeI>}dZgd(wysM^WB#n_@#K^)Vfg+kLMINbNI93XL!W1pN7&>HQ2DqoFxAj`FHAo58 zFZ)3|J>Fc;`mAzyL`o2Q()SOD$?Z@EI`|>okbke_(e_qBcIz2RhlY>+4I3XD7XLfF zsh)1rJrdm3N!y(4qt+>cUM`8Xp_U<2$Q&aeWLv7KYs`%z^#vu0oTf zuA!a*=DP=)k!=CI<$o+;smVAQf11J}AwWJrG3(n};kumS>LcWtAoN|kB?s$^&xs?F z;9z5$+<$BHt$`;ri~54wX)=Nl=Y3wH>Pf9sfdtzeUect)kyL`mi`o(Ef7SPAax&6> zWj*CJTzP{1UeXFz@m4=k+fyOgx}=&w%dntbIpx0R5AE4&Ri!Nr;>Dcbu3T9xY|Mw! z|53)qt8Y~22ojI>v;eZ*Jzm+K5mm3-)aMgYKl5eLpL9#|M| z1qLGdruZ0sS!HHy`>WE`tZ{zM<=BzFUQb6~u}2~O2mU!QM5-%K!Uvh;-oq_Qnv;=^ zGpM#bN@!W`=&LjZQIENcPBYjsc^bUT)fD}`GC7sR8NYnk%^SREGT*qGa6C=m+?Z%M z_Xl7fvXOP-#di{uuM|%NGHNPi6DqHHer4ifgk^SITi|CpCH=WTSy+fd-AaH=E zH(4;ig2O@%yHCbKZd~ZC$MQOi6}i>3NWQrDo89Q!z|<6)UJitrXdZ2Ngq%gi{1{Wa zxqOHMH3>IkNUhQ6*xSPe3M}$E2BsT1Jv|5QA-btcX*O?ot<0K~ZLf&H377rbxp=_b z3!C3X(+8{FQbog6F#}2|`yLkDJV_hyu5LLK`BnHb5E{vr!T0COw*Q3tqO8YYPhgS00OFyd53{`5X^7?!^NTP|%U2;=%(xzH0$WI3G#_Me( zd|F|)yV~7w?VqRQ?%4I9qi0&9uH}>TXKt!%{m1B|0yx3O-R`)N77V$FnG)iL_I{n# z`~%LB7nJHC0|iOqvlw{NH9oMT;lNcBI_nCXSh?B6-_p;MFStKf2feTnN0Z zovhhpF;6ypf$gNF#H3>HX?*Pcxf455xIcJYA#ra&{XLR_%E3;gMmGb0FU`A2Ul{o@ z-j)|3#?0<|vwQ05D(sg=ElYLaJ{s#UPXu`Q>zkX}cDmmRZN8_cr!^sMs@Dtbk1~1R z*;v2(y?g6xua#F*%OfMdZ-sWX`}q0#)(A4Z<5bXOy1#vTq*SP}#zgm;_MRwimL`a~K(M^0MfTdQ{r zUJrO#{mgZN-C}*6h`0SKGDzZ3perR(0Jn#on;m1mo*^1iWf^@wA1Z6gP+(9zFvt5V zX8&z~FN?5JsXFrn3X1Z{axzO=Vsy~M=~1U+?naJK+9TuV5$$11PF^0AlG9-V2G&Jo z8#C&;SbsBx=@k!E&WR$ZM!GYJo@9M~r^*(#;&8lYEDupy-_i#kc7B+4%|F#yjyAp@ zA1s)D9>zeHB)LYEo;%zwIMYp&C zPL}_2SdQHw3u)*UbU8=3sI_HjDu4L)H`!(-vfso7wcmT&d1$}i)tBb77&e~E8It8} z8n*w8CKkd^ln)IJ&Q~;i`!S~rTDe_ZJ26JPWAI1qPm{NAEAKb?p ziG_N}(Koh_lk0lW{uL#*Z9rGN$Y7x5Xjn}6Z_*a4uho{)$T&39W$!v+KhcoD!(Mfj zI(5)ob8)xX)6+c}8LJJpGoxcCg$<_Vc%ZH{EvK5MP7&%&L7#iZ>Q(5{(o#A)y7ESc z=p;@;<~jKVHV;{=N7)oMwQDPAMgzXx*QwX!PlUJ+Dm@0F-w7$#rSW|il+D*9f4)oY z$7f&h5>ILNT$R>nHFMsU|Bs-ww$`%eoDWlztoJ$G%La6hcjziu)Ydk*U^~&mBq+kdj}}x^y!K9R!ODLB zxiVavkAZ9qBzvBQB=~xHS#NL8yUF1%5DC_Q8SY`6?e~ z|CM(z5{yxcOJDccS@4hcl6YVv!{5XwdCt)smmKo1<(d0poNXo@8jpQmIUUJ9Ikt~8 zO`(5jR~(gyk+d64Fwl2GJCik3CFD4*y>1s#7%<&8FSj5@7MAB`$xF3sd+v*Km3p(H zea%HbVyP8#*v*Fvm1%A-KFHru`wXju{TC(B?dK-*z{C;2uWIDf�dvn4L_%f1gDU z8wV$}E42xxoYPn0TYn$Fi;j*?4GVhNvbE$e!`a!$pN}=rjBW$HVN=!luB^>eAZ4C3 zN8?2ISAzmSKR*q{kx9O3Sy|anv_@%t9Wbr0D|yRh^hH%Soi~sT4QXR<$l1wsgvSt! zjBo%Y^%-LQr6CtCM^(Wrn40mu%Asp1m2P4t*Mk7ryHp91`~6Ay5cL;zy`7Wxcw4X4 zW@kz?Y-}J^^u@4$A3P%xb^!OZ&AZmp-#h)7_CJ?CN)tcNS07>KSwm&R@I-=vP!qgI zQ6Y!NCgD64O0bG$CPszco>s^Yw92BRI!jABwA6|Ab&VZU)kZ%Psj)J-r_$KstSTw{ z&H9xx)4k7D4$hCfA1?u?ArRLd=ISOC`29c5ncv^Z6f?~Jv;~KnIV5C6qt&CE>hHnGTK)LIQ>aIkc&H?RUty@@NVJ`JiF>YdRu z41cJAnHxXWnr)TEO~`ZhLmPS$(){H=0~ljsZ(8o}Zg?4)+4}Ad!F8ymJ2Bd<^z?Az z@pK)XBR;+(C@8*E<~}-J9g`BRrKRH-O7#uJOhI42TF9AC2Np@GE>wkv zR8SY`qoN`@Q?wY8bZUC~?;mKMtRKG=K(;yHj!*mHlFO0K&A=Tq@mIQ~kU_fkM6|=BW8;gOH4bB=M{CBw zXyj*YiA>5#p096>UeC8jGhP+(aae1Dc=)@`_|U?`;Z#A%Nq@X+GU;-E z7)sk)+r!xnJL~uAk4@qvH>Dp$cZU5rj7S{)IZ$6AsL3?7pIvu=eO}yofU7ascR`i? zpQbyC0-ogJW2!wXLBEHG+pzgT&Ab~^wY{SiChxDuVnJnvvU$~9_Rrwe7B*?=Cn2AN z!re%Ie$eY{+uN(4kkFO`A?g*U2;(=0bt!}(u~!u0)%6a);|t;eYq)2$1{|**g_>D(11KDO~%{Cjo&@9(S9^e5oY^&~PY9wZ$pC zY2HO=CwRiK7$ne7SBm2Mqk0brl#q~kAmKByG)WjutAxf#Jw9BWUWoNN#Md-xG8$Qa z2km#R6s31KZ^X+usF$!KV01VxU4b+Bw`b|(3>{|ZZyObOwXM>630cI!+bgKAvdr?^ zSx-F(!XQseSu^=d&LlWCqmePi$mmL9-Z*;tUHg@uZtqIn5JuhI(}RQK3z4@qPgg|+ z`p(CEO`91ZQ@|D);pyHExV%6WVGN~5%q}{J0)r$ZIGB+4=WL^orzDtwOAr*g^|C*9 zA^1ROvK?9h=y2$~Z+P1<3{cmkK&T@Dn6(%R;Tu{^0gk5#69yMQ@{T|qJ>BBq$(poH zDJ$F+pqiSrfk2!R#!vLY&hO7mhs5x%M-RRxN{Vhr)e>X{=fK&<%HsfU^ov*zrwx2$ z!mPo?q^5Oo0p>Oz4J62lu;6M#kjLHg-7zxJ;jxC)#d?@$fpqlp=~k`v%RQ5WgRov> zAwKRPw<9%CHex?>gF`f_S7>o@WF!K=xJ1_^6H2wSQ$5>FBfu_i_s^d{5(6=QrVcs7 zX_@<$IMmFI^^86*XNmm$C~9EeHUBf)m-2ba`MHads;wSLfuM1W-RVMP4F0Bdzq;*< zJb+yYkmNhqq>L*MaBoSHO+)pIxkHX5s=&vpN?z(3hW{YK*JdL{rK6q9fHp4xA8pzI zMzB#p%_)9a_5fn6$zH+_I$lfN^gPz%(a)BYZh9CVV<6`4?je*bF{!Kja5PF%Tvrzx z8j?j@MZhv9u$Ggf4hiJJ*V4?}(h9s-(V8q))=*J#2YD>uMcU6;6elJ|h7L5^uc&N| z`e^Q?S>bjtf5o_=wtSE8?EH8KhuRzdq>HWvA&@V9o9Zf(;1)5|jX@Y{jg!gY0rvBZtfVCta&5rM>CMXfk<@Hp+=_ zvQ-C@WU30jlT16xnn%buZE(6Iv%N;;vQv?=qQ)qw^&I#@!{OmIQ7cpHt+Zk@*=*S% zMBafs9j|Yrt{+%3_|%B;bR6umpkN3He13X0zdX0LfG##VMYIAv@o}^$Aq6B`qm_?rqye-44tuZ#U+?Ju{{6Msk$hF? z=;P@$!HkhtGs(J8^C%(rX@4)|EX7h7gEd$UXQH``eaxLlHgDp`YtgOlR6E3G4ZyM! z*wI6olAOD@m?%Bfk(heUG+y_H-G;2^hd&3c@v@#7?Q-w~T77ARt$2F5q{0 zGsyJO>xljqZa25nN9yl_)$q!!T<&uE4`~e{q#K_wH%YXwOGFv0Sy9WVHUXg9!ek#f zt7Z}W4jiNhMS+Dvxue+qQ86qw`h2#D8}o2TI7x6gu0y>!g8P{+Lo{gug(N4>1ipag z*16%$nkUs`a&2>tkipuj{_2{6zQNS?h=d{YwHX}cXSBlo%4SpeG)RSl65F-8$yXr# zS6*IV^6fFcwk@6GOZb@4=k!WbM>A7EvgK2?Tz@U zn3r`8g0F2XT(FbH_{(QDnJ%iq#^;Sb7)d$f*K_+9Uwvf9+`0Qv2eLby!}TnY%r-uThCR`mP}b=y8l$MXAz zsJvU%mXEbMXVmxGikR`jryH~$@m4KLW`=MGt*Tx#vm_neghGHFmW9Q2IEF1EQe@#% zuEF#D9W0{T-R0u;sqbdj*Ji>2Rh=xDZXNWpA`@-ADOPOf2PD`uHh*7g(_(`AZ+yS@ z4}eyWXl=8{HVp0k_Zx4iAw70frjKOz3hfQfcH$ zuY6RTql<4K^E?GPD(Br~PtQ_jD$4Bfn@r;=QK0FVa(fO_b1%Y^g z(R9z?{jDil_D4i(ec`GNJf4`VDSkD;U)UYKkf3nO*>=!@AFo|h!(F#Z3;bloRBZr; zGY`I%-jJ;9ao_h2Rz;D@jSBi-in7i6#g`j0+r8K{jefbAQldgo zyy=~}nQSMQYwgtiBabDD#1-Oq+wT3-;%diR$HKolA_nXBnGaou? zBszvk6dAs2tZf5(KV$u9|NbZnk1wjP%;1-{qjpeu?q8fH{hqNg`-I@^>@|n*0rbn{ z)7C_soZ!$K0*C9L=W?v%eTf4nKh9=_4%OW zs+s4RU*5}x58WSmF%U;`!oMRjcWvY^6sMmljf(e)2F+lTEmRrQj-Th>xMo09O9td| z-r*@@1sHuOg#eWd*)c>~kle_f4e!7GYnFz5sO~~iPL_m+1Zf*wfS-Vn%Uk-Ntw2uQ z8*d8Ein9*ui~PNrzay*Fo&8ywg7RhZyTLPFZy_{b`S7@h^HQE{!(S)zZbbXT;2V*1Vj8|w@xP3YExt9Khtb(#m#7fDI zG;e5LIT6ITkM9pMpEv&=CHRjLKk9E0h$X@QRyf@$0SfXb7M zFx*civlXo8he235buSpmFRuuY`|{Rm2;UBG>m7*G@l`>{W{b(fY0?9UvH}>bQ%Q-C zbBGt;Z^kiboG|$@u41G-F)n;iX_j)Ian&;CXB$v-mlKE7t^;#-5(+lQQ*fr&RsxBjAnHt z^f7)1>2J;+b7rkCmAZO*JMFoVC>nTin!UoN(LA8Z4d0WY+ zM{j7=cKuVnJ!w31&%e71=$_jVdKq;CWn{5UHy+O4`Vy$L?~&Z6RI1CQ`NhJ2b~5Ei ze|>!X1gli4lasNsBC>j)Fa6?4ii1|hNx#d$x*Z1%>X>OggJW_}Y<$Ik{cWfqq zNNubX>Drqr;FmNTW15PtV{)=7NM4Fk(8{Ps{UVe?fak7QFHmOBadAeztb1`5Z+4D zsd@B^-7%>*wZlYXq7qEuMjKrDOB(EZrEY#^dnOKw-#MK89=~I21O!J8ex<-jonTHn)9)xg2Lf46AF?bcekxS5eXQM_yeqvOgI%D=Osu0{h9*DrJ&zSS+}LCL)JK0Eb&3tTZ1YgjyR|#druV$jlj ze$lGX)oA^B7tLiWH(%9WHG_3@2gSdJ^3$)wFt=dFVETyt_IcF(gdO4=bCuCYWT%Kn zh7uBovdbz}&QuLI8T4!Ze?k>%tk((9M!#gDu8F(BO_Aw=?Ch^)6L~@&WgD@{GD3cJ z5|}gKkgJ8ciYLLT(nvyJ54(>pN;<62LAsn1)7@=^;Kmny$m<5^hjp5Z7%QAJ|Hj{6 zTG~<(ss@l!{%;O!UV-36re0yP4h(W=OG)chO0pkj&{HrWcJnj?&Kl`V_)eaaFkM5sE<9iGd8h*S0B$PuwxPs&OB#=N=Tg@m1 zY_r~0v#eyn_=aEbElM2VT)Ke~uupOp;;>u_O{(DkHQoO#0XWXoaDBH)LlsAwu_q}8 ze&tetC7WgCI>jpih{NXnZ!Uc5Pq{v63ZLSBQa|PVU+LJ;8?SNU?5ue z-@kvDtga;)ux#1-E_=gR1u0t9hNb5PAkaz)6&>A>VOH9*K$$dCWo2cV-X|u^rj%D$ zXqH0yJ17qs38^&rQ;3zF?jRW64^1sC25uJ@mr-458JV-fw2V>onIS62jSeo`(uxXo zyDr~FYfH=GV^$T@Xi7FV)p$`03nmB%h&r?MnT^yxa;>ecqq^JM+n7Twt_L*(Kp^xS z;C#J3QgL`>1dHGk<>j^&gE2|rJtNYnOPQYj(bxZpV%5&%|p$TVRnchVmONBO@U(vF6$2%1UN-cJy3CL_`hT zdzNe5IPiIYEc543I)^2ysG8bLZ*Q<1ESX`+RwxQd5B8wHI?}mQ<_&2m$n9u4s%7Ek zV1k2#V`O+ZN7(Q9ik%x-*V&n^75NaaME887GvNMI$E%O20e};0BO^1=7l~s@Xf0|$ z%EE#o1=9q1WKx1l)Z(=Djl)ztjK>BS-140bXPip+yOZbH@?WK$`?D397(!JXL|ojB z7FQa6m@@2L4;Rrzp=N(|5}}`%*w{r%6r7y5Ly0t10T<`+SUbmu7N2{*9fA*BXPp*c zXD2`D$k|$|vxNQPZj$5^6c}hR%X*7ALcm zi~TMO?ZRdGCTjihi35_6ksWh>9@0IocV%~Pwa-46;Offid!fz9?=k75-Ay(iIOd6IL)AMS2REQunDvSa(=i*B1N5>6w@eW ziGIO#ZS)kZL~#C6yF67OQ@Jp#WA~?tO*tDP5|W4xYLH&wTi3cw0Qf5^kd zM)Be=A}pq69*Z8?I81uoxVOT^!;1?ouF*08Q*$G&R3M@5)VERvUXaABC6F?_)r^TFabE$qU-vnafjewL_Y zX_=*?2bvjQJZ`m(KZ*E;?(*$xfmz6Le%LScreE+bXx}Bt6wRd2S$~Pa4s+q6LTSRH zx@;w6`S0^Ckv04kQmQk4Ya`~R%%Kcr1;1nk`v&lGvB0{v=<5mQ>gk7@{t09yw1>^y z-2UhLh`>mOj*JXX`REGChR&fNIeHn;XUuA4-XjslJ~()Z{rvLMaJ_|6(OWq*aXD{e zYumuSr7e~Oh(sLmqBCS55ssyN_ZekHV*{h%t#e;S1aB5iEe=VgHx#|2BSdf3R?@PEP)Uf)E}>G*y&P4FqW9`&yw}FplVw!=2!4 zQ7r#&ri-`7n6Eyu?Vyq6xw@Lu0WSa8m)gpi=_R3yt1XkRph$!4*q=Xh1^a&Rb>C?m zs06%7jHI1tkZw8)=OW5d_e%?ad}_T+XfdYBK1v^_{;eksV)?k|5(79mNR!US@M3hB) zgLwy#>HEu)jHdj?=67R?uq8dA6mEH$fvy^a39NmQSQMnqP~)Teu~ui-DIuQdXi)3f zBJK?-+aNxI^47Rt&J(eoWoUz~jm7W(wDR~i!m5e%JT&3&|FlBjuCdpX9y!v{aQxG+ zAg`tIpSE8I^c0g2Lz2d7SxeQ+UR7@En!`$aM4P<%nCESarBbHAPmZKxs*mU6Ydf2W zYhP8iB1y$XM7{tf?$s%yQ4#Y)Tt5{fou%cDYrl;x$i409*>JONoDf9Qmo<=#tvPPqCmV}};j&$0P$;tH0S@3)wtGRx zoyj9xDU>1LQR(wpp#RksjeGR7Yq8n`iR{9L^}G%HSPGfhqf`F1hv`nsX?;-@Tm}DK zxw5~OtDcc-`)#w+*QR!TO@LL0p3cw4k}`yHQq%r}OhlYqO@q?1&H_iPGSCnr1{%k! zp@r8+s!aPyw~7;!O!m|D+^Y6Q5Jv`~InZRoQRJqwqA=_Go#Q4ZPn^dqDm&rJzy=Ln z(x9@!C=L@-CDn4p_|#Fnq3L}V#~`VP)VzW-Clm~P#1n$L`jZ~ zo4XW&A^$Spt@mv=SHaG;`P+Km>r4bQsIGyxsjy+-UMeY1|KH zBAdla0F1|n-}e2ou=>CbfL3K^%b~GRCI)0GVAj`v5LOl}5(Ba%86+B(YsW^$4&bDu z9A}+YAWG>@YtdzL`0iw?Ww@qhMB7(sIas8HrENX1gGtUrSlf3E?wH{5jyPN$G<;7n z7FM@UH&b&z$Tshas7W$!9^V+MO;O(Q@q{x|d_R_MrCAT}7@>XFLjb1Bcm@DXn^4!I zvZSqlr-^s5xz&}9kiHCt6F+F{ows^(16+BRv~|!E@1@?_*J;gpg_)Tt{o=DwJIO<8 zj`tfHFBr>qt1W!Xr~Dlsaf#jRDe8|_@Q8@|PIl+^HrClhy1c$WjMk-5gvJ37&;2?4 zFcMQXDj=hhqvE%&JzkcdpGVW^6e}fwwffWh2Q=rK2Z`0G7TIUv;o+Gaf)78}`JP7? z)zjnh0slD%e-@55%LQhs)^BpdK@y1iyR=ED>?XKCg;^J!NR;rW-h)k<$#a4{alSkI)h+cmGrIT4mP8c~mJ9{_x zl$UTnO16!u)yg;PdiI2zw({;lVPpeK_99+1cP6d>w9ndWDLq+`V@^JlrnZzI^LI$g zCD@Og{$z0Vh2a?e@1q(;Yz}k>{f@ zfqxkV;C2NsjqvVZHo+BX8^gdOAUMm_A7OIz^!7pyhi)uL7pSgMf97wC6Q2py>gsBG zI^LC0H*^@`I}t7}YE$^gUJo*97cSiOeeE~nV=kZv77mUnhc#XC+123`#p!3tNexU1 zlawT}0DkQ(WebN3!Jyn{&B}~W{RN!{W|e@C4f|pWQ&e2s_W^lR_?cm`d_O)u9z|~} zq?3jz3P_{+&O(d^rme|M^P+NqlR;lZwCryV*RA9Z&5JR?WMpJa179*j5M%DN)YH-@Lq;U?QTRWKwD0ipOzsbDO}hE~`@4xm~OaB|;+5bl$+#(;>QJ zk^^Kd$`uCFP~kxK@ID8gMMiC20Qeaz&K_#|2&ybR_qnZ?p3?^u+Q%Z#sjoQ zI@8$p5XB>mbiGyo&i<=j)wNR=bxL6f%gAXdqwd$7cLt* ziGgU|g<@^PFpO@4BM<9xTboh@>8w-=%*7m+8Q2RLl@OXUtsG5_KS$`=gIXQj54=3M zEq&}jRs3gync0omGNh>A#nBDFiHWQ1Qnf+Dl2LjmfJQJRT+<+T0L1YZ2Porv*Sjtl z7qO1#isYaFB{sqREKtFpMHt|-=wCpD0^ZuQ+*jI&KHg19ya`pi6hZ@`dM_c`8xL3c8Sg(H9!qR~(FF%WrBMRyCGM*2 zA3IoCNht--pM*%FDw#lk?|7gHut%e_86u(;hnM|#DI$YZqW<13#$-VPP(xWh5&Kz$ zBLI}HgoAV&%D{woH;%{{I(!JBKd-%`0q(#S^qZYEc`VLlV*5Yejwz@{d|LPPV* zALF&oV~mZ>!vSRzc?-Qu-kc`w3&;@LwO&u7;J{q-1P3%$@IllX?#Eo&!-me#N{&YnN2@0h8vSYGnQ&AXM09cgPZrp-CSpJ8Y zG9!H#m)v~IL$v)wqYKSo)!9?oc|L=o^&%rUzzT4FioY!f&mWx1ULU|=>{EeyWu6dl zI^=1a^3vk5mve@3@BMuzZqx}rU-ln8u3anV_}R(&np_9gtJZJa2(pkYC18^M$rdK` zzisPt%u>bRDdO%EVKE>oltN+s>+9Q`0U&TbnmOG=n5NP1LPqc-Kfi}5%(?gZZ==5A z;($}ch7PAWmtaTu3tNf65LESfZjmcr*8n*I-_9&|p2p>u4t32qZ7)#49kr*ih~qhY z{;LqJ{w_2QFgrv$WmR)M3Sx*p9G|*gKYJxg8U6A;CC`Ptz_(tg;dkswvP_5^X>H~7 zN9*TS>TNfT15iNy<9Ry+P2gg?)<4&sqP-i&}o4m;%YepWk;;I%O}YDl+z97fDK90x^j6);ft0_G%-JDt zZ(+57H|a$w&bW6~E7Z65+F@q?{^;S6m+PiUgXSiUv$IFy{UZ$xfwXQF;sdkVc`-r* z-KBV@SOwj=+m(U)0B$qSNso~L!v_RIrBy-n-W=z>ov6sP7ZB&1i+Og8LVN-{QVR`s zkY<&7(*thtOP<^G|I^i52E-NgjKWY{wiJiOio3fPr)Y6^cPQ>{DT_mKhvHD&ic49f zxVsfE?r!(c=eh6w-fw@b%$dndGMOYNC&_Z&?_ba?9F?&yq>v`vt$Smj-NeLQ@45#eHlynS717TXXpOw!C`3H%?MHN_@=b|e^N^i~{;KxyPDqG!qvp294 z&(4>EDVlF6qz3;YnD{yBU$K~yMW1d(vzXak3*OpoP>PE~p~1OR8N-4d6BmydPo?g4GGx=T1PCo` z5D~|xr3tb6PG`$qb`Mu-6*%AiVhzlv=1eJ3HY$o^n2PeR*dTPbuu%y+*sdC0ayQV_ zWm1`1X|LIbsOFUYP^HJ=UOqti5yZ|jrJkgvF3Y$%t?F`p7--j~TEfJ@pjM+hgzj7L zzEqPwfdThXb&}1vHpXK?=10N+R#-)ClcBB(OA?*IB8{1Ro-RXW`?QU-!XiPtSL<6r zc7}I<@NqJ0Tz1G12|_{;hEmc!DgwE>V+JuIb)K8|g|o16UN-Gd;P{sisI1dty`5Cl z9r-%M(Ns>pl-RyjlcKhYxn=l+ZlTA|)L2rN)HI%j1Pk!vcg_#{gFQZ_{<+J}f^9Xf zp;gj%j-dsL-CMe`+C^l>ft8t!)p{X&7N#yz!(34&A1ecd& zJyqN>q~<0qgIe552kWIv3p&Iqh@9Jub+q(<6ceiHDGM^nhZFQ^`z#6*%S|#myyhs( z&EHICq*gQ+YRRcBkkeFIbT;c8`eySg5cHwy(=uD9Fb76eC8*TB0;Hp*V__FxxAZq$ zr=`3oziedP8L^_Es5XK}7uRC8MZq3_(mT)Pz*LS&lOO6`)sSv-J$&htckk$xOYjrC zsLqipJ!@OD(0@^v>W@qRHBoOu>_}<4n(X$YUt@sSJR`4utH?VT7!Q$k}j9@1Zej}n8_5K2mR0W1fu6>eCqU8l}NvkSL{ETgy!)u>{l4?zQ zExJUx;9OnKPH84H$DCDsT=~CR8uc@mu(0tx(G6X%{$pyeqXV`?s7VTa#V`!~i{XJ` zkG}Ex-$nXhL1dV$p)M<=(^S!XoTER>?=)U5%@Xtu^il>TbdeA@oT(%NW2c1PLNKAl za_`Vby}bMiRpf@#p56ezZ&-b;$cQam`cB)f2bZZmn}GNtc=6XPm|<_j$*t)N>)@t6 z1aKVswGmF)K7A(;E4LvMxB5F4Soa#!z8L)Z7YcGOK31P8ovKB`Cw1&F?M^z`Rw@FP zropYFpQFs@Y-rwR#Dt_3#Mh5Q=Y3A`I~Gp0E!jKs2d-!!I2;vXyOdteF*aT5PY_r+ z6fgvWqDu`k#j zT5k{+{JLyYX!oNp$Eqm6+YvaU-7xwFpjzt5dtq7(=Ik_bs>}|X?-WQ4>UdlHZr~uw z4(mg^Y?bIoBCTl8IX4>L(?`4JAd~l$Scqh^m98;LigJUgKTC&On#|?ml+s1+W+HT|2NLHE)*;wT(xwlt1?DXVkI}L+gllYy`vlp_qHHVTMR}j+k7tpw&>~l^>H;^Lc7~y(*4y8#+NGlHa`KUDC_c`&L0YJZ z+78yDZkko=R7)LrV7~hYW9K|x=p#x2j*+Y{GvM>Qu7BEZ<*cED3NxfSr%VJY681H) zzNJ9iC;3XQ_J}10t!7dE6aWJzRe-L2DSP0rBajH}~!MT!DpjD^gC_m<%EF4`rT|Fe_0 zko^SO!&>U3X4Wo#Q><$H1iVK55y|U<3Iy3gtW?rV18KRRJ zCTC2D!X@;3-I)~X7{)tjkX>WQay5+#M6nbv&gkwgnD6g>TC5{z=I3#m(FsA6}Dp(6N)?9B?hOYp<}y^Cd#b@9}Fp z#sNIV?3CfzH;kobErO5Y2j{Jr^>@@?AZ7;nFpmJcr9gZ~?D68H7tse~XKhj-LE=mM z^O)mRBO^ezr;!{qHw$h>8EJq+NOmYYNv2@pG{mU!Ex_V~&%5baZM+Ok;t}8!;}8(X1wV{CS$9*4ot+2!D~juMPT}luRlU zIUELiz0+r}mIQj7I;+$5djHNA16NfV6Vc8u5|X%i{8a zNQTfIg2}to?zp2eFn;rpw*k?)D6Ct*ALu~)O1BYWCTO|J(ffVcN`N-Gtt!wOYf#c~4e-=2pr75CGsfHh>j21PjJ#Um!vLGY0Xc_4~_c>1>z}tN*^eTxxZ6&V&U? zK*Nenx?H^PyE`Bo#MT7YHM7*ffQM%W7pzKf#oHi974prl!tanR)~`f-)&wt;G~%dY zs&sei$`Txx>v8c=_E;0OT{HRs&m(eZ(~jH)-g z6%`DFL}SNJS`6%QFGdB4~ z^*cH|=A**rd>aKyi?3epH~LW7gM;GPGSD3ei|`L+F|J zx7icqAV}z3hO$a;Nn7dE!@T;7fR_*Sqc^XiN_~!ZFZh~Qwf-Vcj7B*NC_xhFqz=|< z9&2v>EQMUNa(wm`eI>|-+Fu|W>d@OG=BIbc@^%dmLMXdB_!HoyELrjPmItUUey0mp`&Jq;?1wyaRPG}UMS)vybU9nmC4tIZ^Xc}y()_WvQ`&Q&8yjvkX4GJy_(T4z)|zAMfR zX3)*Uff_iHaW)E}@b7>5#TGA{V}0yClVI7sKl!@;`owI^?Xv%w*l7#}-S@~IW3D6V zmBlRp5+m%Fb21S@G$KT0K%)jhHlTORrhNf^R@Yz{YD$I3*m$n=iK3y2SQ9j z=E=`%$fg8N!*(j&Y(qpvaL`URHldo~&G&3N_yd_IVK^V}X_=+5CK5_>P@p8VJa1w% z4C)ULKvJxh&j;Tubrq=+_{~P02k)k-N{lTw9r0dNa6K!4fNotxHMt_&XEkk@@VG=KBA{OD)40}sqLThTWmOB^_>4;I)4R{u*%+vi;^s8YJRhrNF)>;_ zt&Hgk!a*^Z$_}`4HZj@CP@uoMQK_i(f~iC`doES=LW?O0n)TA`-+x+5>8whDdtZXR z&0KOjyoT~`Hn9{Z%r0lP>Q^X=DfPR(pZ4XT>ACN`Q70p+->f;P)-A-rK-tee=xSP* zXMQ$8?(&Ox0|9Cp$`-F2z2TnpeYi4ZlJrVX=yZ5r#X~$u@Oou|Fm>Y1*IPUrbR=xX zZ{J26B;;A=kDwija({kObvh53^3}bN0N$is3Ka@AL)dmKE=f*~F;*8Le{y*Ljh^J3 z;C12)9bQ(}U3I1X`Bzn;p&vZu{a1KX`7iiMrZCV*EuHTvfG01-C%QD z8n}3svc928T6uw5Q#nw(5|(k@aDB7Db)+4ip7bq?cVAm(^_PV*HNnM(tGuYdGsdy5 zqIi)t6JH_jrR!!LaBjO{k!Ej=v{aFX9q9 z>oseO71y?*N#dZ@RZqbgOGUj?h6tP@2Z{yoGPbOqiaQ1{iy0<#1N~HTYM1oPfBkX^ zY*|jfSh-lIz!!7Ar%+1IZg!f16Hnce+qaRpSjOj8-E#OAg;~(~SHKqb+F{aAi)Q@T z)a>UZDK^{21x=ockX zcqpCsI?+S%T_rcBN(Kuo0F>K|Aj$eW0>FYYq) z-Tr9H0D@o#Dm*lDCp{x~Yq9vLLW2LtzynTPf&lI~8(XCH%le+pj+cURf2{L8wcMMU z%zJouOuvPdDjZUQpA0|!g~J2N;}+qN%sh=vq}P4V@F!n~($eVahkkXi6HEP}G+FqnbKm%Om}Ttv_(uNsj>`qDkkCJ4f@rqgErrI{|@)fm>ei zkkp2wY;S&SGl@&NM31rGWf*6*Q?NFA7+NcW5TYO9IA6XW@B&)N}Nc`NOkCPojy016m> z%?A!5i~*$xn>QZdbgkr1lajo^Xc~Wn7i=M8oBzLh5al1Aw z-AXu9*~Hm<=*3CXBiBqu;bBtwqSIK4`s$&|19cG-`x(*}2623%YlVv3t5J(0txQs| zZ%7DwtB_wbVe$y%*77JmRpaq)k_yn^gw5X7j|UuJZBfqgZG#D@ zhMB@=A%q6a=sa%ybg0l_@5RhB##>xk9T2O-Q7A{ zyaGKZiE+W*RH`{AH||Lr3p!b=0_-jWUU(4x&#Skvi#t+x*yBK5-KeDAa?Xu{ z1pOTDXEv*kn8K{2LL6z1&oQxWW!01)aBe*CG-pU&L8{fjl*mE_24*SvRhc$gze-gE z+`UZip5)!_OIBpcG_I!4628hNDioqb28dW$)XyWLZ_sqT*<>;%s5NowK>Duk3wrP) zF&yg*z0L2Ztkw-kpAAQH(0q?SdwODF1CutG5D0b)NdpU5>LECaZ6w*0QyIk*-h}lf zhe*9F4E{yuvh6e+jW?2*vd<)4u2<*I{7ewb2+xi7j}_!ot-L@}$X4-MwDg2Db54Mt zR=C-zRW|rC?qbQ!Xh>Qo=qxW!>{C((8t@CLB#UwO=1d3$M^_(=*zGpvPuIY~PWCQ} z*ldyW|7P+hh60NxXP&X=)=G4E5loFrjD{M;6kEP8~pq&@}}DeR?OI{2{s!R zE#B9iMZV}f_LNtE2mxS_xCnMb(paC{A64qR#2)draB7JSrPxbXd;$r6E`oWshDii% zC10V@k$$^L@@2QL_e{ZMqYBDg;{f=u*BJGm{o@IQl^-*TB&XmVly7U{kjb$!HCgjD zq=pi!NGwh)YU(i_r`UolNAPWa@OK%;p1HF^_;qjIXas5gNi)6p1VH|un*rwwumn=vS zgZB{dc60W;r2#4J%8xI`m&N|Y=advkU-sNiawgQpqWjNj#X6k+F)OSGdG35wqZ z4IV7qb!H~&hR4Vt*&+nX5#cQ1l-A|L-O$PAO#`b_?p)8a zur&c=0U04z#GlW99uYy6Vo0oE5U1(ZUOs#KU<_8kaXrSCCItfkKz!@Ee4=WT()i#X zApTdtS8R)j*mu2;MZXFjl&1s#k8n`Dmk*c~r!h9Lnl-^OF;~RP5@G)>R+}DFr3wa1 zo1ua>GK2OZuoXnWCEYgw>3Tzu$pV2-X|%JzF*d!&chH+R|Hu$&Q(j=z!)32M{9jk3 z1k||czn;q%kK@b2?8Kl4B0qorR8mrE0n%Ft2(-`SEVf@K;kE-6!tM?i8%E#%Ka!pS z=@LM}1}Uyq4moKjg8wc~FB3vPwtrb)UyoBdZA(8rKcAYC^7qdlV=Jo$_x+i|LYfU7 zTIH;ZlarI{>kc3cowzMi*q7(++fPa;AfOh{k2n`{BULReAj%7ujEq%{6&olN1LP^@ zPXTecEu5v5m7cC{vHlzQ5-Olh5PMR5JSRJQY+_>1J(GZd?w%k(Tp*j_Tw>`A zJTfvuN=9~kc$ip{97aV=z1-$|z0~B2qjs$&H@~>Z*;}FCL?NvI7i0`14A6}X4FOUA zh1oc29r^%rbGqEE$W$Os7}BuBaW;fn&dFIKCAG4u^8{712HWdi(E=5E+%G;GNt>0d z&vrtkN3~kK&HRm`gqMo@e=>|}n*PpB!ispHiV@+QyUde~RdHLVG=Hk7sJOp6Y;oOr z9eA<^4S{xbr63;*+5BlJEsanfPhsQiSzPoL0T+I@4&U0hpirmm$@dmXjEyBP=g1Q~ zXl-o;BJdDw=ElckO+T{rT*RB+NtiPPL(0{m@IKH^)v^RgQN=TZ&76#!Mdc*h>-s)4 z)!X431+$z1{%EIG$7#}ByzGvx^DsM!v8o=Vf?;|lru-=&Sl)&wK{T>Zmj3AIC~4c} z7UvQtm0qskqX>9r*Nx-yOa>rMiYO4>rXB!f=Gp>vWJ=h8>@G3zj5U`u$kWa3gMw** zaly-(`qaZURC_dkj7~Fj;rSrB#pTH)JTflQOMo^)pPE9-IDr0#sFL@A3y18v$=`O{ zP|KgZC&uZP82nQl)Y91aA-qmqQ?pmn`g_U%6bhvm@jCf4H>d66BY?fuS88*T)N0Kp zWeCM6*Xqp^nsVSK>)YM{qPgXl{Y8LqK^b;XRZL{0EQy`&4)+e>i@zUc&~C0*dhPFe z;>~(&hntVt&(ijbxmY-qbj74SK1K)n3c{>>ZC>r3B7HiG@IM5IAiW$2ul-!-5oHOG z;1@HXoGDz&TdN#u>~anN+T@@V4{?3R~q7$3t=2mgSYa8eZiTRi%V8(_h6~1 zwy7zVJt;k%u>dF%ZB3EN^4`|TDOppJXq170A@`%$o2BJtn>F0al${cjTc53{xyeb1 z(z0n=?qR*6{QNPAbF*Tn!`(t+o+F84YvM#cYyPFq(lUZ*$F#}qg|2$}92H-IkXw6zCJuI;~$Vtg31uFPj3En$}5_vM7AZpX(TV!Q^d}Ob}B6~jQy}cRn1QsU`2~9lLZrxJYmoG8- zu>$mUwr0{1D)4#5AdE?K$^Q3MazYcK6cn3pDUh!JTva?DC^;qh+Bg1zV_h9RVC#53 z?s$H#U^#!TdR~4e;X?1cxn+~DPoT+6NEKKvYirtb#~S3WJv}A4fl$B5dzdA35dI22 zBjI~n5AK&Ou)g7$VVg(NyKz|iVItFEvo(Qms*5W%jv4Q!T*l@mpl$6X^Z~iLz|$=lP{@z9Mc_#m(C-8^%O)sv z!3+I-e@T?c5u|Fs#p$|JI6yke*Qpt%7?7_?$I@ieukn%=dk4_?FAjY=1vq0W0X+blBxO86hi; zd#-#eqA0jWHkJIlptrm3ELYg*zPRG{5fW)b{ju=v*3-2|{etxT-a4(~-Cu4sE3LT5 z`i;Rd?*eeJ3WHvJTzgxY%Qq^x@RQn1Q0gSl@BC8i$pKW)>(Gl`hb>DTS11aW{8o>M zhi8lSU~q+oYxsNiOMD|#J9hf0971q!J)oJ_s;#w$y1U4IRor0d+dXW@(g_c2Z^yr2 zc+6a$^+cyh;7~WJ6h`gqLB96pBGjh|iV#~c2BdSf#hQPNn?a5Lk+KZS?bozM$9xda z@vycECw7NpJ7*!%Yu8Bi-MZX><_IJ9`nw7G@C!)*CNRPWA!X@YrfKt;%gBQA=XeiL zdKsIYNNj}W4vpts-J__Y6-DW}G?ye~nnUJl$wr+J8rg8i zGw3$ce8&vT)|U|O4*b@0*!Q)zVSM1j4Z@P!n+L$p0 zM_*twND&4LVzdYgk=J9b1g7(7eH*Ib6)ACOXUJV6AS^N&DU?X6r7E=8|8hxh`XT$r zuOmEFb=w9LRj|`&G@>=%pARf3UDpQGr%#+{mrt2$b?OCS0mi2h%y3E=pCHhUdFSQI zRdT7|t7V7hW{$sZi%1Y95nacY}d7ilSsR95uW0D=dakf>> z{PV9(dO|SZ*D<^W23MszcND7#LfAZyj!+v68DEP;We0uBwor(KgOr!O>1R(~3kCMu z`R?-5;Yj^qTG~}Rik@f*r1wmIhj#9H(?!ZIpa^E|Jy$WnG$y_OKswg0D0oITMfHB{_&YvYfOD=YPGQ`$6D$m6|=@6U*NFO=1S+Vz%WQpmMKyB%2`{`wq|>H zjE1_}2*1%kFG7o4nd@{7LV0JXAuB+RMhi zR-V1Z!xi763`_QWnHOn8v{@%c(&o|+)Lrpt_=m{frwjAK_OB+WN8WDFr}Fr+hh-X8 z@1MlCViV@-xzxUAtL?5?FBytHA1TVs@6mfER<2r+r?T5>6IKU|toz@O&dHJj;^`!6 z%volbAv_lzd$8t`xy^6-SMm`}>e9l<)#IS-w^K{F_u;m4Ccu&5`vr}S&yPj^&?D5p zGkUCZq{xuFefIhH?Tg?O8Nzx8eJjNM5UwP_(Hm4ma&Xer-0+?_{RzK)V5>2Ku;fF} zlbc}zg{j;Ocd~Cn{KWehr}M~9Z4*A9Hf>7wo=1BqWKS!W3?!8Hqqlt86aNGDB|zX! z7I=oE&YX(lQo-r4fRgpJf4F?rZ>QEIJnl!m3tINT{lGR>S#9y}QD2uQrpzi09M3Tc ze-Erhru$ol*z?c-?wI~9j(E37I6ThVZZv^qJw8HiG}LYm8+md&JN}1-6V5D8gFN3? zr1GPB7x2oUR#*lGa3o)Dju6*MOacNLzYmyiY-a#z_Sv+IgsDE#abHXl`m^;i{j#>R zmeY{zh4ES%A?~OUb&__k!-zCdIX-Qc4k1Iu^<75BgOSgkwQ9Ev&*#6=Ctl7vfYmnG zv2rLjl8R-rQ|r)2AQ30~L1r;)WNb}mJnN#vqF1=zCJWYQQfCSqqjRYTX89F zeWqOWbbA^_$M5Y&5de~3Eq5gI5D%cqNh`tIvx=>$?93`klY4&!lUh%TJX#{CDt|gy z(8+t7v2FL)&CQJ>n%*~1UhUAkuB&pKZh6{OyIK~kMZ^BALz?otkT z?52_YG=fjH)N&I}ZDQ0jkGEDrHADYV#Yh>nfz}1Yegysj>S-qh+`}{uP3>A94r^4# zYgeQm!oHvg^9kbgD)_obPC72l;Q!MU9WXgifVN%_upA}LZkD#mU$-jKe;OIENB)^+ zFUHKjs1ih&uN5YKCDa6z{{WsKKq)$piDp1%&}NfQCYTR^fdR5*Xo2&>JUN`X9M7!Z zpQ&eFSYD`K{;4N;=+RL(SwA@vFc)CmH{vE>)-vLDN3eKUH#xGo(z;4c4hyeREQBLP zDu(m6+b%pboC4o#%H9#!Y@BN9r5iv9rN#qJXwu69R=O! zAaS90uIoZowjv=r_v_}U%mg}PY^PV?T{9v>f2rrq(l+gl{+g{0~pGtH=l zSBmVp$9(u5f^MRY6Y@fRtB&)?(q_uP$E)=$dhYD}RNNr#vG6OXav6Q?Zd>C#IHJFM z$}XNAt4Ta~#bYSGwYeqNezvWSTAtM?KxjUn)oiJ*WKe+gkD4&nUZmU#9PA<%&u&4; z*c#$5Wbyz%mMldR6H$sBi6k8!0ep{7gx#N3=Vp`9|F+rYC7=;KJ7;u&+ zC@(NCITRp^uLDQ0X6EM)LQgf^2eNlVbkLdxW{2WdZ%;v%4y|@0!95cv%~?od28I8C zrr@>b?ZZ=+A>tw~@5Ch05tR<{dCrAs!~5~QipON)Nz%yxY=*#q#al0b>FlR{U%}e} z+Q5n^c(qx&>!)@L24pZ|l1BjSAHr8)Lp~7Ny3O2(bK|JV2uh$|kEl%&coziB@wA!BsU9Vefcm8^U zY!! z?LQc$VpktZ>vPUA#h~e`-k^}{9hW6^J3bB4JmpsA*k4&|sxDr$^o;HRf5X6xolvwA z{d^#YE3eQF{A<1ZyDs~@Nr*(T!6k%bjzY{rWvhz!Ca~RHsTemz>Sx7wmCYp>*Zs2K z)q#=jTi#!76`d)ROM}14A0&1?ibey?vq=+Y1DnV#v&}()cI9sz?qa;BMqM5qG9T>B zfO|I>fHg4N6JFnu`X|sxVEVn+DR?YxPOls@GQ91c(Yn$`0V~zvuG6wcP)ut&s^$i= zwscXfoX35`2v|$k8s9S>CRFbgy~q05WOns_#(8kHHk|pKDW~s7#Lh00$;p>w=?cMJ&TiB^JeVF9u7Q{0?1^>oO8?HwX@FRwS^Fjh7AA3yJObq!i;9eaW{iiAQnbO{ql4@0=u0*=4ELxqqNpZZU{|d z55M>vJdyO3i%eS2CT7_J?%Qv`z!=Pt;5BFp5G7jvki+YgMvt&d#6{hKB@s1}Pj=h|>j(Ga;0|OI$ayMMD@rM2evpg ze12Z`O5nI*XymDVr(@qZU}XFqHwRbewmqJM*Y0M$tb@|7ISzX=T>4}6OepSD=?j$%`MEfN2dt$u|yi;@A1g&htziE%CJT75>xwgCZ)YK zhYh+iyGd&MKX{l-jE-1$s$|lS*3VJu)l!R34Oo+Av_Sf4KOX1w364jgGCyJu<)tTl zAeq7CT$*+r6?V0cv1hKE3+3%s7(M<=bmgW0vxVn%3s6qvloR2urqGd9kVtcEDlwKm zpof3Vz$2HU+V`dYy0Zcu=$u zuT=Wce(E;v?J@qLx}G-g_E}!d&f2?Fl_WJ^(QOh=?*s0wk|_i$B$5i_PG09W6>$}6 zGtw^i&=FSPD11Ud${uh0LnWGsl!{dRX|!CVC=qWLSuI6LaR1eX}rL$eJQiH!CFJ5x}+0%bPDY*`1(Wb2V${bwd8;pjyO z*4I`eoCZ#9zuZ{70&Ff~*MrkX470}=&xYk|guDtk`VK&vRCTU`;Lu(>BCz~To30wg zOYN#E`9M@6ipw2b5}ZK&q{Rt4D|?*zWL0F6gF2}4;UnwsM+-m3e^9 zgKzX$7caGZ`xrUOIi&_Qdh^OvR7o{DK=YhB98d0kMTma%`vOyZzhMYY=GpZW4mIOontn~3|TGn^u8rn^{bY?MP`lQB1cIN zm(V~u1K~zw@HPRVV*O$U9or$XEtBX)0yrym;1I!9$3KQs_0}5dE{e~hydtQ4^TuW^ z8hbQWhjlWUhhN{Y(r!t$Oycw{5yka?=nQ`C(oU(mR;_9PxizG7`E7=Ns2;24;$;2` zWt`osRF<~Clq|H!q-)NOFMo=pL7>aUamk~NPHp)jlw2Q4Jm8ca{Y6A}`l(t>U8zJa&}hcGp=sa7RBbOVcMCoW{!<~!ynh~4&3D3 z!!*f3fw#FlILWgs?l%;^{MnU7);3%92#=ETBw6j#O~sKy`Tb>5JQ^tUbpjJA={a#9 zxXRhLbp-Fu^TlNH2}2dW7R(t5+Tm@i-V-~DD4 zd6DD5-%zQL+uZ~nW_sJ>%#!rk*#{Ac%hA!>rqz+FpeUw8=p3*axE*l0ZPPV>{E!t+ zc$mb~kkwdV2viTd>l+z5I`H>uLlR-*F+M?PKm21i%Y#S^he%{*X5VS3Z8Uf{=jvev zX}|nB{(Hs$wAtP~ZdHbIziqYk+PCj`*Wa_ZR`A5S|E_D=v|%c`U_|r@(~fFd=ph{M zHyaEGI*gG*V{u>chZcgXT1Osm)Yr$L5mQ|wkfWP-{}d(cFXIt zEhf!0n(`H-2Q<88e)Qr|yoF{5qq~k9ldC)rut;dq#MbLvuCHL3T@JOmcZRzD85JGW zITu2f(M_|T%-a(dtt>vkKq*>T&Uts0u^6d6=h=d!!*g7W#rWkV#ksSTgftYLGQzog zwPyaLE4#f2uTF--pj&hweB1dB;?XO6OUApNGMrpERM`ZgW_F|HvxliHxyl@YK z@aIGUhN-p>6V=z={+0rln@6uK=FxkLv?HweM{hQLD{WM+nnWWhe=ZAIqOn>{q)-!;eSbyGLLuWA}O4vws2e+GX&?xZ^rz>*NjW(5yd9~Hku(|~Tv^<@ZUY!0UM1db>- z7nW;WMQCX#nGp8m2>!MI0Sdgsy*>M(Um?jY@LD%V;?-NpgzN#`t!xF7CV({awj>~y{z zN0-UysNR`*6KhX$%#Nij!Lu~H3}=ve^Z&TP@X@0gChho z=3xkx$gjEiMih4gGtOz_*7`J&ZFRx)%uG+ca;o+Dv#a=uxWCViLY5Dcx7j&bh1I^T zY5R(ePN$$-{m{CL)Z=Aaj;Ybni;$EbAqCYuENEl3s0QAenZy1UIPBarNbt!~Y+h0C zJY2Wv6{g4m+LgOuyxjN`txZDGtP*5S**lKEM7Op3?1BbMM@f+lO2+@Sb}7!_M)@R^ zRbV5`+xyvOtDyEJJt*|p$33LkHL^FKCAFn(AV#8;V_ zo(i3q=xZ+~eg2qz!^-5XQw@WEdORol*7r_&+3hP5A);zj##;&fhgl+_*2lh%>CzW~wl8LQQODVSE=7)Nh^IHRwSf&C8*w3tcz*|+d@sEpdqLgX z4v>bY^+sHP`Wg1j-504VZ7ptuglEUkx!X&JE^b!^*A*1^Uhe0$%40+vKuO|KJh>|z zL8IpicEbSSSa7OcL0~ie_o5hII6WWdbh-4#!R_(- zc`ec8p;46{S{0y5l3agIJy!!8x{D911r=Lk7GQ8kkCI-j{Vm%tKIlN}#`WILRiI*c zwL#`?!Onpu=-2mIA_w=8!M}Oc&mL`G-XhECEQy4LyWyv8eU0QHmh)4adiTc7qCJcX zw{LNTn8OY^j>U#FafPYP&{D>LLbm=xkAHQ2r)BND15KtXjYNT4%G1X6*yjqLQn7M% zhI$%biCJ8h)5a4g{J%d$9n~k{OR8`ZGOCKxTFIX?A==p}2pc5A-ZwCcSPW)Q#DiuJ zGC^jzJx$;O)pE_<8rRGqPxg(jn>C8sB8Jx`Ho>Y6#rFFW?(tbj3dCwH0Vn4Nt~12b z6R5$eMl)WBmoiQzzivvZ3CAa}7BsAf9D)oLT7cpoMEG^2&FKsu(FKAGi#X@^1)ZP7 zAh4nIRSTu5W=b2oe40?Pt#=9g-bbmK|DEHJhNnqA3r+L3hzi=XBsK3cl|!3)C9&9wakME7dO_b z`*4(scDmOdGf%VPr$=A7^AjAGhOaATL7(z`SyY4O{hqHXW&0f|B{Yv@x*C6s0$DZP z|NG_HP@2Wuu(K(T(5%=%E&E0|+TfCO01fpWm*AKy=TNxfkZfA#s9xu?kzs-zm&J~@ z>Gx)rzTj&pyQBIX_Ez^SSSS{@8KDV|spy>I zMpV+>J+;Z-WO%Slx_${tDCRGP?uxcAv-i(ZiD&VsIvVn`2-$n-&v~3mV81`euBZP! z5^Hmc$n=BA6QCf|M)=|7^*vOo@Ph~F{8O0Oj~NV7ksoi7U9!ff`B!4*$XrC?={jZ_ zL-$QMY7WezFl$M3+e>2i8wg0v2|lH~`dhk(S~E!UF3kJd+E;?R`3KZKFKBB%ZRw6M z5T}6hY2HxApg-)_eNR_N!qhlwe8CgqK)E8s)#iuG*f6C;_v)^ry{@kXpY?7bf4 zWQhAqa!p~@>06X1fH4g)(d4L4?STIH?rE@iyH1}A_8Ii!bzJ8E<)ijFs7vYmRoBjq#?0sURQMM?S#+z6qv}(kyZM(@&K6M;tlcxkx$(eV-<#Q3NI41Tgo&oEpPj#>Vup zSyt8G0YT@;w;G-VN0aRxr7``V+F=UD1FWie^D=d1FzEz&muz@{yqC-2ULa~=8AM5) z(GNaA442fPD`26e6o=Cafe`;+GyorcvW zr_{ei;~RUvu4vxsGsGa&m1o$c%Rz3r+aV#NeL3&551~YnV z!SM>XPXa7E5&bDM^_5|EwaI|27KcKVV=j_)<3{B?-Rt Oc`v0TSs`xx<^KR0K&v7E literal 43015 zcmb5WRajh2)Fs?VfZ!I~0>Rx~f+n~IcL?t85ZocSySux)LvVK*ch@=Z{PW%XH}gzg zG);5rP^W6^+G}^HysQKgJRUp<1VZ}xLsSt2g8TylLAb#|0-pphu6+W5NI*YDzbm_@ zpJuqYVh(%^ZMJ#5{qqpUgBGUgaQQA8vyrbM6!zsiDr!t+@heE-iZ&>UR4krU#ytTG zG63D&7xUlh{>sML`}@)!*Iy~Q=78~&?d|2Xm(y{R1CE=GBh0BA5>z;7NIyNK!_p8o zGJ%SnSeyowH|=x+0s@@a+RLVqq|F4X<6nGVK;_4^O?6}w!?f$2ilaSYR~W#&oYI`q zTy{F_P>cq5STvQ-c6J(JvDnTmC+F8qCTq_xQ}YQiqBAAR)1541J$V0TN(nk{Ar*~+ z$!(0XxKdj=VSi2CqIqkvmRXGgj@ov|9c2`$8A(;Y9lb4}# z$ZY;g3dmKq<9y66^7!fb*>&*>C97JmE)&-Gq4y0Z_N;K3tizIAvZ-5r^#bbgqVJx8 zfdM4kzNQ5XZGP_`@(@2dA9KRP5y%t|__%HtEG8_;Bl2|9)H2X~Io>uo+t^(inp~Wn zZ_775-=jRppQfBHZ!is5QO@?vcK=4_RrJ?vbhoczZFhZrxHqwJcCKl#v%M!|21lby zRZw|^zhkQ)?+@GTtuU@|n9mj4xoXRKgyo7VPVMZ1Z?86G+*yZ*#)ekM%5-)gu&owu z_NjejvzqlR-8=Ho*&cEjC@-cATIxLV=rklD+tzRYPaJGKgC*Q^bb#$$y zl*~$45i{19nTNp(52@*748QfZE6T4 zhi$%U4UAVQ*ug}B-QM3*=<{Hr=>^^c3He@MraWQ_z-|KIk-#RAj8yOIs*%py{jQoU zpG#ia9TmE=Fx`9S80xM8J`}zw&bn9-oZE-iRSM~xeLzu3eit|7HaRra;~v=SpK%r} zYRSK}&gK^5{TXTcsT(I_Qj;!sh^NQak#v#Hv1nvGvZQC4wxi1ZSL1O12u1Tvm9`RB2vFtsyRttv1mnj zF~4il1*2bUhCm@~R-EL5gk}sL++|Fx+ZCi=TTeegTC6XGtQS+*Bd;>|1@u0$CS%jT zpE``M>yp8K;HS06Vg3(-39Jn~xByZT7U|*!O!_|cB6#IZiuU~RBovnL5QYoqJcb(I z*Zw2Kfh9rz*+ANX@Q;?s{ed`nYup33_mSBB_w$NI36o2{ETSy+h>zA&2axsN!AOM8 z7nODbEHmBm53JFg{#PtggD3aIUB{Nv)AD)*Udm7-?}2{C*C^F-@1b&71nH*uoYzS6 zPa?WwQ;caIeU3KFQ&3Yk$Nj|}FHvArTnbEtSbgD&f@(x?B$CuA&$#u`!bL@u!C!XY ztNW4)FMJQ5J1*GnuugA5loU5Ibts_>#}jZ1#s*G9-ec5x5d78Pp`))4rkm|#uwj(( zQP?Ru*ip_=Ttbt(yJ)TJcD}!JU`PwmrE$uf_h@_ppAsgR2XtvOEeh9k*wx=S@p4D_ z9Qnj?VD|g>PQ?J(3)D1zSh~GRyw}w`Hbb!e-b2U8MLUNJFRjwj3b)&m6mF;s^A)g8 z&*j06kKus_Rwt0MT@vM;CK}5@QZ6auKVpr}^6fBN zcjxm3ca&hMacn;!5;fegKaog>oZ$v)Cod`rY;hN}eUD0Tz=?Fos+- zc7%+JQ;JU@_-WGv8XN8c1Fi4IQx2tIu4jasxJ0CE=WQ`R)8l1coF%By$>wq70agsN zz?M*LoK{-lUhE0b!?32NkZ5ISApUgNDQ46X|G41;7M#Sa^wBK5P_v4D5vnkyPjlH-MNZ z$oXHm91aj%sSuii%8Yu@x5@nt<3#`Q5SUaqk_99|he1w(-{eTtkiu9fD6Z2uLJy`E z4-Woi@ceWoDw0(>a5y>)d4H?1&QMS7zClP7ebSAYhYCQadJ_@eID>;0j_h_lOLaci zDiJq?w!O~Bih&>yn@La%jl}hTd8n~BzWU{6*r&3NNI553>3x?PP>54vwaXylvOYrd z7MXDQhz{IizRzZT)Qk;%i;n~r9NSnJ~Lw znGz){x!7c_83@)DLZcfd1ok-o{ZShed#Dx&%s9hp31E24n>P#BkJJ26H*#zQw=^+8ZLN#Zj=}z3`5`uDtF!x19 zUP$8Q2@|$u^0~+)ihnkcW*V<6yX{UgxQNLxg zc>toWMty8|Twf6l`V9DLd5>)f&2G3oNC?n+F&Zq0OTO@vC}tosVRJE6CKwmQCs;Hm zGWI{$=D2Q9bbUwk{frctM+UOP&CQ;!z{ma~hL6YwKRH5!M%oA5QmB}&8P$V2K`xq} zeRo`mP!9#ikHGi-hSj_QB*`l*t>F6RbiTr_Q2;qw-os?I`Mp>rzo>|kl2Vlk-NwcS zA3sg=MS!qxsM?8x&SM(6{9xA~SyXhM?~S7Sq8ql`OdB&W;BNUcqdKoR(y zvI!F!t67R)_uZ()j6uu3bhP2Krt*?N2-1E9<8p$P@fR{)!vFgMQr8*|V$f6KuP9bT zGIW(&qzGg6C|b1{E*>7)6qbTN%osZEk}cNBoJQ}RM^kMc*b|$$_-HkQU2oZyNXa2B zHc`6mQ(X_^VurAhr<(-bcO5?IKBah^*69x?bztP{UA4RQVKTvrRkG4qa8E~3!B0b#ax%sp>DhpKe_!#X1c z)yPUhQj9_@)X!1Kz-G$C*bQXiTQl%+_y>ma+q7yWs9=7p_arD3vFqDfhX*G$_2=%R z*`mC>yg;EK{ey`#)upA$Nm;I=98x~7XXU&ZOgL#dIo(drmLtQVC_)ht5s0}8%_iB5 z>#BaTcB6Q+mne(PdP~0Dzw%1^gJ%}ld?b16b7?PF%S=-f*}$T%BBT^_Ik5#c)>*#U z_DAXX@V^#yb&X^X{4K*S;zSp~bGoW?Z+O0UT^SrQ%R8nD>>guHt5>sc5UO~*eZ|kT zx=*MorQ1?@GGKCPgHfn6!U0jyAnSoZnN)%0omVio?gRo6|8NAQ@?+fgZTx-Cm;Pi##FeFrG|qC( zCS;-Y9)yMcx}#_x_`OV4BO4u_2B|t2XZxBT=Gb$!FMmROB7eg~-y;@K!-L42_kqA_ zo84d6%$yM;6qCWL=v7_P2U_i}LyQ>70#jasp%6E;)_b;6>Z4OhdSmtNB5|M!UG{_H zIr4sEvXQiId6=c>*T5I!`5WkA=pEnw-XfAOg%T*%hw=zu@&wUs-Vnq^WqW)3L`Gc! z`@P{{6yo0|CMS+O79Pq3c##ymyf14l4rCHh5g{Sfjl9sbO31hig;^)3G%i+m-hVet zXUek?>q0`V!JDcIEa|q# z7vvY8AdATo9Nipxv1bLX_ectG(?oDJdPwe`MF;==!PVGvrIz@hOM5Q5;Bd;JnxX9z zd}20u3({4Mx>&^&S{f#n;aItq!e6Yy{`>N9!f6&}zLYZ+@Y#?j@MYdYup#~(ZY}C? zJS0O0|7!bMrOfC3y(|-nkV?FhRz^vAgMPG{#@ioB1Qsdz_N5YvGKzS)^F3IhYOac6 zLKx~YAQ#<_PDndKP`eFJ;Q5FAoS0~k1$`W)T&L?*ZbJtZibNDa3a?9LLkEdkoc-|S ziBmjCBP#Pv-jIrP5)93FzIg@GS#{oA%dSQwcApRaZ7EIs374a&UY+Jou2C}hDfx~N zbo;?RRS>bd2|BF3^M+szw@%~YZD975%d%-a&)6X7rUYlE!orV)8r{9yRPAG#AH6ak z9A~i)HXOmyKU-d}E5=a~YwPn+49fDePdPz$zgFIc0yA|P9!rfK z4|b&lhv_RC#=ULtyZtaXiaW5~j7E0YC8HM?9&Q*VG(tl|L32M(pi;-nlNZS`u4I#K zx2LxZ^;(Z}N~N2oqC#T19glK6ZMV9ilt?zsp>5s3r^Od24^(;|Lk+{Enpz>wrZW~5}0q3 zzEb|=E+pXYcppoa`|8yIuV=cR>i(eJ{vm)=PQ9*^KrU?5Tu6!)ZnM^WHOAN_oh7h7 zGBVQB^Swk_W3_~IWOP)qM46eH*5^(3CZ?VAitB??J?fDytBm5f}JI8Me5!^QP}mRd2ntU-|7Yuf$=M6Fx?%^<@TI zpw+#xTwoPey5+se^q>|g_~V(MU1AJDlEXo9a{%n@HB(q#qryp0HX8XG5rJ5sNSz=F;dru8Ar_9c zaL*7e5{#_fV*klkqhi6l!Ozbxjnn3UtFrqKDrAmmuT?+j*ip0kJ~DE*^U%Sf_f1c% z=eVrg;V;rLzApddJ(0l3PE*9(1^B~D-8z^SO;*>|I6Ks~;4y0KbsUye#}^-^$qPMW z?7ZE>+SlYA-=`{*c;d0O{K|AzHjC5o_2rSWS7I_-&fRrC4q4lU-W@@At)w|CgVzO% z17+Jyha#>-nPz);B#tt?>q;;T-sWFGV@(cdn;4dWP}8@m5<|lul(g@wBPt zQXUVPgC?&%=eLl2CNGqtT!~%LG&#T5hox~YTE5>6z z($YnE+^KBLtL$y-8=8O*4-dDts;$>~a{Q-_(i0OC)6-vvh<#og3}LY`@{%O|b=(RJ z!ISWT!W3~MMl3=4L?*^9Ko|=PeM$2LB_ARR1SRiF9D|9ucfV@$j79I*?UpT9z;H{> z^7?n{?7x9T!uPt&;*&SiY`I+9J80g(!^zoX>zY#C)Rgq&TObst&4yM_a=71U7Vl`> z-FX9OBc{b`>^xb@48&o%bhui$NsDx5EX&^*0f%#W6Qi5vz3K5NFZY?S!{wwv8Oit7 z!egPTOE%mR7LnN0qO&x4@$A_U-?v_>jnlf-e6Ga6M(q7<)n-wt8HH1{GB=N(X_p!*daDBcUSxb!zn=RZOwv7w4mouq@PM=l$u**%1)O z`#pGT8|q8^`vv`<;5O$B`}4)CWzFmKM(eD1-q-ah6Sk5(R|2o|sfsq@{pvTLi_67J z5UA?C^(JB0in89)R`0Z#K?Z-=_3ms~iT8c!jY?wEOw!?dkPY$D`{wLgKI=$fIYdlb zqvuVeyb?{p73Ee&&G;*=O@IsG$GwHU)xQy+Mx7tmE=f#R!QM}aHrGe_%;@lzvbV&% zjQBSnd~s9n4LZl4eX&+i@R@~3=~DJxGr?VFgq|L2@jdIBZ8XjJlrH0ZS(uOax&@4T zRC-RPhZ4Ll92V2rqJ}2_4e-|1mVRH*L@KMvKgz7;mR784GsNOO`$9Xz_dz81ACHfQ z>plKNF6UIBl&mbz3mt7eJ!D(LL!F}pIk$tqD!$lRJ7bbXvKgaZHnOs^o`Ex_bXAH} zXn8YB1yV`&Yo-a5iSl3K?F;L9o=~XYq-9PXrZm0s$9R+^XmY6z(kPetrckckt$#s_ zjk)9(PwdWswQ8|ve#01;RQaBZP*{F2_88?!YFTAsfy8%Wwfc98cSgLgE0+FgkS$&^ z%5bFd?tiAAph7k_by_yDO6EgZPorm!j#SyqU~Uag@=wpjQSFNHGc2?g^nT%nnqRjm zia@S9VaTD@D8IB?vRvv8Q?t1lQesp}xyi1c!?-E!v)#q*&`{(!8 z4c_$3TQEoP9I#98(VITGlpk@!xJKx$Am=wosU%aC19~B2=2nNJAueI!M!Q za}k8DCnECH(yG)VLV2Z+dsF-z2SyNhGQzG%l>|>_SR8s9M(wsboj9K^)v&CSzgoo& z-R);fx0#~Befp7CyxYC5QYPSiLf@ig&4d%9%RS9z#iQ1%m5c=A|Kpn?6=vD5isvnV z6d*8j&E)K0w&jysT{c#VA6jo~eY&aRuo398%j+2_*?)cV{&>x^Swh9drS9fYRegz% zkEXq!!`cul+rvnl3x#bBb`LW~?hsrxuwQxg8gi_d>U{mRXj>qc5I+OXkfZ#q$DN&dn_+XsfN%zF$@KPp2RC~56=x}dasGXzp&I~TYwEAdGmSvbB(-#B%B3a>RO3etCXEI<2kH}G1qu+jqP@TT35IYZ#WQ3n6C{mUQnVOU zsW9OS{;oDi?VU#K8F@L@r|RQ*-^eU=eH`;ROaJ&Wj1~G90&VLvTiKt}cs{X{wlrMT z!gdCXS^h%H?(v;ORmSG@zkJnC=pc|7bKzxIV!Nj6U8dM>)sS=>V()h$-4I9^QZc1_|%8kDfPP7yU)EK<6h@3C3AyY&3=Rml6Mu0H8Y zYnz#?p=w^BY;UndiYWG3!sU9<#G@R?O-tqI#=)8?P*dx>&CKJOibQUs=REhE+ecUv zWUD4u&V@0#O?D<*6vSSWZ>%oef^)DCNj&cS6>;OkY3(@pOp=+_7h*U;(h3v)yYVMr zd!KUy&rK5~6XN3H($dQ2&D9h4-E>G}r`hOD8%0S0&yK^&VVk~SI!C})e7Z2v?B1Y3 z`uT?xD>4C&$CLeU)58k48`rQ_0h38Xp-;_F=iO0~6$Mg>+h#pc7j%Nf?4~I6KED(* zP74sC)^-tFV100`;I*a)t@`)oua=+F`z;(K8W;pL!Uwel9=o{gx{FbY7`5-6)<$$k z6Y}uJ>p~r-46V9!2t<892P8qc?Pl^fy_L-;Rx{Pc|Nf-sM^K{tHEEWOKK4hxVu>0Z zR%$P%SPDX&e1_yVbbX4XX-F*b@B+n>X|js?x;U+NQ|Nv^VwbC2n_pOqMN|G{5`Xd8 zLe#54JcRZRZ!1kME3J1xdg@7MWv`AVnYfLDV!6ZFZc*l_nQ~c4Z97pF$Jw>4wmqk( zv{2W51&i$R^PPT9`)KiZ#9m}pSoA{f)gN)WU>8%8FC&^L>MSOGGxqz3#@P#DG1R-t zU(3(%{4VW#Pcki!=j=i^#}64LKIW!B@UxG zupADzQtp=&$y65F)4J(oO zoKeJrokp|f5pMSr3C%(8JJ7;+0e_z(1l-L1mZ+(1H-nkeB9=AanSK*$J{(0p7|N~u zFn!xyAJd3NkzM0CysY`Mk;mI;AIGFSpI{Bo@3i!NFg{(#_$E0Q(RX7emJ=`Vt3K#Y zvm$1}>`_2#Z#(Dm^$Js)Krg6uZGV;OKK>X2!LrOpSF*J{eGmcUu(4Z`g z(1&AWX5>15^~FVp$Hk*wgDyTbNCR!n$M-l36YtH8}#(bIO zyf?7k*Ed)y@o>)E%i7u>21!_0SS^tqFA^q0_FJ5S5a}iKB@BUI7i}IX&Fb&O`RcC* zI>xFZ5Adcx&FIFG5Hi7rvS&ISPFZ1bf%V?naC;GhWSTx3UZj$Y&Ny7|I~Em?RAK*0 zSmaJOY9IEDV;#CfW-c1xuGN}tx6`>D0yHNx`O9WZH5$wtUdvkE&t;3MhMw8aUd7wC zW?|o3@zRz%FQ&iq^DKoNmIt)?SZ%sLuaG^sM{eTr=jT+t0Ld<^VcrFQSl1iZ`~c-) z2Fj4JVEccdgl3a9Hy2j~0e3C1>&BzVbZ_Mc4r66!(Xu3Sj{TK=xW65`GPGz7 zcL}bJ`Dt2o#b?8YcjwMObt74zC~w-JLH~D*I#l%StZC)$WF0N*UJn=&J!Qt9^X^Qf;NSIS!Jt56WX+8-gYos(KB+bD<&5i;5JOhzl&WBen z6OXxIht4PK9!$eMny;60r9V%sB@2BTPES%U2p>1=*_mN|y~Lta)N_zPbBqd(DP53jgxUnzJ6e$SU? z?M1qOG#>|VXRH-YXeY$x{kMm`XV|MKZXZ4$FLsXDNzsFhW~+@>P1fs)bn3NkHwP?c z)uFu;1~*kdc9VsQxmtraE6%3$c3gP`oi#Rtlwi-&*Z`jXPE3DTq-s9Tc zL+uXl-47dYqHg@PB)JlqpH^oqcpaIH2z3{0c4wrh3oqC9;@9Ghl=xNS)tTX%{y97M z)|-HO1L*W&62>M$zm9YLmY5(}pwUfqIC3)sLV$(>(`Y@ZStBhTN=~q8 z=!wAwge$fxP*=2`eQXfiOu|ACA^Y~N&UWz$*g^Qtdst7tIHWXHKv$n|S`NoLyj;0Y zS1Q$v-6LMhhip$T)p_scl3Jqg@jfOD+T-16+?~*N%ro>$h}y|!Mu}_x>vQcaDCGPf zF2M4pNAwfFC549E3E^mHR4_Pf%{J4(n1osyIdVQj91xa)s&mXu2Mg2{QXeSDW^aTUk@`9~zzN z&(OVN5U_hp5n2?xZaQW2@Q`$`XMlT$V+HBIAnSK08>>hDLa0$IRc`Gc*bfM{u-UlP zYE`zoHC?$qiUJ|=!Pp-!PF3n|CMWD4og?dOq6DD@C7Pvj;6s7cHkL_uBBPgUhm zp-p4LLEkGVS6%<&WgPh)JfCw-KeS~{-pX&_TBLsBU1#DXD?J%Czlq=%N6~pdpR^f8 zJfl=7wb63p`0&sL$z1_Qo_vbA{!q$h2^=_->p!E*TIVlfM3-I%%J0iZS zrv}7b2R>H~T9@_VY{QqTk&sSL=cQyhI*p*_l{b$km_DX+YwO9$Nh~YL(4WTPss=Io zhLGC@;;?(8M(`=pIB)DYh=nCH2fqtvgu)8BQ-h=_ysrcBm~%gB3=Lw32iCRujU^GY zLFqun0EzE;3re;EX6O?POqeL?S0EFjl0G$1|3!*rAxbI^z^yoAH$IB-IB-z*zU!Ft zOZ>yjX$2cls4Ffjm}%N3lSHf`@iuaA zt;W^ZzN!*ajsiCq%Ssa8kezhADky#JHa(jjF5X}t2A0~MB2qisE88N4b8rMan^7I~ z^s0ScKuLC|s0E}OsRbywqR+^4fx@N@;lAyJ<$7ap5FHeB|q zGI({p?&je~nIyH_MI(UN4+koSEMYWXF{e)*)o`0#TaAbAbsIlYJQLi*6fY`lVmv}2 z(>s~*ubK(g#KcQOL)gH8p-&z@Fj#Wn%99}G_P8uPI$ABy?%~SL#f1}z5(@RNp8BtT zCZ3w57{)#j%+)JH7&_EfA%<%IT$rSe-jZJZxl*FM3W0=j6}}QHSi;2UZrIn4}&zdqfh2vv&O z8=k6Vovn79o~@s6`atI^D&G!9@^v5GX}3C}HMU~1Wfq#n{)kUZyx$v%E22@EY`f@8 zjaB$~f^}gOV~1(?W9=r>Gy05S?^jFYsAg5NwX-7GGbdy2BnO8@{kxJKs0@b6`%2Oz z{QM?-qq>Bpu_U3fBpYt5PBvs`z)U3AXtw-MKtPAtx%_d6*kLMb3I-V(hG?^O{`^?w zA)BOWX-SI&s`=%ph$nM#|KR!MMXEqCEH|J-AmAo7AgG~750$5&MVR64;HgZAW}4s< z@>fz#Z%Ge}rPB|oGI9Cr=u{!V_1YV;g#P#@tp})EIxdXAA3IJx!O-AfD>9)uG1}L# zP<@lh@lWVbP$(5zEfrRpQ%Xh0{O)@+v4@d^Y9y6%S>?YcvS+CiMlUaIfshR=93nYi zyKEj(PdzcmtU_%Z$^k)zqQmW-PcOUJwuUP^VwqY!h&pVg&B#-P5jLn0;;@dfYo1+; zI@T4s@#9XhbmVv65dWDmde!tfEc$$*2dg#1uT~_Z8>cYN-%a&R>uJBJX)`MjXSVPH zo=6QXUW7?dN9EYWW`v@oDX>Dnp?~gULJt)M76N2KfAn!QC=6Lx-+-!u_YK8jQ-`P*L?cRD3VKslZO;Wu^ zO+ZY)W-aUwq^S^it9w6dI(y!{L8GEt9d@i1CX-V!UT(4SFTG~OM5>*-x~j+RQmcWO zr9Vu&c%HOWn%i;w4LEB|wbB!DZ)IiU^;StlHcGqz9vS&JjyRAVd&mFm){!pv>9Lc&a`Z~jYql-8(%B72=$9-1|lV_JZ8FabdVzi`m zJw86XTPn$Tdu_K?*GpS!;DDIPJ#aVtGPD!N=h;Z}N2mgAC9H#-YAq%e5p+~yTG)M(bI408C z?`Q%9LZQ$e!x_!M$_h92z)dGT`p6NMDT0&*Jt}H$FcPy{vY=ggbj--=^mK)YYpdD0 zVtZCD>-XRE%DB~vy$B$y6i zi0ntAbsat*=T(k8#bx*9TC#%aa2B~4jsG7`z!BKhc3r)Y&0qg&HMI5TC0AyH<1SiZ zRyAUS%jc%JmO_>PtBRXUaJ$qzCSuFusZ8@yZx1fn0UrYR_R$*skLT7dQkA=_585ps zs2v+wJV2&y+Zdq$|F_jt9hkfP1wHb(XA#!vm0ACLW``J$s~=il*Uycicv@Tb6O@ZB zSnMP)kKe}&D!^1k-T8!#-Q2np8~`T8e66|b?(HZTWgpt9vvysBYU`x?+9fuqH}c-W zG%dXm`2yQF@F@Zs^q28qp9&1I;f~aZ&h`BD*MnyS=1K%)+29iaXu5EB!rHbWxQ>h3E_1Pb-yR1@#O)ephIWME}f}F zi4Kbv6FwGz|3ZPp@bC_%;4j0^Ac)(oCsqXP-#Tr-dKXqfqhI@WQ3%fezG@b?{i~Y5 z8Nr_l@(W(qJua*!tb<5H_Eg)#8rs5*vwWzidD-F5GDy8&@#ia9#}rkg+!scn^N1y?!`f;CdabmbXPw9P#D}vZi61iFl^D$vazA7~`KEpT zAtNRUFL3Y9(0kU{oDjq+XlQq&L8{cMe}+Mqre*IP-ka+s%I1npfCA!oAz{ZQKmb|O z$ELzhhD23uCzQC}Vz!ZO(bD69-=I*(W=63-r0uDv<3$|a~>Ab-y>f6`f(YmBU z_kZCK4Hr@Yh!c9~IOhrA9DyvcY$pHytjyjHtzHJY`KCQddT=5+w#}6p;gt~G-fmlX zx*pK`>sv$w1Pt+{Pj_FCh2lqy3~G`K&HQ`xHdr{S%XZL-da0sXhvu`j1MG5)f33|u;46a|dBeTWGjZ$X)V-2>1>s>>PV?)9N z;%UBi1-?-aZYXmFUgT1(4SyfLNvKyqh$Vo4*y8RcQc~S|n*_zU<6g-11qR2A2|+a3 z2xe80juu^BC>phV=^+erCrz@+WYX`Zt%8PyMUWh~OE+6Yj@l)OC1Ia;S)glEDx&g* zRqF<6*{pJy?+tfF6X4FZH7OJ!z{A7C!J!T&#QMnQqWb%mG!{`wQp6E**$UCc5_~*t z26lbCW16aLtmIwZ6RHTbMdeb3CCY|`yta&{_P%OmrpoCH6t^fR(AeG0=z(%_atvx7 zPnYWeasg10y=cFYO=8e4KU0ncDsuZFGI)O^@)06L)h&ALs696tEzjum#@`%u-a;A0YUk_OvH?;lt5Cj zBLcRzKv93D`d8T(qb0}j>gh;C--pYP)pm8Kmqzz}$;gU|l^Ny+SwaB+{Zp9ptBr>T zi2YVqR*oHcZfLZVZ;VR`0y=p64QkAI=@X5S?75NR8QKa8?2VfH*YC?xu?zd>!vMq# z7y$4Aq1I%rEh-A_J3T!Olusa0IRd?VE|6#v%r7=f`g9kobbW3Q(R_hYn3$+2oZL>RH()Jj~p&+`%0$DdiDVOwda18T+SVJzO z0KuP}7t~`ICv=YT-i?<>6NlJ)eO6m)0uxR=3d#-kCd;_gAyamyfy*bp`U zO5N=*;bT%#p95Pww(!CzFM5k2p6ClbQm2+wsz{6KB~o`!EOztRP7C1-#X@ zCS9RNm92Yo^@DN)^01}XHU1C@-o$`&6i4{@O9By;viRI?w;*hosJJHwW@Z+Lio9O# zadB~b3km)lrrKPS6<65`VNBfsh!WUM{~oJs)=rW7Q+(x-jz$=lP4jT*)O>Qwf^)Yd zT=Z_U-R@u{J}e0j4-W@Nqgxw4%_vvt@;iTISiZ=OtO7O#TSG-4-zd&)h zNRD`R2$=Nr@}kO=LzBxU!GTsjS^L3chm-0ma{9-m%h!~Xpd%(Nf-zd;nYxuT06yF3 zkP`+B26YFBgXEj2iFA7Mu|QkcK@u}KxA;WfVLCa(2i?OnIlL58)C}7AjJGO6t*DIx zrUl=po7}cFb%utLt}6qN#LhZ<&TBx`7VOUtgXmu@PqL@<0;oY-ggsdlt~h}x_<}b> zq{l{cNS{EQE~j152i|JyNZ&VxWvE%YKTHmy$?xJxjOOsf_Czh=gdNCvU2)lf9y?L zgwbW?dMD+MR#4%PNRgt=)GO0``OTPiL2l_ijBdi#YZ}iYEuy6EPhKObiX{3rnSs;2l3KM}0N5J`1&D`94E{?LU>w`$B zuapSCl9arRhe|#fMY#sdDC4!>0B~Kj+pv(a!)gZKp1%Z8G5g7raY-rM`C695!x+`J za}O6TRGZZ%WDgbMYGR6g-bU<$`$rr5!`{Kci6`U8W>c#!#S_|z6ECvYytsXVNvs4{ zT)%vLU9of)#&mywz|>ZzXAZM*hc16-w&GW+L~G&afYd*js1VEcE$A_0`@NnACKv$u zVWM96U8?b@T{uUkeDP$!pytSVHmmE$H&8XZNrdq;f3k(YETp!^n4I%>I;^FX9_1H-pR(C&3yFva-Y!&zsIIFk6|k{PG@# zkX}GB#|q>Bed$DmD@)CED^*sJMIF8f7ruxi#Q+0ZjWiaHh9UjD+my|L+T5F5#emTt zF;1MRRDx`YAP)c2hTgczw_n8M;uCJOq^Rbsh}ks_4GJ{IEVyH}z3KtIL~1;&dJ9eC zOcDP6{&jVA0C`fHBJRhx#>PhX4gmpy4Lzph@FwA$>Y5s0;+OD&KQsu0>*9H_#z1;R zw*(Fw7)U>tN7jMCrGQIz=~Y`z;tO-9EEXVwSB`VR21vh%n0nBek_9U-4^y%kshqj- zf;e>J|8mFi`=1CW3tMN##%LMHcE^mzYHMpvQ-5FEjAQJ+mj0xO<6c@_U0w!o?IqyH z@+vP6SFx{U)GVZVO1b?a9U3k}3ZBAuY;wy572|NE9djv}t2m+J3?oSI?(+&wYF{YC zr;i(7v@HmtEvnHU3cZ04LhlWif>dFjOv6~xZYQD@hdIe_##d?Un{8{vVZsk(C>lc-cudsK6D5KnI3erCzAO4 z2j3JzU0ndRX8O-e2#`4m#5BaaFJd+XObisF5Jc{)KW56So#~BFt|u!$DvFV^PG<;W zm!+~uLm9OsK%p+>J}d1+#+6Y}6oUBy;wBmSpoGkST3qfPAH4|}X4)2$S6WHk(*_WY zeM|RkcA*p$o^Pn5GVH1bq}|Yv+XEs-$?}1iI;EojbwoM*C}P_VRDARBD(ebn#F%gM z2@rBc16m~7xk^9a?Cu^ejsLWtp_+dUlwZ@!WAP=YNYZ7SPsP8@dVw)S_=jSh9Qyt$NSsd++1(s zoToV!F9HY)q8o@wuo*QXo{|S9bIn?f#}W?)ot>Qlu2!X};Oy+|R64gI(ciy+uYnjP z_w=S+8yYT+adPU0n~iO5aBy&~Rw9}RJv6`ewcT!49HI)aesQs}`ZKQgr_133;q-~e z=fB$~=z%7Q)dmYyby-L*&&O)pE|6U53~iob}LQv z!GsV@0xTCcqYhis)aWRW({a2lAs*f_Fb)nDiWTw{pGy```nh zf{bjv-r6Ac1l?^15PQM0nS3L)mO$hW!DjZae`cnJpi(#nsm>)3-6kSBy2}BKJXT97 zm+9!>V6oZhb#pL5uThwvuhr@KbbB=GbUgPN9v*H-)7Z+1~SF%}eod>q{ zSA_-;TWHp|13`_?$J>8g;6j-+9&T-<|@1`u#6k| zqpQ2S^YL7XP?z14mYBDTBloMcq$H2S0pLtTf)I0#z`s$xef#zbkm|R$w=;O0Xqw_a zz0ui}05yy|K;QsIJHy(nEx;NdiY5jMSUgNj)r#rmA!V>AL=lmZglwj$X1G8TB*G;l zyHpYbAbpOX$e0<)FT2~Xu{GS?pOcvl;e#c_#TnG9v)5*R@$h7vXSi&POia+D3RofZ~R8Xs6dwn zF>#jtqq<#$xS^KT8W4Cy5%MO+#~aNYWcj==clmq(a%*L2nVykBOTJ#4XbvP8!1Awl zhi3o%yLImn^9L?#`R)%hk;dub;1D;qZ|qc3Z1&ICo}HTdXW4wEW>b{$GGyKXP~joD zydJv@K_lbiuPS_CE-8PvSWj)anfqm@*UR~O8)Z90z16DoI!uTNH|bB7`S$Hamf;u3W2BB_%02AZ{h+J`Tajp0dpt}c(u?rDOo+bf^voR{&GId+*3v4se(loQJR?1YX zE-x=x#3~n0k{ETZiAd2yrAwEAPhB?Lif(I=2zlll-@sWunF3yTps`vCLUcGJpzPD; zlJW{&4cLMHe$g9LfaIrt%gM**Ig=|^5HSR(t8%7B#jh9w5MXaSzoPp3LBVpEPG?KY z0tEdJAR|2Z3cz0gvALND*u1JL8|pmsjrJC^Ty;ms+eCWJfRp-qwy0g{-)u5+X&e>O zvXIS=NB?5UB*sN7EiD6nH;Ix`d+DPC-AJ+(G5QWvVSq_dRM-Sg>!B#in?@-BIE}F5 zH9!`=+|2`Y%&}ui-=+=sv9Yl-1KBU46megaGI^a(xf~DWQ%LI@8Y;rB|AQqCMz9A> z*}NatU5q2E0ot*s1z@2DN}O1<_y8eikf6O8z#t;hS@_kag2U%p-Jnf{8>IhxJXzn0 z5oqP2548OK^Z&)SX?efDzgz&Qh2|>4iS6zn()Lc8O(*rx8K8AFuG#rw3_$M+Aa@}l zA@%k3_W5GK&F51zn)E`!Pxz{20Nrko3LgHmQ+bu7>@#R?4k~a6 z8UGGrMhfFiZxO9Whf0lHT~~n5tm7`(`ZgEwyYpZl_}je*2?$&>!+mUDW@Zs3I4`oF zJE?zOu>|^ORIu#-EKRGDI_>Zva)L6F-tRi6(`>XHji*i^vN9W5oCCq`Et`ZBc6B^HfcL?`ttR*9tT;e-wr_a_ygJ>O zx$+UG&H4-;RhPTp#<@yu9S#svwEr;Iwg6fay!$qJvAqPhw zeqgA0bz(G`woz+fyS~q(bgA-Ya`%-iX!UeGiR#0)ul?6(rQ-lJ{^_b#jm+SxtBlGC zR`I%Q19XwzJgJw3cP|z)*0cE>pN;l;{6>}UqoD5p&DS&s+VFHL zW~x@5NXb}l9yd1cUp<@vS5-*#2T=E-{QQXb!|)+FCAs%H@7HnTpGPS#F4jB_?+m_K zjjw6(sqUs@(H;zZ0M@XuG~!^0F}ri2t6u9!=u6)g4G`=IrZq($ z4?eWU98b0)&{#pohs(-xYls>G~H;J%foU6LGLIQaTkfi|L77r9?u)Zfpxe|KV zhIDea{8Hub)uZIp=48d0ZF6Dj!`N4HUToz9;pbd4ok^lMZ_yw<(Gv#%lP@%64 z1!vA<*jIqhhU@(>2*|o{@rBBw6 zh{p-JFJ#`Sq^gPVa(?~zb~0U4q7mZKsm^B2#WTy+CTbqQvs)C8;;#CxVJGWaVa~Yf z$|M$1%BZk0yP+^qv&K3$r!{GEJ5D~C*P_b}@Vy`VTlov4+FQh4Pl?e2$zpvt@~3W1&OwC10&aC zdZ6&3JC75Xw*Is(Y(%d%Dc)8l>}ESKGF{f_Rzil7jbVD6<5@53vM7-@Zb(1xCVDZ1qtr% z5?q274oPr#m*DR1Bm@Z*?k>SSNO0(#|J>8#_PzI^`>A=VQKJUi*4k^%@0)Y3V+*T{ zu6!?Eqb{$ddA`LW;kMN(y=Nv_-+AT{i_z?r67hh}&Q9zf9FeM}N2|4c;h}4z6ao@c zug0B&O#-^HQ8Wp85ojlWgEp%`NyV;-8P%@Rb#CeIsi}vU4X{p+p z=AVYWEvRU}o<3SXtgTgh4UP>4=0=rZJ-4HqtN3aK%65#5 zdHeZ#$K$VpF?Q1mMRKwlZzCm6X1;A_2CAle{+BL5A)+;T#94@9$V%|XV;==m4}gSj!|_YKASghyJIyqQoJ(6 z&6b4y&m=&g9fXTT$l_PU9cV@i5_|CPA846{xK@pTjzT(pzsIXNU^Sy_-n8uz33H$C z(}$oHdQfS60I5tc3D3K`X0M9UUX!fzJ{3#z`qMB*zc5J44y&!(BwzH>x3b-6lYZtK z>3(T@Z<9(}OM@r5L12Fi`4_BF0Zt0Ps~N3`w>5586t^dVggaROF%)w(I(&ci?-R-l z@_%`EL8JBm_8}@oKNtZ40VH!~_UzezK!69n%m^@{pFR!3U_O7I@PcFu_u`>o zVPNnaGwYCthJ{(r*O+X4a&$axX=x!mRZTB>Junjrf=3Xrw1Gk{ zkfbPN@HU2Hf#fDGE)I)QG;w&lHv|h*Ob7i#pER#ugW$o`(Qyr2;t5aR0LdRgoRyfJ zO+iS=X8|LELa%@D{(~$t^nf2oA=FjiLx$3oc=-9->pAo*bMA$obfk{A=C1bUYY^z|z?cZ1LfRaI3-bHvs_1LrVW5r`@(cehha01#?}+zBL3 zAc+7#-ozAme}6v*g0IPh;a|U6LCfAJa&q#l%*>;Wjfn~!E`NW2cJ}Jc)2PTu7)S@5 zw@?E9@e)Bnc+mIaxZ2@ac#pacB2AFpg~r6hgoWWm^np+f>gtNuw8-$XQI{Ma|7vd{ zAH0xIi9FB<%iB<9)ZGOFutK4>J0&o6ExBYTUZF4g;?KL+MI!IKwvA}wh^#Z5k@5-7QjtKjqNzfDko)H`s zGcz+M=j1~<$bCVUS5SeIE#Ol0ZVnoPNe-6fv2$e#hh7ZVec1w9K$Zr!B4FM2APCi| zub!}y7mE!5XF@4yzV%cQNEWuwxWEFJ>*W;49YHDZK67}U*VTc>ED9y)y}H;@xQIo< zAVI;3`S9id1m6OgZ$J-ytS)_TA1*$=#_U^3P^bU*NJsJsPf}k$bG(in7wk9@rq8iQ zMi8>o(b6XE6Qs#&K0GlcVGcNfB%Jxs09=?cFe-oaa{Yscp9eYqGaod6)8;TLfH&p^ z#4Y&0zx(?C$A{i8==Ej8tE17}H2!~96XPRq8tPW#eQpiH@*HORjGQ7DL!Q_aF)=YC zKiqDrfuT3}TUg1;-q`qxDS?|VZJWAZ2oXea&^F1)po;-NmEXm zk&daTmnE0|&f{&Ym^S42^QPx2grm5SsCB!#3=U6{_8^iXzU)Ay`rsxa-z(+exgNS^ zqC$3x(6iP#N-lkhLQqf|O42S>>szVfFJ+q7uZS1bA8++43ZBF)EUYtSp45hW_U8*_ zvxr11b!=~O$#B)v7S3)lg0XE9WHSAYM`6(zs1R7)~i%*Bofrlp#N|b(0c_09;m)VaTPR1gHLcB_N%T=dm zQi?{)-Xc{p1_XNVEcto(r~CSXMqH2rYNLD?$l8?_XLp_LkzqOn1nd1fVfP~sz$Z^tWI{qhz-nuI2P}*n z9Mm%9f9r5lcdt0y-`vb|KQ77Jwym_>5lh&Mzc_ss-SlVuDcoeX(u7s`(qJ1Q;LUCf z^~$Qtf8_z$-59za89X*BE#BF;gD;2R;OXmzVutYEYx5$%DUsM=C|UQtp(iO^?n|OQ zkc9mSN2AQoMVM)8$4%eR+bDIJ3n8y*QX;o!1yt%c&%b8kqO#JJZogvJeakO~ zUYDj!a=wwQWaiaz#9q*J%G~QkJYOBLny|va`IOUjQtM9w`1KDyK!yM@ObTDUhc91#0 ze{6FQNl47fayq$odD*$0vPFL?>ho7JHxm1N@8NY-N$rzYoAW}3YW7f4Aht88K<`D4 z`B>Ccvkmtye^3s8i3BAH892Di^b>e2lxJ&oxwR5Aatd)|$6i4`i-x=UA`QAZs1opn z@2$;a4>)FBHut{Lvy}13VttE$kN`d~$4?l2l(fFAr5$NU2jUnEDUFkwDgH7%bG7e=?REC`Q7_Sh?cH1x>R?ppV`T2Cq(u3G!**sywvr$CB z82_%yaVG^ELwDHU&Hj3wjn(Jy77?sLAtIK}$>wJl@5WS}zJ39O_qjQaKV*>erIiMa z#rp~U(W3C3q%jx9>r?c-|N0K)mrT|OJ`%10a*ZmJMLm%iRkKD&Z8oknCHOcizk4px zvB3eiOA(S1IuCyn&;h*2SuRNx;Kc{jMBgsvo8P~_JBkgX!hIV`?3I|fND@_|rZrd9 zS9SIEW)*;Y!Qz#BfMv_j!_Q~-pT|JDVB?=D(dnZ)*?3VBgY|}dZz>R8Ia%29qVsa@ ztkiy2C`~W1Pg1p&`)Vxp@B4d}hs#{1B-2`kaE<(!qSWU2yw};vR*88OqOdBhu>}T6 z9l9SytK>Q?6h@3=GoAo$5d6C`LF-Uep8O}=;=Hp!NzD)Vu{5ND++^pz2N%oBk$M+M z(+EJRybMa((ro8RfG5<2HZb;qeoiWgpC`*B9hYCUP zO<+UKwt{FZ1HFXijp@>y$+rcP9nV*g#5#Siq0eVXRi~0q*L9)TsyCani>*0V#O})W z1VNVq^<|$SCqI75LlUuYmB!Ne(;b3R-VadD1*bTE5E*6#&)Q|ZW;VOM{LK)o{TW8N zqUviHUozatvdFMI+2^pU_NB1@+eT+D zS(j5oxvsRhB*%*M)EB@s<;_YZVNhUfN;7USk`NNQSivq}xK^pyOD(oM#>h14TeFAj zKjSJwA1&(fBTx7D3Y>bTo3;6M5j?Nl5e5IpK4MHsR0Cuj$X5Kon$k`8or7YPLzP2U z6iuEVW2b}KgYjx=mmwyv@Mnd`@tTqm|A}qk8#i$)14~S!J;UbxU9ltV8iwXznttAM zBtYx5DG*zlZHfMpIgjCdy%v=^JYFk;{wb$AqVsD)LOrx6K*i`O?k*ksT<3!UP%?KU z2N~R@76sOqJl=GMP8%2@dkQXwNv?|9)4_D&bn;H&ud=hhgVJE|4|wN)W9*_!J2a;| zHt!deM$32NEzziNuw88T$TavKw)x4Iq?@vlCpTXthxrp-pm6tDnyyH1UIHq$s1GJ^ zb|efB|3DJxzH)PowzD{LuoyeiNZNei@X@`ikpbrE#Jp`YIdYlV43%-9d&>Islp`%! zw+Rz^e(*g}o%Amh;G(3Xr+vP6lvSOK(vswagsNuexYPVOPh!@p)^GQ_`cXdV`}i6x z!clLSf&kFj`TV!30JQ`odxtj{Eu#P}EiL1%)FNrx7wkOs4^Ik;qW=3&!^q9mhOIsu zs+_)!D%2zXnSK`sjfYBxJGy&U(g6S6@5FI0hu73bN2{OqQp#5clO(R;SlGL+Ki=H` z_2HeHrSaKmf>J9CpjM$}*OW9({Q2<;LI6om@Vb>Mf{uG*tgMM>%i-OoR0&(nbul7t z?QBat^Rjy4F>F_}KPODo+0#%UzO??kU64Y)$TRezHSu)e&A5Sl;$(w=l|Yl#?kKCT z@A{9zhUjB>jgO*At%jQ`?c^#9jDOpku@dWk z2t5~>Gam~zIH=+-{U~85I~T*0U68|E(<@CRZI(sRDV$tt#|wfovuN8t>4l%-O}C|8 zkx~iPU@UTTxYfhgQsqk^fJ3o7oakfd7{7 zLwB4Eqceiu&D4UnFkko(x)m8LKY&5bxo#B*Xb<%kD<53bK#_>Mz4=@dox^%>kF6>T z00CRO=4e^^!gj4tF0?Pp_Hggg?>`jXtB~u6_g7A%f3COe9Z!Z-ZM!Wgq7bjNjIuXp zFDxw~^sN6b%@Fb;;{1I@>D82e5%R@$slebgH7euoeo4bc0jCbhLxn^KezP$@0Rq#yb>ZxL_0WtO_C7 znc!|N>@wQ3JZ=aIwK=DtUhmCl4%>|~X;~KRmJe=B*1Yx7AQALam6u(z1;$EpEzwZ^ z`|>Q$H3$a+Yt;!*W(~BYt<%2=)%-ZVEBth2&sedJOoG+qyrC1uf)~6Y`@?0mPWv*u z?u!_W4N`W};HwSE{h{7NW0W*fVdl8L?;QHH9-}no4rdh-$%wt5G&TfcVq3r0ztX`* z@0AMJ6^85}fk$Ly!VNBM)@Dh5ceLDb82g^jIm)p9AUV4Rs-5!AEGc-m1JM%-)C;^8 z+ST;!Ut@?(Yg0`g5$0nAkNA4er%ZVaAtYUzS6cZLb}?Or=|eMDB{*SgvK+$nhf#qm zE;hF3NKMzi+lrzmn|#hZGe`S~_(i;ng#r)F*Dlho<2e$=Oxtx8 z(!bOe+u#D$V!6uD!`jUj5xtxie5${>iyb}32%N5wcG+xg_uvba5 zy^IfSi{>4@T714MFrFLN#W zH{hq&Qn_m-IF>M_mg*m=#&QyWxBy#7yTX}EE77q-4PD>-#e!kc@#ggnvv-8mEJMQ-#z0Z7{M^@H<{<;W#sg4+)Y_PG0`q%004re_Db|ifC+#4;Z z&?AKl=p&f&EV>JYquSZRD1{^wG`|A$Gb+tSPgbAGQzU7d6@5?vmgvsepw|~FTqdc% zn#b5bqA7Q@_>uwIcGQm|lfwkS7n*DQB)lUc@*ZK2OESNHQ$~~dFaLF(*9#0LE!Y4< zGREV~=U(`LOH*QM3BycG@P8s?nGcx21sv!${Dn{A9N~D7FQbxWe7p@)SH$as317ZS zYstgjIg+jmN2Qka%(nQ2WcONq%7z794Nq@toq|C0w_mM(QaS;Y!=~Rd3*wt99V!xn z2oyWN35?yW$VZ|8Pej~gUiH6E1cjXi-;x{-=rSO^V=lh5d4&kj2F<|%C7g0`hb?Le z)l>i#b6a8B)-N--zI-w7i}{{c9BN4AIVuzH@>0gQKr!W2nP=w1YPT2h*?EkacAjFuy_6`u_{wyIr&jz+Q_ zrEFPVFp%e1_bvwlHS5}{f0o>vRCRv9dM5sk!u$5}cfLDk($kIOk(#yZspthbe13RT z6YA|Vx_-DB??VC`X(DV%_(z!!_%6xdY3X8ur?ovkBR`u{5KL2YZ5bV?=<965$rWbm zv}@!kLoXuC8J&j5f50u`DYWO~5t#X#ZhPL+E(SF@1$@JYv8!Ec4(Jj0eq?sNx~LILtTd zwpq6s-b8_4jGk-`QjX#>A@cKdvTp~lFb9gPV`@`!z$n{s#*n>&uWxBOj}a-v4PrzF zkw6}zHBxv8&bkQ9-knyNxZ83OlNQbuD3zJahYuWX`0`5iq~T?h-goV%B`@?a+m&;d zGcWDrOD?W(RYvaEH^cN~E~+#O<$KfougQ~)7Zt)`M#o{|{Hrx#GY>JPI<<*n5<7u{ z{t1^h`e=?b_V_t|E($u-!yy@X)Fhb40m`>U16gU@CG{a+WAn6|Mnxa{rE=~IV@jDn zE__OOEzvv60one&z+>dg;MZ7MZldttU;bOAh=Osz)hgk8#3TwengyfMEp?^MEms*g zdT%49%Mpo4b$L?8K;8P;sV2Jr5G&pjs$?&R{uIME6m1LRh*|PqJ4ww_Fb3^Pr>s2S zo67>C&VbP?6zcN8>tI`bZe?A;exz_vQhVpJ@8J*iCLQp~sg6{m#TOO9U1j{K*t2~m z;WyIm*m@_MgxBm`ms3ApXt-3#xZsLfR`4@x!XCc!hAbO=ynP`K<*d;soru6{LEm3T zQoG^ZGrObrf+0Dcx+ovpnYiE^ldZ0J59K0mSTF-BjSfv#}GfRK=W*GE%Q;N56ama69}0 zmnZXCIua<1qoQ!&8=odCvEhLRxVc;^^e+@PKj9I=L<9VW+2{iCEXil(P4gJoT*S+^ znYOFvM$^VS-ygoC6aqe>r-Ks-niLJ6^?X^$Wc4hKGVxYbnKnkG6RnPOhxdo78+blb zWC~~i#dD`Y>T+TU1Kg;!McB*>b`5Us*In#d+yvQmomiE&sCelxwu%xgg0=z!!nDA7RUc$ zGXG+aNPdVS=u-Uj`d6?|+SdA3KS1?2O^W{ZOaS<_<79ZSKiPG_y)C0R=|(A?5~f*ChTLEZH?^Kv7m}hMO%i@X&6WOwA*W z|BYGnP=?cgXPE>k?-9$>3#zXxHZmsp#`#Z9>uosGuNH*j^5g4G*hRiqqjSwhoo7?7 zK?t2WL8->R!3^^X$?V8rrAcR>F0LI$d7YI#2IVL?ZG^0rzios=)Jv_Mkn=5kW*MhL zJR1)0?3V=xu>gkf!?g~zt)p$|OLN@|xr?gc(3aO@SlKBI=%rsZU7P&TWKpOkR9-lq zCY8y`u_uG|jlO-LXOn+V*Vo`uUB=#RPe@;?gP`(Dr3pz_jr!E(^~!|%gA#P$xqx?~ z(qOBv0UD)#{#RIql%E`E$txOFbnCZQJ;iHmQHxLZa~4-atnSmFC1j@OLVm|*3oGheKeqaY zQ0y)n7G;Me`Ybh`DwG~qMYM~wR5%}gGg8AL1Oh%HM4APtc?qil%BmjZKmZf2T3UIv zoMic%0fd@Gby4&T7cuicCV%Kk4Kc(zbdx?$U5TMvBRa`NNrt>VTq2(t`F!CJf#HH% zHO!#>iN#tf#{%9xja9&S)&w9DHR+hEq}*qe?PPaSwYwj@J$wxpo=qRx@x!pV8bKMW z7j?M~R%tq#(pu4{4O#p2E+$dNWbO zQ&ALNxv_|<*Bd-u;cst^LE1B^lt-_{x4?hZxO`p?uh+}%BY_5Tb~>A_yHhO6=H+vh z851I@#^{4E`tZIcoCUrEeviY?Gt^D`Q?oB;6f+zR>i7Qh8{W4re(TEzIE8r(V!Ml_ zQ6k@N7{d%7_GU$^`5y+}Auj}oIOl$M&q1G!gJJ9sPc!zqdK{-G&u{Na zKP+-RU!-2mflA)H=2WuI{lgfNL#8S148$~6iyWfW75{Hyc0P&CIKaDG&Z|V}Phumv zS-4u45#(#8FMb0mS0h5@mgBuHhw$z4I)a-$TE9Me^-9mYJUyZsE;_`q0mt@E{SKC? zbotAzC8&9Fg{2ja*GrcYY^SU+q*2NI5bOy-`S2YZO$+V#@XI{AeRjpv80VNy=Y4;Z zFi-SQvgO_%mdotP<*JSDoOWX-a6P4DsMH1ghYVb$uT~JX5_gck6DEUc79s-~PHm^k zjrifRFL^PB%;}PZ8bWQ`*^LO2mIeRN0(f2X_UrmEYKaES1PHgF=i8y0H-k3dvy$}` zKZ$5T5St}TG)z=9eEX(G?nb1`fBNsmM@~?K&~f=ql_P;^#ef5X0!LKJqu<&D|9JI5 z^DS7_94jB!w|O5*#3?WPF_`xIYz}<^}ag1X$USA-yXV&aUC6#P&dU3hec3$PH*ZP|y%knCs62kW zy{jK|`LuDN?cojmJ25eKfU*2DbE4DWG9to7+^j-mN2_-iJ|J6>w|iH1Zw#IgDldC#=tn>(4Yi4?X=%n2MANg8UKI$*2gZ&P@0 zt1c00uq)eJ?OHq%{`py1;Hg!vTC~A^=otUC@*tyDaNTT@Kw-?pE_*<)aonv@SLv0) z@kwG?<)!20w`I|p7Ao}B_q*`PPu^K(ECZZoGYIqQojGNK6L;Ef@SV>=e2;H#dCQD+mPBI4rv zXo1|(wKtt4b3gQWgd3E)TcsF@sa@V-9d|5F&%8s?q5LhJ$0KqQsjIiK%Z7 zEw3^I*{+1he05vAwQZ?m4t1+%f^BtN1%i~u0--N!aX$$N#~EFm=v8%@CO_{^{&_n2 z%NuR1 z9aCc)38-7S$xNRv7+cJU^B2iTdUorC6Iy~Pwsd^MwbIwDwH>cM`;Ll84HzE^2#T38 z13sE_4pU1z`~Zr9D2oq%d3s7K@c@P2Kd$&$3JbDvk~a@~t$_*xV$T@acCN{Vxmd(W zeS})X|N3yBaQF zP!(F&xUeF7&6?JLdV%+=3eLO&#y;u0iJ!4Ry-% z#%4~iFkw0w1JBQo(xk{(~#1~27-Xgvm#lO6g;6xXNQAt2FfH2O#tIlLY>?pnqku{lhnzJ z09wePm(vT3vE^27OBgc7GFgkT)2Aizh`3m`P@BH=5?KeC5Y4VG?=Gj zNyNKLU�kCDrk2dOa-$8!|H_*vo;hkmmR%8p$R*`NIPp>))xkwa27P!ym5@o1WHU z+Wq%+q^Em-?buaqUF*wWA$M_KLqDr2eKw2P%v{@-vKh+0{hdEYw>DgfOVaddZk5{6 zo9O?9ou;PtTSwV$?S91EXD9PVN3Aw_$r6glh16A=7ZD8a@V8)c{v3tqZ#*_(P&csXQ5sLShq(OL<@bL(^vboIVGALtT;J;^s24M4akpO-k!gy z=f`}h!`5MsJeATy+e&Yrc~{5p{&IoT0KDCVg>KuWFDq%Xh<(4kZ-nQe6#jeE5=?Qk zB5dstyU00CUDjta@u#Rft%AN(-$SKM|I*ERr%>UhAi}fcpu5(0fM=(G<&E84v0+eUjQ}y(RV4M zEIQ!x;P@qJJtJF+S8ageh4U0WE|p8`>7mNGHDtnfFL(w^1pDTU~f&@ zl$WD+AqNcwz|e&8$m0-73AA*bz69WCMw612dC@t#N6%^z0%AiO1>%3$_maW~d|iXW z?EG@<22*4(6&=t4(;Vx&l&UL7o9XYsji#sPV`qD+)|Jk6pv21ji z)OUvB@0z#U6F$%(CepHeUhF{DT5(-Qnn5RMpN<0HMF^RV?ZVKnuNAOQ$*}-f_O=`A zN-T*kgT>M1$rHk($?yD*C;%8rDJ>TMaxdeoG%=MTFMtAkkGp^MKbS{;#`ljnODNQD z=^bGQ#FuBwZ9Qyi$qE2Im}P$}BXdGaF|wAy|g;kF`S!Bqt(-aUf7UE71{Q<3zm1d5+J$|>?qf9 zd#aS-9EM@nIo$k+Z}q0}Oi;;t5x}cLnbF2Jt27sIOxZRM^i;GC6xMyoO6WEn<%B7q z0BF&)_``CPX=+SzHchi&xj(ql#AWy6ZULUxUs5iYYkI$;s)#Ez0_W@x+akWlz`ONL zwqIUp`c&Ry$wFLZOHHT)4wa~c6>xF8#sS`CIu@0W<|{o4E+Cz}a1Zxx-y!5@e3Tm3!*t1s6n*h=Ul{6haa_nHeCEvLXhrzaCuh9XM4}*KswVjdT(a= zoLpzBJbsgp%q6X0&}6i+;P<-}o&iJlN3of-lPW=1*LgXFsMa{O`+b$pjid|ml`!pbPFTRu+{DZ zMzD$6j}RoBGCB~B4~@0D+n9~5=FW&XAgc_nnTy;W_S98XKjb{|bU6pT2*f}PSdpqs ztu;2U)SUHHA;}qol{a_>^->BWu@gS}Ml(dz~NIYO6l)c@x%?I%KKfw6LwzsyD z{!h@;FHPcxK2=dh!>jjdM&;WngsVsU*2DOBSw4p92s8B_ZEbUt3F>S|uvZ$A;4+r} zG|IvnZSh#kC5J!ai^0R`fXtNvp_38oCIDVUiwtG`nW*J_jA{;(eM6F~Ug-lFH0Gn` z`Z^EI++iYhIxIC&EEcOLvZb%$ic2eC@Z_QU8D@&=$A7K=yjjB~2S%&$(ssN>=W+XJ z=n`pS-e+UCjM@0R%zJuld$h&l2OE&;zH?%i6TucG1(taUVE13K^Pc+;P6b{8^H3qn z53yz%O_8<#R?EAE)B4|C_S4q`KM335W=rA;E*)#Hq!e!sepattbC_VThE?7CTWaP> zc(MP=8gacB(xwC}y;k;P;#V0c+58BhQT~wpIwW?YV`4$e4 zbb8EyhG%v@D1MgL8ZC1a8L@-yU+&WA^nua@VI{6G-cv8l)(Ehr_pioI6KKN)Dzg~b z2Yqp%>jQURCgD`TVl3*>E5Ddi%Em{ZG#H?~;3R~iBHY$i+!dg9#(x6w`n{b}ch0353g~_PV2G^AG*AW1x!(Pp=|vYrcRGsCcllR+#%`3Kr2&W?s&4 zIUo-=&(J&F_v7T<@D!cyN>e5Y{r<#94Zwu%sqSY9!t-u6Eea7;z&udG4~8G*c$k%H zk7;(R?|=VDDqtP}*4^&f${b_M*7v%8U0f%v5%5As6byu)Efg_k2fu*xxSzfd2V(Oj zhz!`)>aJXb*-hi{S#v{tXo*HkLsks8^e~5ypg+L}tmz}}??OY&f;;@aDbs-M=B&1MI+A}7L4 z9XG2z-w!XxwEy=~=hy5m$ALtoswS4`p3nY<^$$7hl$0~&NnbHiM(Qz+1uypy>rZ-@ zzdsMRMrFA;us%F#R+S!_!kx)j2gY7e@$fi=EPlDcG+{4r-oX<=@N<3gxy>3&DOb28 zui07+plxGf|8(4PJUwII79S-sH*2P-HJs1Pc-LKFWu`R-zC>+_r~}c>M}NETb+hQV zM)VIZ8x!#oB4w+j%qm_%o6TH2+*a?akZgitXL_B4Vy!{-QMweIyC29Ay;Zub$CMCWBaCK8ukI!v4LX59tf@Kc^SdzT&zc&lM{^N)r?HvOn)! z7R)t4gC3K=+WKb0#@Dc2&Pjiq_Us9}vxU|hJnG3uuU=kBM}gaRRKzcSL=_Qp58kb? zvIw+6`nzrEJWCv0YBgj>^EOSo#7frojpmf;ygn^8@JZ~Ct3=Gg`|OGd*u}$gg=TNc z@?c?x< z9YmW1C9q|kiu~=mC^FknPlLa(8H@>MVC=vI-fiGxs<*GND40)x!!biZ5DAwG)$4c7 zzn_8Cz+{nMq@YCPM_HV7@hChXv?kMEW?A|1rdJK$3-&VSR~e=U6jw*kPGE*x1D#ja zT8%IIMZiClhANQ{T`AOFCiWKPll=u=kPQ&LL1NiKgbuiQRd&>gw5gdH!KIv%FPr?y zecows=hEB&e^o|mm{?`qX8MWN%f7G?+)2zNu=TPt1RGKUso{ylhM=UOH-WkW0`!02 z>?V->pO8*R@PV;e`Gy`3gI$&eRMXLYtu!%ztT2|>^w}k%whc0w|9Ms?KT@;DVS(r` zMHT4!ox@JnLkTSA+X#SbHFh1vw4NRB((3BdS1eJ`DOJ%`Sn~GnO9NZV6B#8XB>_PZ z52_9Un1n;kT%gW$aefZQ&Wrjzc&N?wS*g=xg2H1qgVg4RRGGoL|C|mfBvhYG49ukf z9zaL(*e;*- z^Yg`c}rWi8IvU(>10 zArj+Cs*qt8YgHQpXWx-2$H9;iTu_Hq$ocjy4glUWIi=^@-5fY7PR=^eo)1Qiz?_rW z3|<1DVF--j>3;m10m;>FvP+}J2W{UBEG)}4CSS9+CqZ-A-QCq8Xu1Y^KvUL!nCrzg z7DU$0`-1 zgrIEGC?&Wd7(6M-Us-`XK+jI=gbbpRB9>owSn8OGOAto7+ma8h8qb^&v#8^``EUK^ zk>o9wMp?rpoEgEMgn=C|#6}}L@AB}Zxq?=4uo0El$OBpiBn1Qo{T}`dfEf=k*i^9+ z7AmUAiTLMt0C0V>LK9d}Sok&pbnj0`%VS|-jr3V7$|xvklo#wc?~j3=vOsKbUlVx} z0p~YBjdlgNnd2CkDk~(U=i+1&Vc~}#CIQ4IB)mrfqXpmqa34=+LfwlR9{KX*tDhi8 zY(U5CofO*L<2aI`m%Is2>u!alVD0b!YrxQ*9}98%cVuT~|LCBXu5FR4vLuDNaiAaO z9_BR^feLQ;o)ja$w9HHxtpE2PfJ#Ip3p+kNeMo-u;?~9_wRdCBh)kpqG#V~%Pv+pi z46;yBEd}FS+Q9L>y1ELC=e|cC5%&5~qs^ijv;lhg5duEEVS?uJVD)lf^m5cekXA`G z{~TY)Ex_ZkJ5VA61bQF*V=n6u1J(z9C20|bq>wrMJN|beA=k-)G0|-A8OPE3Iskyd zhS5<`h4tW;Xpj$J%m|z@m>mIHKyv)<80!PUzy$c7Y!Pp8*Na(Bw;+@E$>sFXW#g4D zY$@ewAx{qnGt6zRWAX>{wKPB^F&7;>dyIoNbbnIvP?ZBc0|Bf&y(GR1CFmm%XbA}# zYcXQcDlF zBKObj#cm+jlF}+KD$kC}vs`F)%vl^go~zDz0-yCnqrM1Etwy;fEC}3INQEmVC57 zb;(-*Ky1pB9b>ADY*aibHk?s4Q|IY^IF~avrivLjoGG6JGkD;PzkfjlI6&(lA{qg> zNh+_yvIiI$1oT*>P+)=iDhst{(qJq`tA15|y^DlIpoMYOrSlcP$C)u0`Vs`meMbe( zqyg|n#eGqs-#R%m5;e9%P)x++YorO*SOmiz7fXsy%Lz&7qVDQYFVJuM^sk4Oc_XWX~s%pg+ifs$s7>6&y^;DLwxkp#6W-JnMExkC>ewY{z(807z1N@ zICN}N^YRoLt<-%{(ku^{)FbwtEVHAt-S?{f4ZGq(Gdp^bqL*r#Ks8{H>|10K$lzw` zd0s=~llh#k=0h?5|KP8~W1%*>;6_*q28e-WFaCRlHUaSDB*HqiWdUyJ2MOzSeq6Md{)5TqJ5{ag{3AGc$elsS(4X z!ZIZF#%j8DViv&{VyE*lo?$)A?u#BzYJJ{X2sL~oaoSl}lkC(*9!H()O=^Q=Fa6QC z{vS1EjCohr%G4wG4cm8}&-f{RDKZZFvN=!wP|7D>H&3JX^wL~5IFk^-7&`NkT2?jD z$mdwybZqs6cy~B53xe_iEnIEW!EgC)A#FDY>SnBEuYxioc%$Z!d#1#oi?KqgDQQ%h zg2b-4)Og)(`dKaO*gtYC#U~|B)XRegj@o>xgsV(AObB=J1>0|z9dBeu10M!Co~*n) zMy9*9&fP^M*55AO*S4+R{$)RVTC?@#(OnJazg?*S3_f1$9aDlr-+eG0bB!*@^{NQO z(|Bzg4qPU)U5>x{Z8{NnAUo=~t|w)4u2tO&7jCu-q51+;7dC0V(XpPgw@{s!ekE(> zcsWCV-i=&crVFE6J!0@76qdG1H(W|=2Hm^Btw)H75l^i2CXb!l?X_==i9Th$=OsUq zvh?uUaV?Mgqjidx$dE`}s?>FBwK7TC2YaQ99?>4Jsr))+O{s%);x{|O?)mYj2gPWX z>Tz74$c-P{Ta?SFOnuP&T8%<}-&_AsS6B?%G;`J>XMM{V^qS^sznQZ7{^S(i;3MZ8 zh3uTJ?=~av@WPzgMw|m^If@xxY$gXGEwe_HNvZ=m=QCVKJN1z3Mie|?!Glv)gdzet z`H4kBvLoSdKoBR7@-s6sk*P~A;!q)RsF22iQ|^=f+|$PiXtQDia=;J5IgCtZ2GiJr zttGT>UW9365qK{SmP|e2j08cV!YXd;PDu4#vNq zrtE?&bICHRjC5^o{~2gd|ET9*5s`s0+-PYT5Fy)|n5})HkLHiE<02sbRA_Yib8XT4 z;mOEy3hrHLtaas9TQM#0$z$7l6n@r{IYfTBf$7=$bx-?xnI>HnxPMP)jYdq79+Vq# z1!aN^LIFNap7MT(eO(dYa4CCWzzM zZZ4%+3l19_hD4ZhvTOL5m~5c>>AD;LOO-0AoC(6jvq)kg%041&WDz8kxf4w8|}< ztBknBqXp0cBtOT$^ZL9jF54@0Tu;G(fVo6u2r1GO*WOM0*V=lU1%F8!=eUu@EUMt?{B=)r5ac zUu@Ej2pwC4P98gO79&WwA2v_k-P(E~9nPoOoq|z-(hpkPssfu|wd+;|3 z8Ly**a$GA8hRM(Qna>+!dOwzRf0 zVE8ZQUmYK-&CJo2uxWNe;-&=6)KxZd7EK*RE$6B>BH&(J8Bg za6mhfS+u;><<9pz87E>;bGdrXQ9UzPELurFtCxDv7cz?(uWjMnrA6e-#kE!LvNwYXE<-62qlyIUc&KqyYp;t(Ww3KZ8C zD_-2)-Q70byLWf*?(C1vzhvgiBxlZ?^T_+W@3(lqJWPFqIR(Jkp(a`-?teJxZ**;0 zrB1s?|0Ym~OT1lf`4Kj{vD+fw!UnN{LQYWqA5wiG9oZWwF}#C4$~Un{(Xa}YD8}PY%bsF1Q%dVq;rq^Uru$>#mhD* z10cs9+ti!1!~XGKa~%oy|B~xS{DfF!gwBl6jMDzQhE{>l&>$*;!j6C5g*83i(7Z|Z zNLHl84d<6sb)wlo5)YgzkdJZg@_b6<3S`6J#%geqPZ2@@E%9%_)KZHNsH>(oYQtBJ zaB?*DS937${e)W)BNMDPP$*=&dadjTdZ=R+xJRA*$!xzg#balM(w5dp203hHzo4k_ z(tF2tCum=>o9W-q+i^y|_$Od7n$ehgLZm-Y=x7Kfa#-_f5MK<3obYt$o-e8ad%n&= zYgX_uCga|)H(Wwu6~QUVc|4{ALac71V7zDWSBe!^H@iW$RN-3fYNZ5(I2?H0-qOEQ z)wHVbjI`7xB|lGJOuX+iBW6lSi_eUD>d_KFU5u~*gk6|z7PK`d`;4|0y*7NBw9%Uw zq7c6FdzC_NAkuDm;5}CAIp_%>dcTpxhhK~!RW!kB)!+UvtAIXu?51}t5gCwEy>ik^R`3jZr#^fpMkFNjp*BxDYn2aELH1TBX^lN{4z%d-JWXV= z)9M^nRZeIdjS~G#^7qX6pZF01?Hh^Rz?Yad3ozEn!+Ut$S)-Ecs>aRPW8>{nZBgIt z%(xPc$5RZUC%`&3p8+M5R{FYgQibkfZ$Hzeg%H@oS>(E%A`|4fwYey#d-E{h*3>cx zFGhGVR3FrB3wcVzTZ+B=-CbtN5l9a!eaHUM{A0^nW8~RzJK0kVsx+Al^>z8Vlt1*& zFSEE8g}irH-su-_ySttKe}Nd%Dh|1z*u8+wQ2m93*fBp=Q&267;E{rAiqoWjrpEDn zMzAOl>r?%sG0O&a0xXG-ysckpoV99165qLqCtN7~2YfJ2n7|JsJ{Up`WPiB(AmxQ; zDB4$*a|jW;z4F4HcK=S6vAmr!S|-y4YSvVPs#)fVUT@@jC^`{vD_V2194Ht_gc${h z9Xm?Jv|^|C)wUlC2~;*ossi68mc{q3`#%{$cit1zU%gvwEh=H zv(;ezv-vXoeWdK8P7jn#%y1G~#_Nk;@BzSdHP;CvMfUd`acwAaAnhd^hah4HQ{MZG z|F%;=rh4vQiD^|H*I@ZOKE_lsV6Tnz-4v5SLj4`x#d93BismTtep1phfl}3xK0`NN_xM8b11n zWL?x-^Poq}N0wwaGzbtUx-yDX%+(V;JnP?d{d}j`x)9b{eR*}?I#_@bs6jPq(Bq-1 z2rM1-UZ$g#4(Z^g)Y)i1j7kL_H1y`F6VUx2uGtxO-;FLfOL*`TH6igoZ~JM;7?W4| z>sLJ4Pz{aaqXUZ&ndC;WwSOfFl@`x938eZ$yXagsJ^EsARNy3}N4jL@%MYUb>t_{B z3=!AWS@`Gx120_CEo8dY@P3W3g0%oKAZM0ReYV@(p~lFL2MBDht1;5JdLizg_|0PE zha-APM<_L}@#E%Gzu~ zJF2m^NczC8C^{B|7W^FGp z@LHi>!tL*mpynZloc}){*jxX!>0JM7n#d#}Vs1}#EPde5=w)cO$x~$F=ZL$50VzA` z8xDZ9a+r2jhYM)(L6F;`l;5O3!IC}f&Cx4;>1Tj|^D&7Cg2Bofp~kPr@Vv2Q)vme{@GOnw!E zl&u0^(5(seu(fAjs%#GOCwi62539bw+PmdKb}IBmPY9x1#w7AuZoB2pj|RbVrVDSyIY1KMDlUTe}?Zk{-K#8u4Ke>AO7xr zuW!v3e>3ORu|2;yL^UGRSkKNnQp@C}-CA#Zw^E*0sv%PGRC)2Vt#x-wggFWLM3eP` zT)LknZ?<4`5$5lSbQY;2RrF8p5btu$TiE$v!|S#2v@|=8b{? z6`I$GfoP1%edrJ8;^_X3?1r>M!uMzXup+dH+DF+}x)s5sQ@Gl}W+XW?D^m^YjPP)D zPwczZUS-Da9EZhaV=@6`Kz$8#v#K<*FUy6jP{UB@b8C{3Dk@g*F$C5JzFSUfUdg9(*yjbux*;>qrSlbBchOgty2E6?dn$>jm07oAZ{r#JYC7jjSe%jx8 zQ${7^<(tX98&zsVk*Uw`uvII~S1ljHn!8jfciRFkN7KD7e-AanH3>GGT{Lff!!qAI z`kb6(yuehzTx?>C)v%wfce5nXu(CXDhMqr}zm;R`6ZAXtR`7+yIjk;LM%X?#=<_M| zTeO*;=ddk z5H5-{U;VSyeCg+5-;XReQ*pC5Yd75aVmiIPN)eBPqMK5E?a}|HqdE=mB(Gz-Bonq4 z=DbC$%(g#VO~KR*EQ{Y>UKM%<9i1 z^PDm%^sBt@i~Nf3u3hsDsJ6Qiy#PKQD~El4M$OzSSmAiQQHQO)0|_}rgeNA*!SBT# z#5cuIbk+hq)m;uU5Ox3-o?AZLNqPt*gP|^$1#0zg&6bkD@VVcT?7y`8R#j?PA##0i z3WeUuUQ#BOCu$H866VLY2-cggFT3%D6XwS!cSyZy`JLOkCfwq3)i!*h8~V&Rs>hx*_^lHK1Bd{>FF3exc-mrOLW^)8ENUBh4RpH^TWA`SIPVQ_q5C) zws_$Ob~7{gvzC5pk=Y#A+uBr9gmO7U*YxgLC~|F^N_borlDPT_%Ylo;TJ52bvpyo* zeY$fmpGIc~4l)sxZ590*M@M*n+SdTyg7?1A?=+Wml}%0m8W2kc9>WQn-SGW5*E8`+B)TA4JOAFAFCXS z)$A$RPQU3>*F0#Mm=kq$5OYgvQy#q(Tk@q_+uvm?7n7W&{!?3=@@ zBI*yRF|6DmIr|1JVJPd)gf^eRyHQtL_m_WKAO)(fsyvrcGwmML#?bP7)WMGrG5csU z#kA~ay>Ym|H0K0X3PWCqE;kN`0t+I%xz|9{=h%tdu26xa>LgWl0_pK3fBx|6^rH8- zHK4TM7`#g_6adPAnByIplKfCVIp%Y=l{YV>YW!-nv4~lOE=JesL>J|YQh{1;6(y~` zz>h}5(IOrl)oOn!aU?)tJk$H~qmICO;bG&+MfJu-jvf@xZ(`P+cKLBuXtb^%nl&&h zEjXCg{-X}eBTvQ=Og7wKco6c4bSC+vx29j7pWU+VY{Y^oc)f^IR~Z#Y)<12F!%;^egVoz({nBY|A;9TZ zH!pcXXqo!S*B?|_DqQPT3Fq2;RpmsYhqa~~rrPmhzo5MY!P|w>qM8d=!B^T0l5%QB z(YSz|ZEq!a{OpvY_@U^1(nm^)mP_*6-DA&Y;Pvs?acf>F>MG|mbC(;~x8Pg*Tm22eeV=+6x5!Qk zrOf?pTbq7-9fGXrMoWPS#UO@;DYyOhn6TC*p7EaGp;D%LH~RI2^}BpFh<&PysqKZ+ zn{E!lt!Kk#ud_Ve;;7%bG3`e7Q|NlD3cq~m+N@!1ZQD9xg(i)`UXaFyzMTTQMNWo15(*ug*_K?%L?FdaI8d976FF(taz8v%c+(l@HwZ~=_Y`0pTS2v@(? zsuvJT-XhXyP-JD@Y}si=Wyp*5G_Gfudt{VKUuIC#Dr&3byk}+R!fh09ck5%YqGEhB z{W`HOmvdSCQ*AY)sUgwxo{O_%;R~xN4?$)Wa227NRsXB zMKJ4G-ykDFZ$d(;iRZ4u@Qy0AEsiL~pSTc-sca8ivi33@`nL~irpM`xFWq6^v9sog|i|ipcC+;7fo&m4rw0l`N z*q>jyMwiK}iG@A^3fY^*x_L$y&k#z5a6FLz&f+X#~Vxw?(oQj%@Vu%AfsLcf1l z{c1(}q2>F0Ob4H~$cc$4B&N@{)#T(EfW~qc8}>7(9hOl1HRm^vtStxjt&5rJj0ExD zKAv#-&5ZAPRQTu=Ss6XEyX?Ru2gjaXu7qvQO!f9M79G`V=s6()CF#-R&1#Hs@xdC` zui@U;W3<&e304JBCkm~us(G|uDjW039$waO$9+?=q#=nndv8HWAch2Frq^Qv4RQzszY z@JLkIU_R=HAO}LrrOsW3c@=>#CWgoWacd(gkX!q7hU+_`v+yTxJ8w7U{B2$>OhBzQ zTvmoRU3&Z@H@)`BZI#hephc6~ACxdjWPucEUs@wHJRjM|k+Fv6oYJvg{7c6W)q$*I z*lZfd`by9HK}BgK$jwF?5Pz`~^E!$}8)&NlJ(xlJu5OZjMAglpBjka2+aGFzp`;h? zRVQal+%%c#0{S$y2ATBlIXpa-x$_(#f0wTID_JFJflc~tYHfpbE+QTZ?t?o@HUO)c|!+_F&1+b z5C{NF6lE@aQcIZBEnLvh05#gKENy(?C`5n^uw)x5`pS$4S3&_$O4QxC(lkNZ_)Q!* z085t;FHu0{sR$saul)qT|GYm|EA?6sH$`ryl7o$fpM#_DRA>};>;l9Z_B;pali?S> znY8HKeNUcHt%Sq53X#{&B@jUhAzTrWfFJq(0mDgyitX+KB!H2p&j4j1Go1DIq<#LQ zXLk7m?k79!2)jC_I87Y|3>u7GF$sNFqgaE zDbj0QCFC}1e|i9WY*EmC1q6IQ5xW4KnVF{b__jdkS?1VXsn+O%DeTyIZQlWrQP9Wu z5EkQH5x-R4;40_LJ6tjpfZot4xymG>07D8LpZuh%w9^5quc)h*a0BC*$Em*8?R%S* zDE{2Z)G(M&a(3SqH^`yFcR$qxYYEcH0b?_$+LNEc6A`+Mer4^^+lk22A;PsdR>1#Iq(Ne45<8f69)a+z;E zvneAwNk!G2MV;6HmYZctpyS}x{7}MxX+ zG~SPsMFL5W6a=tRvJdkRa^poWlu6TzqqE|OY-!eH7++NZeFK- z;NX0*fWbet4*}!Jw&(OR!E4$*khA4^M)<3xHMYK1J&gz=F-2+sK#!A`lF(`uvn)3m z4x3{-mRXEa3T%zp6TMJlhz~j}@Bq{@{dm`HbC6M_{f*1?qB+k$@|6#dfk}~(ku8-; zQc@Dx6XIFQhnK*0-u!rGf2Q)6l_kQT87n9c4zd&VGRBMY5><9Lp)wogZT`YrNa{HP zv!^AeCwN|(p}uR4xvZ3yQHoR%W%GBwYqjaL7-B^08r$bNX`glsisHGEZYI~zPfUtU z(AARRsz;G&SZs-1+JtRCs_gU2RiBy5cE)tM5LwZ``LHggVcKvw8^hWwIKcC~^ud!f zBfaDIpC+r3mxDD{RFq8N-ko= z(=)l0N}S~N9C$F!Cq0IUi|#*M-QGqxpNwm0Y#$!J@~;qw;HzS3@H)+wFtI6wV+eWH zt4OF3TNKXxbkmVBcn{&=DqS%y1~}I9>NIaHODd z=}$I6uFD7VCb4suL=4?t1xKqVs82d{6iBtD4rY>Xz3Qc?ecd0Q7rD$~_*{cf@j5U+ zLknkQiBW1Hb~OwHElJN7_#J1WgK7fuc40Ng@45%R{Q<>*2$?V> zshVCq+T|LPt|9)pEQld?xnuMWKP||!Ha|cSY_ppj*(?^?l?ng)oItu~H?t$uY0>|r z1?{@*bF?Soumk`%@_jv$CUc=ru}+$aw42&J*ZN=?%OcS@%={G<&d4ebGVV!Q8rtie z-=i|EZ|@7sO>6Y+U_V=}`cX*&IlWaTWW;wgg5}<=r#N27BgQz$B?NL_$yk1N;huFE zYnnbNutx)&qi$97IXq>(sg;aWtdb3$2Cwwgzo@u`gcai--r~9#D{Y74q*^XlC3zQV z>7Co@El9ip>D=!fR5M$t_UN(Dqlq(>7+Cu~t#*}@{mqihV$A=!`xkIU1M3$`xwX6P z%Ap7t6Q5lTl>xpQ>0O>f)NfeO0$bX;QCTD?y;RJT;O-gU6ZNZP);VBzYa( z6`cs{+mgh03<^luJuFeXRix@dxcjH8yWMzEM&Zb>Q}=8~a`mHYd=0M@6GgrBtBZ7*Mo}SKGcoumb$#k(>b~vMc=Pp{&{z22oCZqt>|%uzbI-#j zHQ1kQt>%x2p=kukxhOzfY9*FD=RjIvwPG1L{j6(Vg`@qieA@~o`tsh$2vh)CJ>F#7 zjr8O4@5w>RF+odq-~Ke&&Vrw4bsN{p z-p2Tipr%l~`})lfjAh$eldQu#FPgvbVH!Zk2Z~xecrV;*U*1N8&%0@Q(az+Lug}F9e=eN03ko)Ftu2j=g-6+JNZ8ggd)d9@|EAHzog-cEW*)xx#q6MtHj9K_YS?)v z|0Qz6x&K86%XFpP%^P5^7%N4c-M(jKIqhouiEb6VMgH`M^aWhh*O=cw&O_Jh$+3a^ zJFz%gc?Jt<-I(1YG!GAu;M2EcGOwQ*sDV-mJdb$Q>WrS=H1F%)TKh6Vwrbo}#dM5> zNjwfjdrZ^LDV7elZS3Z1){RBT6Clt30_iQTKgu?LS>@{n?Em~ojTG^X7*C*m;x>Or lC_VeahVl>U`MM$U5ebL8Fha=XUI;+EL_DJczm)7=P&NHf%?Rm4q5OM}FwLqI^JyO9P7 z=}v*m@BGhm&%NiId(S-c%*;1yz3;o$`sQ2Ttm~C(Vl3}~%vFlAQre!swo*X_DkN?5 zrOJ|$!SZOXGUt)>)$&8+lYFDeiX|^Vxkx$7^F_Z49O+%tmSZ!06KSBd;*E~mrsFtn z9tLry4`YbfAUzzjkefl|m$R_nbczcLyfuR~kTR+C3qU#48ID&sEqa8IiR1A^qyRD$^c zL;HS4<4+}@MV^3qqF%EMkxm!3ZO)pa%1RjZo$9)U!vZUrm_>g5S8F4hw!Q6;X1x~^ zQu4_9!31C}m<;}M^$$zC-=3EBU!ao;huyJ+6)wNJnPukBq$NV!+82!shWb zrX6HV7fity4z{8`uDOT9*}@%9W_2E=j(2A&FFPZhxMgA6{XsLfMPQZgG=BTClE9WT z>%+S;i2Y9oP-Fa%PF#jJzwNxRB-g5|TQ{)3$VF8ZN{)t0$*IKaKEwT8yGQhWx)pH# zmYnXwV3T3G{;jD=(uIPMaQUWZPtLEsAbuq`URzCLm-DYt2!L1TW-RS8ay zSJV^DcUm?rZ;1C<4!F$4JPHu>#F)4-WWP^M)dJc<}K(-5RDoR=8)^|Y1J>X z-c=YYWsta=dO%@TFZt~(!KgXp-U*i_@1xniXKtFShMk*u6trxg4M1;A+;I zB%$QzpJJ6v$~V0Jv`?Q;pj!!fMe{%^DI9doL>y*3@y?(TmL$sLO`tUdabUR4>iOu8 zGu8E!=x6BgnrZ3${h6dLj;X5nYbri`#Z4&eqHE(VrG=(=Um-IxLtttoiQdEHOGcG* z&;!e0-1Qu*Q9AVj*SprngE_Xl10F5WLtEGmRkSgi(gz*YAKHftM!PSs9x{NV!_wTR z7k9EBoE-n?Mywak(zPSmx?GpBMsY8SV-6YSUJ6uV4bnbn30*d{?Q@g*v4N8>8MVzd z+RLn`JG@U?>ryb!9)iO^EpsY8^hKd**E7(Hzeff!cE zDC2wjJ;Hb6x=xH4KlR<=JQa8#!br#mMt;ZqzRTjIWJloTj-xRVWV<#U z;ct_$#h(C<7qtuI8THLV&=8z+BWezQ>)Jh7`#wD>hJ-^D_bH5=bOa?XUzhc5kd?1H zReTjExUSih>uDnJ;6FbK;lY-I@5vfkQ`^BLQD7T(i>1&8*8`So-$T>uX-f3zeQC(3 z=~fTw&f$M@)e6UhL|>3ln2yrX z(FV0UEZd3ufLG{I6Ks1DZ(?d$3{Rw}7jgbj98u`#`vEb*h#96)hBseIW(LCXHiFdK z90@nn@b~pUYXmjyb%p7*4*9J@LPkAG;66m$c?t;(lSDOgY(yR(XH(p)?lV;3eh{tW z@>J*?P6JdAc(X{o7(@@=*0bn^Zcdyg!NAcSev$^&yWx6uL>L+4n0(S)V4TQ^K$l)y zn4K>&9oBkh#L(!ab*;D`cP7hv4qIpZ8Ia4;Fgv6 z-5_4VS_GP__>}I5bML*H$nN~g_~Sy`zWmpgh(k#BS?yq8%(na8%-~>SO*>mq54pkjEFb(R~USF)S@9fT*iAK${Ke}=Hds(@gU5L{Iti-`G^M*}Z!SVKSk(6eG z?&h!ZwS?O_6C}56NMpS8?f^Ukssr4Yj$Pf7r%!ei-DbU9%$&Wxq`BgevU2|`;OY>PIOBLimhM18RfFpwc2AA59?;*_PmM5f#GgY-U#>2QY>p> z)vAwBgmM@43!dE8`*w!5Xq5N=c6+$HyZ6yp`0{?nAtC0jb>W+Ft2@M7fe6&)w0U70 zF04s~qC`IObb>^p1FQrv({2M#39rCjxd~ z$r`%)4OwrnbS86aVfR|RC?G$&77YYtWiz;rb~d8A(_N*Y#OPpJrYKb|*ykm#QN7xG z#|yqrkiwU(FWXkqLYU)6Hh)oA-yaG|CQwyMfR&_2fTeJFZ(kp0QT7WnAo7iU|C=x5 zUf5$Y9v)*XpT>;rkx`YVRw@eaV?SPoJ=MnU@wr`|d>J9@*-=+bhU|yZeU~8sjLWe8 z=&SN~9Dg@X-m~PS#x>L#J+nq7Xl1{e9hF>&XMP z(q7CROSbMSl#7~L9)Xxo>UXT^YA(cK5cDWIHyiy9IPnTBwakL};C@(jLv9&iD7a%X z95hqD+pYy&c?On7cSeiVxf}+twV`G<@$_Ut53}K5Q5gX)qOB6fSQT8GRaEL{tM4o( zue@5)-fNdvD_aW*a+?|!H9Y-Ym=C+{m0iFOJ_@<664EY+gR!ZM--{L0V$p%Gr>Ce< z(e281d1Z`f9XRg$TojucNODKXdWHns6!v5)=l1J)?_k`yWM%|uxZCsK&qmJTnvetd zZjf?WFnyW%->mAGizdBdau$5k%#P}C-2U*HWjjh!uSKB`uwJ-i z%cKC#w`I#uD=3+@?Y7QNP_}?{f_P6V;Lm!1p?V@$BJl`{;+7N3dEvZwR${etZ}#ib zj0vLKoLQzlbbv3iocC3&={qcNnIf8}2Y3-sb7!QfzBD$o>Bipsm*V`3w%sI*gkqIi z8*xd?TC!?Egj7=EE6+dKyNo;LpT5bZbw-~2f^xJnFwuz)gF+@AMsW6_)Q_Q|AS*Q* z){J_g^WiDWCg&{VIup=QrHujDoIO5p(Nn<&1EU!H``?|V?LF4{@=zOGNR5LP78cSr z`rLK+fhwFslYbRYX$Xk?40|{O`9mPM=+hZhh_6P{uz+d6q8zl6@xYGI7yd1^+ei6G zhr`B-cK^UJr$|g}AKq zG*4mTcFTwBOe}|hYHxZl{7%a5VuOM>y(G#@>eoBq-r*WM$i?j#h$oBUoazLO4l8A0 zUJRO6DyEy{v0+4T8s3&?90#i9)CH?3mT>KM*+k(|)vVp(RV|uZMcHZ0cveP(_v#H| zo+ocvZ)2NWr}t#xwiyLH3;2CU`XcRcHXW7|@k$2OYSet&|NFTd9rKZ9GW8DEfp~gi zYBnuBIJ_*??OfeeMpXwt6IJ#e98?CJS`Vl4xuv}+qY5f_6^9H76dkj%m8N-RHd%ar zUs`RU%`+WLw=9P}j`bW1U~)g2Y<*DF?vZIv07-j#y_RKgDV{VEIEdkQf3+!rGaDV`Z5m9=v`66-VQcFHvf|}c3>EXmZV=)A$-it!3RPr{_1{K$2zO}vvNxks~$xX5? z93iXQ0Bf@J$|}Q-U=RdOj{D+QwW>9~8(Z;oq*e>)%0)!L^f)-rQjQ=`1`Q`QE; z`o|bsR+AJmRwK)Xr`-MH2G;$X%Mb@T2dBj2EhCq{)mn8jV$Ys8zKt}EkvU?P4Q$Pn z0lLa4%S+!?^2WvA4GmZv3M55Z^}r{cP92fb8=vGyb88yXFX@FO$&0mbx}EN}A7+hz zJ}jREu_uTx&c|;z@w7(ZV`PftQe(rPGj9=ZGG!kH@OIK94LFINoze$Xc6iWj5Uan0 z53J)Lmz6Qnyct0sm{f-VRrGncOi&r@6-f3i?T`9BDHd| zr{Yco!n%@a(gvuP<&YrBr!JD(z3B21(dl+lx5cOD{nzKc8wpymY`2h(LV#OfzrI`h zJ>bxblKE|NGGLR-MWnRQYGJB@{P8skUC@C$@DJZVwLD++jWDdOQPlC|LBXEgdAp5s z*;qibg1VJ5l!ooh`kai6Hg;G$?x(dck2Thr-uP&pfEjTnM=^V{MweVkI>q`(B+pQ?>iZ(DjI!@UmS(kJ6G)Tt|r;UQVVvCC0kB&)@J_MYBe z+h6-vdw9^)XpU=O+$T-4Qc}S(i@>`=Z%If0(!)BK%i;$;S@F6Z`;Lu6{g9&A+%&<^AHyl!&9YU0qAlGU9<569Ob1HH9v#6>tA1s zfAiDIh(u)kUpZaK7eD+bCu;nEays}I|}?R>Cif zsflIf|9c&o34fW=J)I2;N6r2fHLu|wYUY2)3_%Ljdah>VHXQhB#D<2Q?ysTSg2W#( zlOcsrPZK$Id(Fiw7BXxGB}6>;P!V!&1POG$?~yJKft$bk;((Y(7*c^4>PS@441Wsr z;#7eDb`L7RYBTtb)eO(Z0lwPBuuM1OU{zoykn50uInGmpc8E0t8DdYGQ{+m3yL@luxj-!w06IoU4e0Tsw ze_R?35z68I->Mq7>u5?=3_A$)YDHJWDq;+wnG{5G=MC(UF~mGtmVsC!A?#(a55!&8 z*oL!;UCEiY?5WT2RZ>(U8WU0I-hajx-%Zn=GM|`3HTj$)GjkqH0IT=4%(-u;>M-}s zkml+sv1N?X)@{(#z*e$3R6%WFw-%dKbKheI(Tfv>G!?rKpSb~-3BPAWB3+&X2PXbT zdJ~hAIvsGKRMgp3I-S@YpTM)RpKzfRh}Y`+{>47K_JqH6%MiRXp?}=nC`J0+GhX1m zHG{a@$(xC@QU3D55l=MIOT0>JhT8DGyQ}m7-e=$(giKl+9b1U0v z9%J_3Sr>(d_Cxar;_K@RgYJllS$LE*?thJ~kO{|GQx%Seod5DNk@B+`_?ea#8ft1| zGhi}LZeP&IUyA6|oku(6a%9yTHNzbvQ0Mw4Qftl4li=heRyonu*7-Y?h8yh1OIz1C||;oN+hkJu>QE&2E-q$q6-ee`&~ zZlbjks8Nizkt*TbCwPO;09>B#I@{)VpP$?bxoTqng;$SEoBwXJDm(AH2O z%aOBtXOFVWB^^_8hsKwXeeLez$lq|x_rCbEOh9mK#AzVe@^+ro>F#XN5C!TzyNpO1 z&bItG{{JbeQLJqvWlSkuMQQ_%-4g-u(+cfv$!pJk=^`-mf^t-Ly1UVjJJ4Tf&}M=^ zSiFPPGc`1BW7Xgc6E(@-gNOvHiRlFVXd^F+@tsGL0l)uoE}`Lrt`oK4Ff09`B=~G| z>-++PIZ=uzZ4!U7iLjAb!z#l(X<~PS8WK1DD<>X{z=u*Ge4QkxQogE{Un|mHH~{6N z6&%d1bLK0g67JJOTW_q;Vc{lk6I~*+d}k);$-)}30C^#s zR<{PcNENI(o<&@5z5Z!XN`1IOI6>VugdF3ue1^4Nmzn?c) zo;Pt31^yaP-?sIC@9xcT1lwLtTEKiLFTIL6CI1g$;^M)Fx*gKAK; z=QGlz+>iP_{`2Ukl-Z~HX_{CrYoS%2E4T3C`^;Zl)x;~blhL#EwhCf06k>AK1=yLg z*{}%*pF1V}!S+xnez?$nEo<t>2UvfU%+)qY`1VD8nl$Lm&luNw&UthV z4ePe?MS(|OBLA9ZqmqzRpl$otK3QyKu!iY4o&?C?lMK9@AF`qdAJk*-(q}GG>&1Cb z9LAQc{hL7Cx+P1FaJYUri4hR9>59ssy=KTV9tVVE4{f+)Bje(y-;S` zaY#_kdV*Z;ha>r?k}TC+Ofq6}ub`H7jBIYsxHQ}5mS#yVo;CP5NL1U_Z;1y-mf-?R zKWi7(i*Wg&U^reTd0Q^0fb;od4yFbHQqre205PBSe zB+7Kuq=y#DG1)aoLtr6#SI?pU)Ot^K=osf1_(YXk`%xMmJpp{$fy6}|z3GZYIag}d z*&z|>i4cZv7Kk~6G3O3rFM?e0-W9o7r_gM?bL0+Vo9)YXkcnNyjmedc=kiP(CvLhZ zE*@U{*fNI%c+)5ew;gBo-#Kght*Y3#bdEFo!nU1hF(lH-yD1}8O`B~b3G!OUE}qpX zaECD*V&-QKJ&~T%KD;0C(@U#xb@=#vrRM3BvREMa}n_!P)U26~FMx0^pPBf@HA`s5){Q(>>wT&a{*#%pX2+49<~W zfNe^+0F8&DAmPoyDX8}iV&2l;P_Sy)CHCjz>tq6PR*#U_T*(d`lz3TeYwI@m?wstq zlhe}=wAa@j>2+CefzF_9FRh9ams~W3YagZG%ld5gI{;R*iI*xRAhNDM#+4Sp&?f#R$h=abW#G)E^Lk+k`JHD>p;alkJg8NR8K@eMEtaX5{Mm_ zlN9e+N@k8Homuz4f|lO2m3U8tsC=I$`r4TS1y?Aam!Btfa4s9<`4tEU8$4FJ<2-&D ze^4ynPJa==(M0NNj*M9jg8coV*I~Q)kt!ePY%T0f*Log}LTrtVk6%C3{(g~H=7K`H zJO*yecCV4i;mbnr50xGMEDa-JEqM!%bJQ4??yTR5d1=(}^QQ!1GrI#{7`=2tj1+G~ zmP~FD%>(WAKx)I#NyZ6ZP|>A(FllD9v9iuMuc1?FaY8Na#`l`b+ua{|T$WrhCzoO(T`l~@9tfj$`*UQ+T;a&DRH%&?tg5ab*&G7_Gh43P(lt+hBM&=k}H`CoJfDA7f_I}47Dt|g6Hzg4X@F?nE z$*aV*^F0n#-84W>cH6X7{L4Q4(~=fu9(&X;Ev7>WHE+f=#i5)kZk3+MWFepA1V`0k zo-0yn<(QdmKZI5vP-uV^&-wKq_7D3TB5H_0t(?tt0KOH9BB%6wo=7m9RZHZ&XPnf# zSupJRdHD4t`k%06vKl*z#~10j+Ne^tIrEg3t(1Dqw4krS;FD7b6k!_p|Gt#b-&O)a z1ei;~!y*59fG`FBKhS?Cw)OpQkpIE?|Cj%lHHr4W*KcbD=TEi~HL9HNmuuCUUxs<_ zr!f=8u-10-A^fljjsEmfy|K2Et!Eq_Bcq~-A%86T*pkQei86xR8z=JQG;N6aLBExD_rCkSxXsdE>UMmm>q0RgggOv;`u(u6zAe0Nt{RBQH0;5P6(BcF)d?oBM_S z2lqIIEkn)+r21$nvqce&e2bRkcCCv5u`(xa#q*|0J5{@>R}6*YdOhz5wf~eme5J1D zC!tMJmjQk>@ijF*`Ec~@`PHSu);=fjp2-j-I(`HCf%1fWK4CW@16}H34>zs5TcDlr$>V19|0;rVUdRWkQ-?^VH7W<^2H z`FrJ7NwpO7hiyjL#tk#`IKXY-qhC@(Ibm+3)?EB^c8kK<*953Z?`=%xLFeD6MRByohrSq@^SXgJI zKeD9ep_Kek&>S@=jt;NC14Dszg4O*i1#^)#pR_jPr4_r!ZJgShUw?Mr>ki4Q`lVm< zbjzU0ON-Xz`a7lu^8HLyx|SY2TJ|jC$MK$(&5`DQ2W{f@PsAXzQ<0)KXcqW%{n8-O zQ~23Ct!ZTv=UCQcvAo%+3QG_;3fn85K9;OQT{f-E?0=>+Z7FRR*u?aB+k3&qKh#oO zn$NU;1;{_G69cd_{RDTi=ZO<4v}FfXi)5S}S0sHf5j9}+l=jLmXc)(A@T7Wyg`!x? z!>prv+X`7eb-1*$^49}|{^cY~_bTwsaJ;JAVX|ZDHMFfkv4S2mFIK$$l`Hy(TP=!d zs}T#0qTA=g{V=bWT;o2{P?ksfZPB{8(=#{*H6uZc`uWB#w*6lErknN#7`=~y+0iGe zuad?vF6%C-j7{9(&|iIZ>!&FGg80%UsL&_HGyzW&p(+SIGzmm3tR$!MA(=`e=YLA` zzlzB^Fwox~=H%xT_(iw%3aHS9_g+f^^#|%t3GyFeZ zftbRG(uj_Uwo;qO-8iYUCief*v+e@xARHRdoO${j_Qqo-_4lUgh(u#CR zhtiV5JHHdxd(Qiv@4C+X^IY@nz3#Qvz4x=8xc5ih^~YGtYalD0nv#OP*VNB+GPK@G z)0KBh-p|-Xip}dU>kL8~I?TOYukbw*q$P^8@{?X%Y?R$;9uQ^aJC;&+ZqzKBouDG= zDWkONlxv5>KopZjvPb0G>r|+5t8Ijov*3^WOk-)Nz}~xSvP0f-+}zn}+M|sZ&0=ek z-h-|g!3VyBJD~Sq?}2m+B-N1!l|WajGwOSUBf(v>H)^?2p=qJiUl0Zcmsz{5 zy^;M3y%QIantJYcJM_69QNz|$M%MMbFm3LBHws7E-pX0jQml{z+v5f`((I~lj{W0{ zP@lHjq8`eeY;Y&0tfd|hV$O4EQs3J!r(};{#}4S}OWrfYnP;CB+qx;b3z!zqeP(oQ z-RPHHRROo5Ilkr!-#5$Q{rbz!U*3^GKLK$!)D~r}zox$x`tnwz=&h!!`_D%2JM_)2 zqV)Gq)4L)kUC)ZUX2Sc0$;ikL-x^dXcrE7Z7{Nj&p-lEAWt^m9aO<4TQn8sK#?0E} zQi_$!z2tIcK;l>bJ1>Rr<3kGv)-D#Vr!vN|u#ez7;|wRQ-m$7T;lb~6*VZ0_?P=U_ zCAt}pNa(=xd%gA(t&B#&sV_PZ*0C>SYhsZ74z0z9Q-&r{l+W6^n^PdxPFyuyrCQz* zlBNQ}ZO4?SPBNdwKSzD(#A5xLl1bpDYw)iABYOC~WF6tD+NaHTq^8m&;9_Aq!XtEf zb>U!?S!YI{CFP1Jy;Ew%jv9ViIQ0i81qCwfLG8fv1x=O1<$k)nli3SDrBkQ(c1;sK z#l<8$)Y2nwOuL7FC>@{$nW}TChJ-9J6fOI*|<^e^v zNT7+aUDsX(|Je*Fyj~YS>vRm;kNy}q^NN#qvVyUrwakg`WVC`VhBf&0Op+xHAzQT)>=I&{U6U^|NYE zy0l-fajPy7tdJZ0xDtV-LspYTcD)8=EX)fcAbTmg8Qn(Yu!n8!>+H>QbFzgjl}<-- zjREG&&wn}}{BWc6NsJWo2P%dcfZHt`>oTgQmD8>Xm95l%bIA?n)Og0Q zAB^$7YJ0w_>1V~9DWMn3_E3G57ezZASWW$9v5y5RDB!_3fz9LLs9=3I7kdB_LYqJ6 zuhasn+mlVp)5@?Yab_20Nqu^_|Gs|YSd@(8UhDxO^cOyL$nLIMc9+`ntSdPd?^b6e zmPmj5780ox6k!tS523)~5kTcz35bw*_y8*!pAhc2c*&d@aR$BBf( z%Tj>&c#GiBU<+1Yb_a~nIpdTMNA*Np8gvD=G*iLea&kf&?>?|B-TUlt4LbVN+&eMP zvdxCij{Jm)x){4~mp(oItLmob=E+z=66;*?NZ%PsT-h5@CSdhXFK%Y zqLW?}h44SpRV3!@<+n8$U*i$tEq0PWUn?;YX3N|q)6vSJoKyv;#|Wq1s3inxd}|>1 zVBGQL_z1?{TLOH`ed*0&u6%Uw3*Y;puxP}|np}&XxO>B*(%$bEMNo(CpwdMrBVV59_ zGKnEzxnyUj9=;?Hv4>!5VAZE|LJ{9%o&AY8pczOoSjA`|Vn!Z$EAD%=Jr|qc6_OB5 zTR)!WUtTL`yOHW;lchZvxGhCc9u)LIx2I!gmM4nlgfS9~bfLT_e-=ZN(!YATI{DxBN=kRo6R(K0YwK%V^YIv{hU;c}#LyES7-YuzwBV>$Q8eYV}25>r66O@P&5 zJ*HVre%~w)B0u?6oC2;i;zBnXbgGV-Qd=xOd*G8ZtdTQe`X?a6*lA2buk`_$me~_2 zH!4v}8u<zSF|+TXYDA&!l%KnT zb2ZFTM$MVcPB9p@3nd7gD$K;T-X1TA;^qkKGj&0(##)P|pT*gUvl=$53b?J%!TM^u z{qcjF=v!g!WvYjrqe=Y?=}id+D=YBZ$dk|gO^uuT+3k3L z#ZT*_Va7_azO^+W=G~XRRA_(n<4wn#C!fKAbm>9gu3ZD?MXwmQey#4S&dHf zGr2v1VXFWV_%D(%`AdZtRUH=#h96mgO5v9ddahq*ob{lACOpgy!}@h&J4e5pWkA1+ zlMVMLO|mQjZB`#T;c!PIuh|*K3P8Ayv%>?wa^VO~8!c-)8zB%pzI7CiyYBEzy<0GL z@;$Y~tPvBk2WxWDXZ571H2U}1)Sn4K3VLB+=0*4Fs@pb!gN)fzNo=f;$70PF#!pB0 zmFC1*LNP;Q$=}Emh>=;mqM5VSAVSRGscD+z4PvCR`(AS}(3d=pZOQ=;tkayrjAU}v|A^o(Yd&N7c&Snf)`MNo&I?D1 zry-Xjk1F;Ew(i*+4p&Y0 zuZS-YlYqzFuNfp=wkOKj*9xA|q}3$f%y11O-De7kjnjPWO}r+dtRW;4KH2e&$fl`) zN;uCM%(h!>ucJ3g-n@V?d>8-`uT5Cr6?lNdEHN0`h6Mr42!fH;tsJPAOX6e(M3x|N zc38a(;yq*-laQCjhv8qv<-+hGtMG1IF=Y|O6o;;UdD_q_{BjawsMyBK!u z>}Zc{NF=C_v8JWX)d}Dn81MTj6y_)^7QndR~KrhKN(mR@NMSrjOp zRV=|66V~~}gi2CjDwmhpJ)%?Q0&XNV+1IF)R zZl^MKa#vQ}>q=Lp+iBKQbLE)GCX$0lEuo-DYqi(FzyXxAp$(Ll;_}?Ips6_YQHtEg z#}_EMGOE9gdQ{>LV-hFphR-aZT*ofn5#0IQH`9*Z*(BEwE z7sYw(0uj5x-YR1c+6fdEiIXH^9X;?n(&<8_0%f4CrM+ivX4w3Y2O3$T`t%+PD$}eC*6FrnX|)?Ea%-I zZ?B*eo$&{h2&u+^0mFT&X$6_ZeZoMsNz8UISg47nX(uFnjYx+6L^Op;r`>MEe_nSl z;6qu0gYt<%w}V)f-W+{OjiJ}IyY7~&GF<~{++Wuj_!}>!?7$j9zguZJX~Wk0F8kzA z)I#A>lKK&ma_8BE+@*#Ze3uTzAVX+&_wk1#oi?U}F&@$YjQ#z4e6m0`g$*@A!MRZf zd@81SSW&sKfp?3$Mv7}V@g;CSz%@~1a-w-Scu0$dokUfvmttS ztoNaYL%XyU3GGFQfB2SyF*K-GP^nNC989B;qVt{?(oA_A|2AeX_GP1gJg=@Vjq}@5 zSq?v5JBh_7)`YNIX9@(Z|TMp9A(2awD==H@#hNHniiLLP3W?##3(Y@LX?3!JQhcUa!u z&y<8>8qoo03JzgHLMU82;^6&KOtJ9dtTpxrP0InHgq1|>USO!pLw#Jd-N3&1>XuIY zS9IG#V!4h3nU}%Wy{B%tYa%u4eUG4miE_MJy5LpB*p zH!VL4+E0(aD!a<5Icqqc&AbT|UoyiUhzWQ!mHzQvt(N6uhx`6XxU>buZUQ5=#}cFF z`0)k5JH2HOhW^meN&DrV|LAhvbIWEy(msH&jQGkP*t=Rieo)5SGQxCU%k8Eoap9Ph zCnb_r8~PoWs`vN65=m3OYsV=L+s&=w=gN(Kg4eI3&5@|&+*99G$>>RgO5ga)<19yC z&Z#K(lv1;8!;Ql(h5!&_ZfRb>dho9Bo^)aIjzMb{KQL=qe;|1mm~CyxRtOuNpZ04z zj>oHabp>m~8DBRe+@ixxxBZkk(dJ&LqHnm!Yzu{kB|XlJT7JQ|Bbhm*2GV3{b07O- z7OfO;#y450*VFFgYdAt>yDN7ixPU*I*PtN}*Op{5=_)BeQm=83&B6AsG{@x;8Phbm zK{&5-fzb!P)}cu`LGeRL_|OdNF_u?S56=BD=1mZ$wbTCX7`?kYnfg>_p!uVTVq(&Kpg8IHpg#TRFX%lN)gUR;nZ zI2WlN1ugL}3P!5{=Zv8=1t_!M$p&!F?5Ekc<(EAEwD7A1?9F^Uk6ZY0(p>B&*T6vC zp~mTH_3xr4xPLrCIjP6;!7jy5!StJ<9UFbaj1v9rTAs?8%^C$?H6>E# z-1Mg4oo8B{Qk3pCu*HHI8}s$ia7?P8c0**{ks%%MQFtWOvB{l2@ummtv!l9<0Ou8_ zEFx_5qncAnj=P&zTw`Ty$*2+w%Tki^-lER36-fw&$L=K6p*~?u>-;SDMqzpVmSqYY z#5qxehh1t|1XEzl-Y$qySHj3bxqGF7Vm_^lJ-!zB;@;}MD5ec@Rh63Ksr7avA?QYK zDJt3HdHr7js=QjLnN6R!lb zL|d9hh`0v_Tytw)D97oJHF|VF)9q^Do@8-{d+?|uUm}DT5!Q|)3rvZajE(MiyZ$%7 z7k~K`GmY(|Qe|--Gk82pIV-opXXu%>#npT17`HOOEtg+APi146P+%HHk+b{!R$76D zc;3=3$4eWSK|ZmZ>CYt2V8u5{yhKp0SFLQr^H+bQxn?h#{*3&2tX5wqeIH8F>8So( zHTKD(j+@0|2>=>5?8tcsn4dN5#AZ8)Y#qpk+inOyWdqg%eou!lG5EEkGfz zQfwWMLeV!^zD4DG$psI%N>opB!MuJ+i$bmvvv6xWCu;W~>X(hWWRMQu1jc_j#ereE z-Zy1J5X(MNPxYr@G)e*j&+85()9M7jg!hC<0|0d?O`M^=VrZI|uW%ca^IK~g-LgrB zj;PJOK>Sn5u-H4wEyZq2TKK?5xlRan)`qd@b%Vbx&D$DLOV)9+!HBpxm)iJ!zW@v3!X-F^ zBUl%6H}i`Jd9;IhQSv-!*b}&pRZl{cmmY$MPP{*UnIPcDKTW#`M5}DL=i+6m;+N?$ z|Li6a_*+kniH=IL3vB?V{j~%qxj_DXQyrY$sR}-TfjX))8>yd5At=q&S6LwNWk!I) z5hOwO9PUsOvFWZb{QcYnx5?^lZ(uqYP-;b#S5o-db-y~ke>j|oE58;tu>D^J8)mbY zKNuYC@u3lEnBDLVGZT*!vQmMBR>Y%9in+?wW&t^Np2iajtj;&Ml6GmG>z74|xlXt} zXe)))>4XQ*r|<<@4JbD2-~X~!9qJNXSgWPzo)?wHQVrAa#Htl1n#y*ibd@r27l zf0xxI&ODi_Sov+xP~!-euZ?BOiTDi69c;`7U2iFtv4mZ0vg>^``8^E&&U`W7?6Oia zkXq~c$9HGS=QvHvM^GcePtWe&!=i5v@~sG6cv_R^W_7CP&zE~$G@j;A!xwXNb$fGf ze1=5rDr0lzsUluHi6;aqD!6DSFnP!cpPlLn+U=?8=LdZW{4GY_=OtDQHUlrc*N1)$ z&pMLi+wxfe*{s-DLf{RU#PaSHi#2{nYmPq(c~p&aZ$o>38=>x}S23)6!6y-^wo1qO zQZxL>NhHgQW4VD?k8@H>HN{gEvRBS0+~}hS&SPDAW=MQ1mYV;6D(g%AGC^ZjrctPku8#*X+IWGgk$4 zU%~Bczh_vvnZuM@cu}^z%JIAjHdI?8oF7#_2ii;I_V=no^VGwjU61+RKjAOXcaXN) z=tP`cn3h&oJ`j9TeLD4AsNvO0pNZW0!&#*2fTKFpMv2l&eU&bMH#yE*w>J_1@m1ne zJMlO!4pGgzu<+Y@e6{HnhfOV5^k&Jxd%=cnqZzHnA{K!6Osnf@K%z`86|)|_he9IX zcHm*0a^w$wcaCV@gbo}96}x-nHV;i|?3a6lUYOQ-Cq={a)+O@W2pCBJ?hsMF1VNS1 z3aJYH3wNM4>a2WskfFiz3f=at_){wSqd=|W$dF*(^1s?zZ1IXrRH1Z?RsPLd8&zMv zyT{P*cxSE&-QQFE-f*^A{ULOJ#*weqLft9|6XUrvbDHGoCt}^7T>PaVx--#yydw0_ z+&tMYX1F_>ZwY{n!ZHi5tktnBzI07e~J&-aQ`I zPH$T1^uCVdc>tB2`{Q_}e7L3Zc*j~8V5ixJ%ulgdEuN-7yxhldvvhGZo{Ds&%{Ck> z(IRHI#=#U0@q8WQ6@sHjxgNU?r3wY!IQ;r?Wxx#!E2^P6k{s^77vaG z;2IDQ-kH=vC3j)#AU97L&j(nxXJiXfeGPuFJaBl&f9YH+pPBx8#_l^PpxGJm%!1`l zOtNMr#g>FJBboY7;#8{K=V=Q+4AuF&xMkp5(v)6e_79BeDD|nUC$b~UWhpPV0BM`d+s4M zPqT@-$G_7Dk z!pg2AQatjo$a7Gn*O9eZ-LkDVf1v%LA&1SYSJGP3TT~tjt9Tf%k9>10#Kf*ET`FI| zgE9jMV+>!ftVIr7oYx|VvI3r*HymVa$`eSQKLIMm224}IBsXabc~7*;2Y%jBg|T{d z=SlH9z$4vEE0x1cSX~S5TeYFzsq_Xe<8dBR=I~RSsgp{!o$F9L$&@UAj=o!k10El> z5Yv6|j=RyA`Z~%PmF!cVL3L4pv;oJn;9{gZ$;%>-+_V}x0~ZP{IAjg0x*TeU)u9|W zcuu`w=rH#t3g04R+I#w@~*CHKno+s_H2RT5+X3wvEUz)+l{SSu284Rpb5Qp1b> z#vW%B4PirTW@(v=O_cpM_iLKQ&v@oJRq@RnKuVeZgD!XF?9aLC84wZi;@6lkgT`o` z$_2P`i7bL?Net4$yCH>O6mp7Ib5pLpOyTF;k^GKIy{Eje;~HJ28{^EoIRZ5KKptOvc23A z_`M^Mc4R#n_AnmCD6uvfg6C@(By}* zrww_>D`za|>>i}5JNtQ0PZlL3WiC zOA-c~Yz`DuS`B?-(`L;ME_V0S0z?N8C*;T$?z4`aE7mM|y}#}QC9FPl(6Y|-bh7-o z1>Y^t@yC=_P+V-^75#Isvt0g>)C449K7L$vMBK8YrtSTqYtAMahlT&bl9KD&74HUC z!dC=V85owUFFTi9>qA?zTT3s)%?ovALvi7CWYO~xy0-;j$(<7%?nfeH(SHTw#g z@+kD;o}9+ZKb6xNpigQtgb5jTl=>`Po}r0L^lN&;`kLi(6#mXqo}~iO86i%=X*r+H zH0zey?Y}d`c(NUpd9Fz=0!U$TS+3mq)VJXx;hd>^CdtdL#fzfweJ?+WUObY!`qdh6 zZL3+?ZQx+Y@3L*JiHiE0Vfcd7&{ySUE z)zQOF1KOo3kI&uEuJX5$x<1+7>eT6dtAym4>qdg<-c0%ug%x5rpI7~ z0k?WMxa{3n{KI;2@7jc@@xe5Wsn_Coj4Xp@5+rJ#J+JUun~pFIib&-iG(*z=idhc( zD`gy;(FxBx_aWrjK@wdD8y#lv#5}#Pc9zwF_`tuZ?gN>PZsyP&+D zq6$8e#~wY0)T5q5-~7gpJ*S+lKOK#X;8DNrE7P`n)V6szhR& zd_uhD*C4!X$%*yBE{Gys&^rsJjQ*-igN+S^6G}o=AHuHF-(^#ouzI8{?C!M4U)P{x zQKXwquZ-3UrOm#D?D>eR)D%(rq+-wHZ_0HPu_ZsSH0Plc(JyWdWW(Ai!LP%Y$0ptY z27HYxXA!sTSD7}63T^>?I{BLR#Auk%IniVUm95xz4J=nGu=pEzg1hpp0hc)*V39RK z{ELX8-I%T|9?(^nA{Wu;Jx(m;y_QMzW#%({Qr0O&xOr@$rJdGrO>}f*8hebkCUxyoDwZv5x_D| z84H0E>-2d4le2#Ymc@Zucdf~T*<>O|_r7~RsBdA;ww%^w#xyR`HhbdyGG^eukBYUPVAh5`aKmnk7a4f%oAasWADgH(~f$n$$93X;$OTpTxkdf?DUR*h| z6;jUsc~ALd4E5|`2qZ@3E#v`zl6nuqhfcJ5nGA5u+^C>Wt9X3}(-zoayHm};1P46c z>XrYrwSW>ZlYbxww4a_A4~D-(FKU*?Vr2|$c-{?nl;u3Y2|vsR3gM6_5<_Gs2{v8c zMoNIQC?|4W^%=NaF|?pJP{pR*Rrfj23SwG{rGQT9^B6}!KFTe0Gt9`=PHXgzhNZHp z>Nq2ZZ8IXEg4E>eB)9ptEXixyN^Gl6y2ZSq^!)YFTBVCdWjXKP=V%-3+Ok3GNh3%G zvK92 zTS@t^B`8SGn)-)P!fwvRUh)Da_oJ+A2EQ$Gl{{iT_|)yT4tJ7r{rs)>F0Y+<qVe2R zhu7H@Z9x3=I3^w!c@c*0-8ONT?nkfs@5U5!0pNX%`))i!6&a0whkpEMs95hld;E%a zIQ+sOH&8GrCr~eX|CaL~s#}*%ei(dD|0!y6Y2eDtil%-yC$buNU}FK5*%V|89J-`% z@S&e3dXRWaNoFxt9M}$+&6T+qA}AOonRVa32E0h_zF)A1x z-xraU+>S^r!&FQ)!?wN6hy|8B9g>-J0y(+nl_vkll*L+Jl`ie&HS=fd@CBg&733&B zHL~da`u1Os12^`rA1kVv%w!}b|WfD={|%F zJcqYMLXGq8|MjvV9G~!BUV*#ULZOQ1v8Y|0yy`z0vC{q@S=uLLiFg$&*xh8HVkw28 z#@^McH>ij|7zBM}kMEZGB{F8Y_%kD$*v={fPFkIq%_o7pml7Y%vCaPJdjY!xSEq0? z0LvE!WbIjgV0S%2qBnF<@_~ZAh$L|!g_I`Y$bnQn zTJW&?F6d^}C+N0PZ9?>H0@9WsoCv9%?k226(;Pm{zJXMYgb6#xJL diff --git a/hi128-app-kpdf.png b/hi128-app-kpdf.png index c89f9472c4d22aef441cb5415287703339688024..fdffe583b8262759b98cc97e03f1dd9341e34454 100644 GIT binary patch literal 13702 zcmV;1HF?U3P)nXE!!lSB&-P#HrWwHc2tnfr=WnK{AEWL1rx_uG8U?V z(z2<&DO+~6$PbLM<*Tj=gYNDyXm1aL<;x=>D9@iC2G2elmhZYNEFXDfXy^z|{_+u(Rmfs0~Mg5UpM zGQao*A`nWC$cigOPPGbbCo=RMN#zys2~e7UTssIw+{3%C52MRqQs=gK<6 zFS;n~KKpEh0wWJ9Rc3wf10s(`Y64mlLxYk-id7heSc2~mk(M`!DoFp4zVZzJ3@*7O z44!{J?EC6h!==X^7tRIUO8I<td0e5>yK_ zTLFR(mmUmW>akuEWJxXNKk466Lqar`&ZMXY+S%zoJJc-~>6S*^c<&{&Ur$@SX z*g;;w$n6v!B%hZwuV;xY(&u=qM>*?IbjL?}zPUN<*lRB}>>}!Tb#|{jUF52=vj=({ z5_CBvD7y2OV-U)#D3FIz!|-{ti$#v6&#QxT&kcj!c8i|lCFn_LB}B|a-@nMYAA)w3 zw|L7zZt$;$8wc@Te%$PZ@`3f9+Us52%6fg{4j#E4`Ys2)lWH)9V5f0llh zf|E`PgDF#@{x5`{azgK79IKBM`8?;p8=A5)B!C*Ry&!^k5@U5K$qe{YBcRRdb%#zoJz2znZ7cm3zs_I{E7 z7El6u8#H!fNOsknDl!e`_VmI06`4$k&W~u7H@nXh`SNsJK0|>HPYBFyTvky72SAgD zi7}Y^G-!m7-W@&1{`-ePQ&XhI7DLZ^st$K&`GF#rh{!Qch+Cjq*$7$&8pVLz5$XJN zS_dPd6&?!A#$|-FXPPb0F=9k$LeS&I4JKj?3K>PHZUYNI3NNPt=Kq;~MfyIduaElL z3O(n9H>kW{495WqISSehYOxUa#*pX;puUIHf>*AEp@bZbdfZ7ni0r9e0YdS-&~gVJ zD0WWZ4f;@RW)Q?1(i16Ko1Rg2}9Yk*z zO7WFf#F#(HDRycbW|73Wb~y-O%uh;cZA_I<`S*xyjp%m<&IVWlErphOhTh{MGxS(K z=%BE0@4aE0v!V;`?+=UoLnCO=L@2*LpW*w2qfuG^igdo#G3>BI)UV~x0;t#Z5g~pg zC-VQCtG9#IHf-z#E*WSf)8Utv0D9Sk!1D;q2n@E^A}r3C6Rsj`+U6O8!0FS%?1Q#| zYS+`CrhbC!Ngp1F`gZWaVX*h!VZjOVOP&BDpfh0pDXx#xpfObgS3ZPoEXLqpMSd3W z+Oj&KBP#?<*+4B`jGM4RQY|fZPSi$KW>aoG8iA>sx#!7P`%K||f&IvKFVC1Erpzb0 z4n4*{py~ReNUJ^p^a`{FDnjALE&w4^B9u3~6&)(HhL|nTC0sAPuqIb`susr*wME&p?m!k0QqJ z_9^2bH}kuE=5G>!R|TLznb$o0q8sBVAf87c?|i3(DgbNN*xyY6O6$wd|1f?&%->7) z-dj`v!W(XoH4gU2Ip#eHqU~2<{^Dw|zexaI>k{_h^M9LJ)Mnv4Uk&I{hy#?hX0VG- zyy;%z-y6JmBt^`kmeBOAH5zu_Z8wtHhfDaK??`uy`E%eue*SfQzNi}PZxVoHTcG%R z{9*?1`>6z5U^P@m|0@Cnot^f%2|(FSeWMn!+<>7PV8~K_OPn7WLtED#xBIb{E z!iX#K)V>2Sf0F5-D0)l)WoT;`aZL>s^V=v)iTwQSwhM!w{3I-o858zdF5l79Fn^@T8Jz!K zFUXVM*n>Q;J5>x#Bnb3G;26IcYW0FdCIDr}fcvR57Gm(wmO~f_%B~c-IAZeDsbO&A zjbWLx^@8Q{9TD4~3kn$XcihDMp+SMhTV2`Mngjt@>Zt7KPLePpatO5f5QSGW;P+Wk ziTajXh5@DPWrU#Uwwa(+vtmjAF#%pc+$0W==NCl%VYi`bUktBbDiqh32Gkb-kXfTwTKQv-Gp1OR7TX> z9}=v_075WU50Md=SpY-f;*j-RF$K)))e`ITV;dLPkg%Lz}IG4Um40YxH2b7bZ*y%eUPYmROorb{V~* zLmTe>3RMZ87F(yh0K#p92Um|t*0=CXXN&@-QNWn8;LfAHq#wqB1HYGczBw$Oe!646Tbo#6eh13_Qdhva8#G}P^WXTE zy&vn|7KW@i=9riO@R?UB{A5KH>;jD)-x^wOG9qr$>XH-*IuE(pt1D))Iy z(zr(#*+0NY-Vg2J7jQ~K+hha|VH-)hKeVOA?_+{zGKm(W9=9Yn{|ns5K`t6i-N7v0 znX>bAW8)V2>#if5_l%^kzg|jVC`D&rB7A+H68R42&QgOfUck9Y0N&u1C;e(WLuHA> zrzcGkYbi%%PYAHgEmGMk{m+PX>|CnuPm{tSx!vzZ@bM3YGer4mVn)F4A z_Ptx*sBV zl&!1Vqvl)Rl8^$ z^u&o?`Hv?Ao=TXE;YeY@M^zP=uJ+gG^M~7VwYB@#e)F3mq?WT^`HGZTvD;;W#Nitv zH+-97PsjY1J?57od8-IO$|$x`Q5MQM%6gRXDD5aURLPg5zVYAKh{?=;Ed)uA8)qkS z^g0l$BqC6A4w=QBJynp=wC<%aHlNSGuMW6R>3W3AFOSm8osRiX_(PGKt|AHv&Z;gi~0R-I6SLVZDp-I&8o1fISq@>g%>uY!7v`NL5F{Ml<` zVI-3$Pp;j1>#e6D^}A#;nH^y6B-M|pR7zE+lG(v|H4(=Y*!Frrqho9?;HQYlJ(e#A`hk-O*n6k#k?# z_0U68N0NKb8v-;nna=n2l=Uzk$~mlVAy|VdIQ1hUKbR@o0vI()(qDwl z%a%#Icdg%w{GJfs-Mnly=KC{$xCuZC%KV!|1ROm(PlZ~*`$s2E9KE=ysdh<2gHnEF zeSI#3lcRX(X0~J-2ZY*jEX%AK(5p2yH4&rjXs;0(u?C}MHH8?fm@#c_ZA$t&1#Po< z@#1af%$f7y#>Pgy?gPu0FTeWn#~*)$>y-B0ci*GA)&&UO9`*J00@C>Rd(Ax&B)fJ* zT~9tKA@2?AUwNgZsVq)^=}VGYv`AKa+j0Dv zf9E0tZsxbz%(qj9lK_|{TYnM~TOd%<#(R$PuWh%LWk(+^@1%Hg7nt1aNEw~WZ*A?kZQk~_ar;rtyUQ-S2uLIdf~-wz zW9DleU}p2pC3GcW;?3Fz=+C}iOrT&DI=1 zT2FAA$SvN?UkPV8Iiftf(2nO+sJmFaYp!xrHEO2efRCRhw~`ZfO8S8woN45v6b(xzWnmA zn=R?O*p9}QZ7p_0fagC_@fZ$gwtg?$=EKo_Z=`RK^*AN}_7O3PoK^pciNlF1=I&OURo#`26Q3 zxBKoa-~Ex~{{3(1aNG@{mnz2M)N?9TL>)?|^W)4PZZ<$VL#VUY7ENF{X`3=-idyOY z4!ZswcTP!-Iz2|8`G1eUr|C80q&7jn!p8OWoc{Xa-!t)krKg{cIFZ2s6lJ~>fU*ey z2A#FKPkcf`W_ZutcSjto`OIe|&BBdhoQzzN%%Y1-o~b*y=1s1BSCzFN~hla(O090OZb3IbTe!@w6hTe=W{+E0B-(x@NG zxg=z>X>GNT`TH|*C2P4>UnO2V)rE{}%#9w-2#`|B(&?gy0Oqfo04UYC&y|L{8G~V{ z5figRXS_nc3Pkkx9>S}AeSInzO4_GHgyP&pq-s|iKtw$NLx3oBYY5ObawKoNqWhI_ z7gwHik~D$@xkC??;CH`M0f?e~R%AHJnfE8K(ZoNkV4pux)-#?|@G#zn-1b_L9P{u85=tEA`gFC$u>UH;dC&#%^ zxl%wd@ktjhhGbZ)fWzo0y&P$liVA?izd<}N3b5rL> zN~Q|*dwMN>t>;E4U@E}+5^r&V4bbNSssrhcqJM!yfRbAlRsu~zJf222lHQ8IP95=& zk^jYJVJy>T0f%&P-&GFNCwtW)YmMp(M5`6c&k=?P}F}4rYkwzE-Vh2kc64=tCanMqC-V~8- zotcpH4Z&fl0!Enr_YhzL2w?hO2bc_99Kz!kzcDcJZ*g567ZxDhEPDN}A&z+hrULY} zLce+eO6CC!r~*R1)A!(m5-PLURoetW5CHS@YoB{g8b0_z8FlKZl6~wk38?DnPKh9v^z;{xCzfDNL~ zx^--W@*d3SgLLLaYGA~O5$2JoXJD?P_R)lH!0Y$^=ReZT^^^lS;v2%gK;cU-MQ&ih zoufK`G%IzpEZPW(^7Xa1%TlZ6f%%Il^2nejO1xf*d)NXxEO)cN$#$Hvzz`pQMdVAA zlbzBd(y5nl6b?H9$lcLCU~Dt=E$$o)DXs4H$c4&N)YN8YzVN1xmVJb_QJmrawmnFi?TR7}iACHWyta zMFgt%r$3d&3i)2e=w{FhP&2_bO3*Jpp;As(aB-v3uoD3OIKc#<%)s`+00h8PfI+Sg z+i}a^+_$O$AzyH4aTQ>ey&nuxAy7llkN)ZFs4wOP7)lM)da>j~6(I5(DMbR@!SahQ zMpk{}M?NB>f&HAOiK*u+;L|U5oGOkVFRje{98A}HX?mJE1T{vZ{C|PSVhPo5UtavS7tiQ6OGv2afd9SU-f64A)`(>L2?TFlyvp6 zZJhnYMuD{V0un!3JDB0xq^&h6rT4C=B0j65|cT z#$w$EJ|KO!-6oWt$wgVS)JbcYH(#ybz4p(?$&0u-(Fg=A0}fvEORQL+1UeI zL31lc;?`6IUq-6Dx&t$J9X7#wI?+NH&tMF+b z43V^i%n-u7fPTG>W?}~UV>50RPZ#s>s^w=)l1>`uc40bCG+!v`FR&# zEJal>+*`}dcHMPXF@g8{?LSii)$qjax67`e$V*NL8lVvl2^Lg@;jnM8x9?|I8(_=T zH+WU>iNI3|Wc3Ar!8Z8R2lgdC5%z6XKuJ(vHD>R_zOM$%0E{=wP};2LIu;A4ns?~A z`DPLQ3^Zx`)vshMuwF+#KTlXVb=6hULCoJ^zo;{xlI}cKe}-!!U~2H0;MsUs-+Tdx zKAXA47P2D(pdvC4+6l@#H0X4dA;bng`EijscnANm-OZt3gBgKGp#Otd7}#c;4YF15 zLUD*Us2&XbC#H4nXojD;btVX)f?eOPsX;0A0<4dT2Bn=}AcJQ`o@2@9*AfKEKk|sA zzWP;ZCl;{CoB1!Qt4GyQhU+r(&EWI!>h;^{l7&L*a zssf6ne%p1XBh-^9;;13hmnXcd%rD{@EVc-rGM{?>J`jMK!RTJwY_p9}lCJ$S7uU!H zJW&ABj-wgJ@cGU?Ohem3PeP35#LGmk`k=^J+D$)FxFG~!yh*JEfy@B({P%&p zK3p3m<^ufphAK+d%m8H_fUkoMHD1%tGPAqulv5;yFi*PW7Rh7K27Ik=mPnSv!l6eNh#q0RY07~oik6sQolylEH9x5 zVLCZ}uQHZ>Hz8du^q9=1%Q>w09HHQd`NRC@T=)SNPZXA(u$NA7Fa z_U~`~^aVhLH9`Pu>52-NMNVL^7hS4&G&Ig}`sGT^!08u=%>ItZpB(c8rS&TSu`qB~ zK0ml1P;#cvm^qkCVBD2VtPDceD`}tfx@wPD8aU3J=zZ6Ze=MC;^rm3uWJw*|-uXAg8kZJ@)^B43$B&*+$FmRBd0(=huO0@dp@2w?d1QUxv ztR+Uv`&lV6<1>>d%OvXdqSdGWz}QyiqtCVVx!E5=9n|>Q z{Rr}Cj6W`f_IwtV^fRRKXQ&vR>cME(ys{Xe<_wV=Z^Hi6)x}RaA;?10peLXZV7Q1# z#A76ly3HQ2q|qBJ0I7H)2nbUt_Jcr{2DaH2*V}Pg>rk=%-DbSy1Pp;}nU`JL^s%ZX zV;(D4r1$jGqo0Ex0aGVXx|PPr%lrvsCBi45hBZs=mU-5tYz{$Hkkvn0m^nV%6N^>| z1;_0j?Q6vja0Mm}Ab%hL5&@teh$qxGT! zQmCaM76xW8OaP+Sv9?y~ARb1Js{m^ZcA^@vU=V|=uT>ylRRLVD2WEFszNO2tM_zbg z6yymB?WR@V-+Ql!cmE!!%?ZF7_U5m3GoBc~E;_MUt-=)vnF+pm0`a3gk1qgb2ZT^v z^iTR)kvjz7g7ZawwE|#R;EcgqCj_%Ah;YIsfWp-xxBE$>H&g&D5fsM4zyqiNv-soh zs^;zB4w@f=d%{7bv30Mut7tb)w-tdt@*QGY1O{_ zilNLF1aM$pRfEsG9gxWndQ}wwEB%4NjaFv)7d${RgBKny^5gmNqt0y!HWJzn0vS?= zid>4Cn0L3xbiMsh28pu$Sr`)%$!;RHqZ`_!e;r8pg$j=WUGhhoaxwlX8h=ne_S#c ze`y4wm+QAV1v z;6EM&^7Xqhq2wxD!D*=Z+$t-$)KV{r>ky1J~xQ z(Hj#h#(xFsaerG0N_4RL2a{f(RpH-kkVFKt=j7-IgtWhj2+->xK%U73W#N3L85Dh^!d`a`Zg`rMO@u3P8cx07`n;8kC>ws)B8sK>E9atl+s+3EfG*wwNhI zi=5Ez0zCpv5_$LcL_T+($XE4y7AYK30jRYoUoYXBj=hL@OCW+{ukVi7XFCHZ3uDWY!@S_fp&!+ zt#}5fT)`tyQ1~;8T|wm`6M!1?06ZfQqe~ymJb=MMe>?;nKPIUFqgU+!f;RPRwv@uJ z7iN2w*_s8ebJX+K{PUmE$Gw&roIC0!#-E4bDUhQEgK#uLVyzA8G<0J#$VC){5c1V$ z(;UCf{KOmtpH)RDGgR$a^?lq3^tYEA4+6yYS~8u!<~AXNEb^HHM83b2bDnW-VH32I za}W0h1;`gHA#ZTE=NXiTL;!R>U_1}d;<NH zYw|J}XKCK&3Fnsa5LP)13=P_u=`W)Hv;1uf3Ndu8U!(TVF{A`7@y=huLXW&Fa$%Dz zjU(vuB_^+YF91rcPq1_2;ovUL6_3-+CIAt6vf-kB*N_Kj2Jc|}#S0t)Oob-6;|n~} z5u}e-U>_nd52{?7dpHyVFkWH^;0J+tpuyH^z82Lk*M&wz082cC5SqRGya>8dKcMNV=xpmF668KuQH^d zZs0{!Nx_AD(fbPhNg-`N4iFdgq=1kiK%xq;)>sjMY?WPFtU|aAgYc5C!w=BlT~9b9 zXm+Z=c{eQ=id>IX^s&X2?{!!q$?HY{dNeMyD4i0{ul8xW`?0$p|gK!jd12 zD_83(e~Qpz6KWW_=)ChJgB?*DhFaXIyNV@lP7z=29QXb0z2BB1bS40X5WSuk;KIR; zJ_1zxZ9|3lFNvIk(f4z_vpv-a+!tzc#^H2`w*6Hi-z0wX36LT1=g8{{1Z7nKlB0m8 z0tN&91Fi`2*XNC62G?ukj%Z$%KRGJ_|m&$nw#L=(+YlO(bL(s}{SM8t}{E%q=wJhzo#U z6A(i6z_)J$I0}<~&j`V7#pgQ%tN*4^XkJ(aI%(U6ER*eB0OF4EP z-JYdHJB1Y0n9IX?#O%|XgbXAfqA%o5ejX~7PZ9bUxi{)ya&Sk+9QvYI^y}Y zTI>Pzcer|caXEsgNDi$=&jbBYkZKla2pV|GcNiZhsSolH`HymwMQXB!Sux5mw zr-&N20jv#-1fBQe^6@06or*f3qG|jLb~D+Vct;b_(Y@KU>QMq@wC+j~2Gsh~_qpMRe82>(6iQ@;fA7eJp<6#g)&GYYpW4kCZP(dR>be72j* zYt2hcB?g2TD=iz3M?y^i{2wi@8>9-5gcw1`-$WiCfe;Wfz7e-$%q-O2?rd?R+04Be z*O`C#gN$FX;=u0_OE?ejAT9(|1t1RsNGuPKhs*`E0f@nQH4h+B1&m=;PKH4eDs@ET z`k(%^`0a55I#0pW6oapWw-eU>M0EfEnW?||jbw2db1=3^H)^E1H%pCwFHG|zeG3t= zr5KLl7=piVyNUQlYg`Rf+xg5?fS;i9)rd`!YWV>FM+|Zk5rQSW^u2(!5rW^78bAon zWF5f`?Q`cg%|`BLwG~5P%?-L9B)V6a0u(R}2AoXe)}0 zGuKCherp4psnQV`C(P)Oh+T>Wm{x#VVi2D>@IbNa?})EYcvkE3UM&h`rq|*w)*vVi zTIow&e;)O*2BunFzXq_LW_kA#XYq4ywfOZ}4En3JYU>i>#V*wXLiSl=M$pG|;{BtR z7z(Uivx1P-w-N>hP0l%*ilUV>X4KE7kGrteQH5Z4CdL!&VwQU1i37+oUUnMG(e=B2 zZDF>*Ft8y&vnK!sd+QSP$?2@uj2qT+3TxfJUrGlK9i4Yu#;cX@4{#c9p#j9G!=S6v zcmb*59M!$;*d`vxbN8s;63u{1#ZBGHgFwD3dLKK%RdwV93Nw@7vQ zDPh{gSUC9g3c)W#{+Y+>Kb)DqYWnorC+PETcsq3}(afI0flz!>g z7G{$+g%Gc;K>#MYN+5f{YCD6)kI-w+R~HTvt|`RmT~7a1Xyk8GDB66QK#tBDKf~5Q zexUB>KbHpFzC2z*i3Ob*Bzz^;wmDq{E#`dkld>9g31FOF<88$IDehGCimRoh6m)-; z%r?vI=&ua&y`@9}D0nI$gqqh)0L04zw&NMx!-#(J5Rq@N?5%Mo&%P&X8b=@mQwVuK z!A2PS5n9^~#CV+V*i!UF1hC!|HSX^W9CHC}U|QAP&5Xf}Lp(hk-xe=%**ivH^@PytZ-xYI==wh`U`m}#L=f2D>QQzq+nZw8 zMi#b&6}TUPHFO{Xu*lRvk^nSYCl&r_Rtsq5SnIs;V+ZNl(QL*bq;-9d!+w4x;2PT@ z!P}tQLn4H^V~>>_?p+GYy@0onW*4q57~JDoO`R}(25O;1VMi^@vL)Qa3X&K+7$erF z#ERv(C!j>DS{Bw5%Lg>B69ObBk8pw?og;E0aR2p5&px~V19(SS+glOZiohX`CTvLAmRZePB14!a zb|82U?e2+fAg5z1bOU#4J7nEn0l>a8LRCn$H3nILoL!I@Re=#`~PRiM%dkA1Ez*YoR zTNE1Csfp(Z%vlONO+<%l3le^gP2I$hSb@DaW#`ZOUKssvJb|BKM|_MKUxeA@1)?R~ zwmghBXatD0M4_-5k6Ni}ADA%M{Y?Pk`G9&vHYp)A1nNMKrOy&3!#lX|y&@-15jlh& z*DkCqLM|u90j9bjP}*|=X;$ZE>+*(V`}a2d^9=gE890yZ0uKp7Po#r{`sWa)ya>F{ zJmwf#s#!VQNCsP7My=}c{rQ0eV4z@7Qi?b!Ampcq{cY=#GlI5M+|LILUGs}VO4N(} z2YQ-v^U24FyyIFt2Crry$i~9J6UDPq@c{hTwi$y-?o*N%kT|=1gK!P{X&LU>7U=bQ z_UALEhsJn&Z301G=3@vx%O*~1(Dg3)9zp)Wcn$vUVFu0q0@QdJy0wJNUwjF8zj*;a zH11aq$HT$C4UmRv;~BxBYoWKdKv9pVg;g+ro>;wrf@xd;>hJ(k_QnZ-$8=j1njH5} zw)_X)7l6oBE4n>HaHmZ8vW2qlI)Xmdhd!9Plq}v7;sJB9W_z&oBcqGK9fuI8d-oDq zFjG&Kl3klvg%90ciwlLn9x$mc!ncDG1)wXY0`l>U;Lx_vGY*STw;{fJUwVxI@TSE& zXNe$vNSpm>w?g=J!hXLxw~Sw(W;gEHsD))f`Wj|-8Xvn`6G0xF*SjBv0P5A!SLWMq z3EGa~#;k!#Yh8l?i;MWCaAhpVCIrN$UY=D-Hg@MPVy$?Ehz>zMy z#lzZ)px499fp!Rs+Y3IFCi>wv^B`NTY%7KbWc&av(Wv#21*6XR{A>xrT8yVAo2n3DCMi&NC66L`2vLKzc(WfEWUpD0VBny1_6b(01xhf_Ma^ zKj>fQ#i2I9eD13Nf5ED$fOtB$TJR^4p(enwmLwR7!eJ<7s?-0z6@@ew3RM$A8%zMk zRc!6Ckhy>sz_9Y^{&xmTHk1bI3B(tY`0$zt&&F_50h*P|yG5)v*h8fTd@^C=-qiv^ zW+NmbfW-oA6i0&q!$AO2pQz*jG8T)sD4>S`YYG3=p&yDvfBb!t8c0mM7$V^Q#kZ16 z62Q0+Ci(kGRBfjFs=!o$p;96OSV}nK5TI$eAi!ji7Crh1U`#LpFx~1i(HIjq;)bBv zj5G41dsd_G$KCChMSN?0An3Pd!fRecHE$rv;7fFo2}+p&BzgjdYkodpgCf94+Y};( z044yoIWsg^{cW$4j)}7nN;LeS__a+S%qCGtwq3&38UAVUY^ML-cZZXfjM?jC0q8#? zDC^r3$a)4~OUBCsbb7zZV>ZA#z<+;B#{B_~tAeUt0A$zmRe(XiQL+b+EPP3@AAemn zAmj(1{CyPS-iiuI)(tI0<6Tz zewWXTFMDmD+h<9C~1{~PI zpPziLEdkRF7yO37r-Bfz8+e%|q|;u1lF#?Yz^E7c|LvX6YTG~%#y@Ml zTDfulK_HhrL+?H0)LZ&4eStvUBex!UDD)KqfkKaci-t6z4JjrG*jUQ9WCn)CSXmsr z7Z3cH+0j~H>GNu3Myo6GJK1mA*WT>M*hzJ6X#upStRDRe+#CRhHGmNR=1eOIvVDG> zTK9@t=m#<)9*HeEs)O7(+xO>Yqyn6yn-{(Wbl02%`~*H%z?U&FN)KqKN=ZebZDry1 z#km&N`up4XiQJL@rg(Hrc1bYzR64#o@kDZh_Fbz0?85&HjTI9BnVtccAAyr&;1kP; zKO6$@1F#)8ra*iSSfLLVw5Jp;D*}JrysQB=kE7Qv8R|7loBGGqZEJGs@r&s}5 zK`BXlVDo~V;y>xbd?MU`z||a>nu6%HniY9PYO+K2$)00;Kp#hh0E7ncfq1}G=CkdR z;dz<0dHHmE$NQ4odns`?YvT>&d-yG&p%_N=^#}-CBt&AH#JHySq!zp|6r}B??VYrp z$w^+RL{Pm^Y6fgyh`v^*SIbr02P5JfiyyZy;ZTK`&yrMMq^W9CVBm#di&!` zy~cUIzfS}BJs@n8U7&vV5;tS|K;O_mQm{XG!Z~c|GDd%d37Hic0c2Z;R)ggViVetM}~@8uZaEVWuKp{~Tar kZ*!dTMc2Wyv5l3mXLsVje+b|vU;qFB07*qoM6N<$f(^h0O#lD@ literal 14500 zcmWk#bzGC*7v2VpF-F(ufiwt6gTz1@C6w+)Bn9ajjnXY$BBi8+(~06#u_~fb3j2_9p&2wHHeGQv^hWkGN!1gS7wv1VBwu zUe|a2AkXh3<@EOlxoN$Q=RRYyy)XnRY3Z%1WU93YP`ZiHqyq~Luor9zLwR>O7 z5B6O>H*(Q8Q;=+5(P1qL(L-mbE2^FZCiovrcrw5zZ-v=Qb7ZI3-w@Aq*Kc|Gj_Y zm5u&O>Kqz-VBXn^dIh>;;c4QvfC366%=6S=#MtVOSk-W-{nC#(EAzTRV- zsV?o)aiFrWeI)pfXg@XD8K`*TAV)E%mihzybAZCn;dhxuw2@d0LkvF&{W|-rZwjwy z<8bKYI4cpDknxXUnFquC6z7};G5-;X$7~)2Y4O2@6xW}z9K)qS49-EJK<$rE-m%C` zx;3uNkzQil#R1LbtkE?N!%5JH*El>yKRLx!Q@ss(Ee-ftKo9~*IawiW+ddN8>Xm(F z8Rhji9!ITIm6*Q2)ign~P>V|uk!i#KC8_IgEImG;c&wLOEXLL>ZyPSG{7teyZ+km` zX>Tkl2l|UiRgFVcm1AIV?{|+!s}bTGVLb|H$h+3U;9NTnQ6EdyB) z{2^or%EjHkQA)(a4ZYSh%*C1b-CXn9D}vux^g|cky#s%{eK;3t`xJ#V8l~y6wbVj1 z#m<4iq^2ZYwJdH0Z=-7Qi75$4hvfqi@&Yyt^a-KEp*1)-UE2T%VB@IQODyKxQu~WI ztj-*SB=C_8^ryTP!Iz|^<_Cp>hBPn^mXz8JgnqdFecHbXx|-!@e=f)x}9!C}~ z_KPOaeT+#Jn5Bx7|GP!1f%X)G+^mL2n(45-MCgZI8ou({vpisNr^UDs{88SS4qPLl zC^sgUbRqp3iZa}S#k`&{v}9@*CL7ghLaG>L5r(Bvi*FPC#0f`jYl2a4iGEOE!iaj7 z-Q=u(TC?I66Z}vhFkiR|*x+h`OHj{hLAzj(Kw5G}u_V9Ay4Cm4iGzPQ+L&>n&sg70~8?fmp%nBJMq_Hk%VdsZPDY78_fhA&P+9F9;FIq zu9$V`UBp>!YD^d|BYgOmKQ;fxM(`aQYyep%^5MrD(vgI>TXgh7@afi+H6SMQN?t)9M$PCE~- z$Q1Ic>HF7?-LIYbD#^ck*uQeerwi@3(Y^`tWr0yhoN7aGx&F)D;rX|G5@p}JAHJ5) zAOhrln_^}rq2qFFhmZA7s+Bp#Egs^q4v+kLIzB!ofjBNZJ6=|C_kj@z_{&{>Q~l@` zM{*lcUeO)A!!E`4ntpxczsT?Sl06phDYh)yxYt7F0ELE#Am+u~=;u?tAnqk8scppm zZ~X{6s(AD6CtUH2EVt1`n+q5PNWYLP1B@x|Ma3l@i9>sLJw z^&rGkBI+OzNq`Yx13IF!91V03{vK`E5 ztc^tb{ok1H-@iTBfl(d=uME(PMz3G3Nt+QtP!lEG-x^uS31;HabrdIoO|dF*sR$3? zEjNr}&P`5Ym+Oa_Px2|`A?TwV)8TXPvD-!y)>{Ey0B%wMb@obh01>l^C64y?Hu77O zwU0No+S4Pzb^{3YgdwaedL_O4NgNzlmKXI=EdHBIYVv(9Fc8B0d{%ia#0a=rkG@## z#{ClGgu{XoNy>kk*>in1OD{(G1X=VE*u)8eq5UZiFYpwV5E zHYY;G_7cFQ3Ty{GfD(SFL0xK)NsUawj^VZVMC9kaB(VwwvaD4bCoY^FZH28Sm%Ux& z_vcojCvt=Jb^Oc#k>Li!7%c|oF0rImN(m++mwcQl@F*#k zKF|2xEtviGU>L+wIP=DLFhjv&2Z$P?T9=pJ{*=!7XWguc3Sdu>Ym5pkvXHZqJC5Lr zW8gliCs!i~!Q(q3+0vM95Z7+bLtm6yTyin==C9kh+W=4M{=`@$Prt^gV&Jq2fQN3r zl&Bvz&{I&a-`_6j772Q+yoL+pkj5>m^@~-G-x;qZxqYl{zAX1{D-ScFf_wNq zx}9|WQ)pJ$e_CtRJAwvufl7F}7Qj_uSq1G9sb@xylu5TI%LXh&K8Y71-C?HhzEH$h zB^`cR@ul;5Hllbb$IHY_-uX}S$FI_l%}dIi+V1Q*k&AYi1r@8!1oC?W00zPX5Um7E z(MiLdnwLzw35g(0xM6t5^m*xGUJ}E7?MkfuBcyT!`E|t;cfDO#MAl1EUmPa~92#8j zN?Crpr*J8%q_keyR-mQ_JRbY?*SgyJ0AMy|FqoWquXHl^C1_lN* zCK=POjr4;Mq~#O}@Ftfs=LJnD3we_ZCp1z)s9=nb= z<%Kp>!rF!ctpf~YdByhJ-S2=0eQ=__fH8!}7^H&h%px zA*OHfzBT=txa<2v=KDwevQ6xt38RVo&oidlCWTf1HoYMI$!52e0Td7?Dng+s`LiQ2 zAucEgCDkjq3+pX^0xS6~7*~6QPY+I3#T~BS-rZG*vA%*aNgGl^Benir-R3%rJ#A=c z_!s}(b1RtZS+V2`gX|KOMA!22a=2ag=KW{K!$%QZsWa=5q>_j-rj38k`7@m~+pjhY zhfEWatWh7J23x#{S*f2I^FtDy^PMEUMrFN0o~s{(hNU?D|BYztDXk9iT8+@nH;(z! z<=;t4N5AT>iomX`cz$gY60;d%c_b^yjr-SG(BbURtfRh|wO)!T@k_$bXL~kvg@Uk> z%E}L|tx~&tdrLp(=Z*gyORTwnRAu`kTe(%FeL)wiP=t;mqJQn;Qu_64d{dK{v586i z@87>=4604PZ`~Yqg?RY+NuHgZ)zp}^dC#{Ub>3*Qkq>Hp6kKa@mk88Bkj~0c$Lg4w znVkkLAN^4S=mn?1h-wY$qoKXwRC75nGo`!it#h{P1ctYUP;zaC=cYpTC*EHv9@9i5MpXm(Yj|DxA4S8UKKT4#{ z7kiuuGMn%^-(%~#hD7mY-)9VgnC?G)G!~0ZBt!On#>3=JuxIO;{8T%%!irmoA^ZF+ zCbY5dxAOhf`F1B&L$4at>O@Wd>1A_h zqSb_&rbBh3$7b_uVT=7r0OU0MkyPPxK!s&eDG^bw-)2_eU-}jFtdi7-a>>Nw&o}V^ zOgH{4ikk>IF^$K_SbeWG{1NGo2JBZ=znplgyFJ@_>k(F>Y_%97*ZpuCP0Vcu zi4{O7(z0YyWQ3_(pNmrPMZ?d4( zSkD$c*F!PvnWS)W;+vvq!G~j#R(JJxz-3;6t&&mA^GI|^ug}q2sl;Gvy}kk>03W>a z`DEI+slUe(O)eBz*hvYsZJ1+asp=Mm^~&IcA}3aMMa=|vzq#ZD%37Q-V#+Xf>n{<#XwSFrkbP3=mS|lPV;QZ7nsFl;BK?yjL#44VRA~{q&MsC<~ThXJtga=02NQ)P9VISAVV) z%K+Y>$g#gZ`M1?@A1BNucO)IA!Vr4*pYW`fbSO)NiLD{~$jvK* zuYc?o!|ui*+oCHKTjD-m04}QWayWt(N*3EE26&~ zEYL_$*7JTn;PPCx3gcOCz9`|-oJhksq!M0}Evns=8q27Vot>qLi#Pn7HlUC>l;BB} zV>0(Axar1MqlA7_*F4hj@lx%;m8WzdlkfKH%3y464_weiSB#h6a1FZ8;-Q3E(-2LO z%i>$w$bqeYY~%#a3mkOuL`kvGJ0xkE=G%zIy(YmYi}bb0!Wxo4k0!wGe! zZu=TPokB46tHeK-_yq_K2~ZPeY2k&3$yB0*UOe!EU&s73yK`F*8?^O!1idi6RYwIM z`FSfNQ(LQPkv%=#^&g$I*GJyPc=~#)b z#6Ac?3Q2ocq3#DL1tHDV`MvxPh?d5&r-K&?=gzTuwUTu`)0LZ?s3=HJN2-z86L9o> zQYiTLceqAANw4M9NR-b zJzu&Jvj(WB`9B~@&mpynSfwbfgX&=iL~@DFIUDxlg? z`8@lWdpAEnzvMzaSW(&xO9bMsOwLNf=81m~fo*-<_+j=iAzI>rbXD?CKJPzvEC$v9-aj0l+|2G%$`N6X-77d z`qs>J-Szceo&Q-6h=-R~5`)HB%8i-%DjH2(>Ud&%z5Ev6=@Ya(^&HJ4BxMN1IYd=( zc8_g?yNUn7{Beu=J748Rbp2ai0)DSj%7Q2Kw45V6V7a?OwZU*Lw{I5QBGt! z0BOZXw~8|YinL=S?{0(xr+J=Rl4(XqC)tK;<_;whU{aZTZbIC%b!fJ$+2}!)=?cIhJ_?mq&W+b;*cuJY zoy7!lI!*=fEWTsSi*ZST#Qsw!oz292V~fNZ|KnGN>VRfJklw06adtJsQ7evgz7OC9Nu1DvH^@XF%b!_ zF}17)w!DDK9UFn)e_=93FPnqQ(|M41X4o1vdG%elf4JOonme~QCVwdJRX$4nZudP4 z`>Cyv8h@szSN%mB)N?aQdW%7oZTqPWxO+%FtfpfV($$goh3`*oXe5o9A_sNv_HJ=; zaahp#+|Q1m+Fak>svCh=^E7FI2skWd!jNyZ9QFN~<$vT^Jk=R~;Sv9FBt$d_g!%bM z(o0w6rgfA6wJE`x5ehksxF^G>+*Yod9OHZH*Lq+(AzCZ~w6n9LgyLai@S;eqfkc#5 zlJ6=|N}z+Xq&Tc|OeUK4J!#;XUff1wO)m~K$-f)alIU6L}NCunl9;UxbQa!lwU zY;Spfpi$sZ;H6)1f3xDg+*TN2_29A(VjV~9;3%-%|_0xevie^^>bf%rR#j3>@FU_?XvY#LLKDW|jai8yB1GcV)G)flUz?n^wlwp&0Cn&<3I z_NH=!yJv(E&!h6pkA4TZHI+KT+IZnuk3=ej+6v8m1v%$T^^&BvT)){L)#MTA{D=*i zWS(2(E%*Mu$4cX!avS6Ppl!OR88NxX*gU7Jr}w=M7-_V zTyAQg2DukOz(0I?w6gNm_gwfgtvPkj_CuI?DWFh2gjI8-9FP(ce)VkaPswU%pQRF` z7E0Yx5JLu6LF+N2i?>!?9Pyo-5y{ifmqkq~5uXD9ITV21L3-^X z3()}{(=RW3c0C&kg4Iukc*#N@+7|wlzU_zo_Z-Zj$%YwyTK(*6st`aTy>1pz+2RxP47@+d$?@hxbZ032YUKtMH3} z=I2;wn?9QMsORU)%d7({l1q>!`46HP9x=&* z{wx>Io}S20{fRza&ij{tEAH1wo?tgUDCFU(Bg^YlsP2k@8H)b6fhhcU!ze4i#xj_g zLDkFaOxgK!eeeeYFU#`DM4(4^p_6uW>GlF{T7^5 zm4M$`xvDBh%SoEA^!1e=?(brSvg!LM*N=27k$4g9u7z|p-}(V8F;VCtZ=dWzzyVE9 z+Db3VSi)V*z0kJGs)bNTWf|Oc4>bKWYh&^#vJ+4qsXR^a%(ocDbC#uE8tCOO2w&v5 zzOaW*1KNhiglLEIgEGd0F62EMa5A##Snce7EX+ej^S?s*O%o_lR@qZ;-o||SeDiOD z%Slsu0?)ZC_)e806`MI(MaymjmnblmKs*>W)c*n}J+gwKKHx3sb&DkpA&0-Z-|GoJ zLq15N;RN%^=%+~L%WJo_UxcgRtB?gs?o&ME4+^}gaAdb7>7)oZFYm&7G%qlN=N=C=YPqQ?^U0c|(G)LU~1 z8}r|hcVGL5A-%jrd!vYW2ijAyh?5l42EsViK8vX;Mk-?#nrZnSYzXX)-mPuAp~C{n%Z~S>>%E4ZgAyY8s)7AH_@BpN`cIc&aR> z;ft}Xq~UWvDtp0Ui<`7N8BO)K-|C&0RW`@XVVl69?JsfsH8bze!f8Uf({9tDHF3y} z4%3=Lwaj%meWAPpu|ZBRX=d#0SNG_5+Fk| zUj7|*4bu+)Lvw>QHm8j)M$`#n?nSjpD1a=G#T}EO@mxiM1lp0?-?zBdJ-!vYoPlls zzRkdHM8oe4cLn|*kk4>7Q0#aqKe-1CW@_&5F9-%%GdqKB$m5jt>@yN*aWi_HbVH9(Q|KI#h}}+ zE6Usp(|Ex~F{P%5=*a1hUCXD!Sn%dO?9HYqkXI>E)-K0`z~Km+Kb3IBJ5{%lho*D< z7-lAdij`riz0a@jm+kfd zBO@b9fLgxTZ<}}n?(TjB;Bon+H=&INz3Y3cB#nap8LwoOBSnZ;ysH`gDHdf3Ml~cF zx;#B?aP{BQ>?ytHvee>1Yux1+lda2+ZIl;CrO(FEel#$DFY1`mps-ax3~4_l=N`$# zSN%QxQji zs;tCfW;SK!%aSbVS(_i6jh4r^>N+J4)!=7oexs+eiS3p#ygaLEz_k1oEY@*|Z*-LM z@((yvJK1j_%TVeYa*PwF+y1F~EgvV@%99z2rMwD|{TY z>(A4n+GOf(vRKMTNQk_A6!V!DDGqIu4c%z&p39WT>j!t)!Q+Hq424ciPye^GUFahg zFdO84;pZ-&X>;gIj!QoWkn@^lFNT5o08)T7s(q?Wdy|W$w`OlRwK%@n68z3_vpzkD z4Vrv`$yrI_q5N>&Rn07jGAb+33^-a&z)yKDcQ(|+uN2hqbbg) zKtD+h{&v!ZdL)F7o_=StERlXmH|&g;?QGAlaA>XlJjs}O)eZm)&$S~P+#-0lg`-Xz z8jKhK6`ncMEOa;p{aiv3>V zWGICPcgD56In}DeU1t5Im!7s{kW^!$9C64sMZfHgrA3I$xtY)RCogaerQcAxVW(1Y z;-Sh0iB#BcoH573z^Dc(yzNb{Mh;%j!u2&rJYNkRsqRB=<( zhK7gdT$-1*Q`@9F7r^KNoj#m+`c zHcK+(j<>_unE2}PVgNAL0Q!IH*Ku<`oB%3mQ^{L>t}=X9Z|57fc?vh{ehNN)y7nj5 zstjZuW*@JN5Jry7pl{ZaG?mdbc?Cx zcWo1B!o?ly`648-rFa>16NX3ikB0{?>B>-t-9lUW!;3$eN@jkQQXGW_j2(gH%kt$< zZBSqt>vW7DQY`23F7z{@fkSxy8=Sp-UyyQqn0z?tjA?kCKUOanb;}NXH^6eZMZzqb z`&vXjARxd;XM0$H;`@nuj|%gP+g}<_mVLv=&3q=(hrfH>HCbWSD$44Ojc=o@1hI@- z&swd;^6~SL*vTpfeaM5w^VrtMP)*Wr>*#D@;;DOFyuUyT(wS+k0k{8nK%`$tPg>69b{ zalc&>K`fJYo5uZ-M0UWR#neE6CjR7JE4U|0KD^db603DRQjROEtQ=}w^x8bpkiXC! z{89y2Xo}Sb?<}V<1M0J(qe@Ttr2}cOhs5H%tdss#u4%$VriG@F5+070 zbn?Y=a8CGY{oQK3Pu{~Iut@-?ylpUxL(*}Ti$?ov;4%ODX-RM&rIH>}LA$&hohwNJ zCgQpFcm)n34m>w{lPTaZ9YIj*%J@4BFRkN}H65P;>AWnhD5Q4(DRrRhn&+``A=fLt zzW)gM3rmWCEL9QF#Ej}(lsuJIi=UE>i`%luYk6=dG6Y;W$%a&_&`TCeVVx;@bu$r}vLFCa6i?0xSlvRjGVz*SF=ES0`Oowzul z;!{+{dcRz(edEUL$ufroV)n`k5=#Afr9`7jLc0dqU(TPX;ZD=$a}}Dyj4OpdGF=|G z>iP#FA@bN{SmA&BHZGEIiC$Qw`3Jy5Bg4|n9k@ALM@jvdHDp>3_p?^?sOJ2JfIiNZ z_Y0!IVS(rq558P;AlBpV*+_dKnQFD|!HWw<$C24d86eePZ6^-(Cn#5(A9;qTMn*s( zG6_7NA%E}uF_6%--6!D22v4Q@&DJa0XpgAY0q`ZeEEQFhK%jbWTA$1`m8 z6ma;xtWEk0WnX5c@j0lM5Gwk&BNDM(S&l?#pWc0TbWJ0P@!G=q@9{f4@ls-E!~=)7 zKlLoQZ3lGCmC{F;l@*L;CqLSebD^uls-}_rT+3uHlO4N7i~`ZXz`*t7cNKRZvUA@5 z{LA1yYo)Z*ODVcXsNG?=9V~1nbNv`7kWMrH?63b>tvJJ%1psi7N@3IcCGhf73WdiZ zTZa6ei)J*PoXtrVssx-))Gqy1`sY44BP1~h*dJfwc>V6bOpDK$nXX?F z0b)8v9ZrBO_m7)PJ`QJ00kxL@!C&g>B}~{YOwG)^($nj!w;MJ+`}DHjguDu~@TZ^-<{ZBZ|gb-xMuxYCnnc|}f`UJ<)gu5TO$cWp(ma5gn^SK_F z7k>D`QqAt$MYvcc(r@o~o&DLH*6bXDPcPYqhx4F#em~axNrP_A*{Ngeoacm$^v5^6 zVJo_iKIDJU)2INln|5$ViE|eE5KiX2_KQdM)f+2g8k`wx26WHhNZx$@dLRsk?j5h* z6V$JVQgBt7irhnMnVAe0eYcUo0XX2606;kc%bHPbY;4fqDNKsQUgL1(9S|v|pWup7 zoiFJkxeCVG9($%w?3=MOKyXzZ-=Y}NfZ(`s8>v}{!ZUO#zBbrW5YCqkEZy$X1#V{u zMY=5fu&yg^4VZ?h8?Ei;Q!ag;+$pAhl4Aq$Pn8aSgC3*c(j%`n>?HyCn-%T=5aglS z{yzbQKR+O-z|}M2%7?JX^0c|HNg|MDMLgebFZ%ktQO#30 zTZ?F0I&QWfNJ}+Si_kt&b7XUx1FPZ_6eNkw5^A;+Ysmk3X@lu z`?7a&7CJ=I)WzH41%Mzs!mNehpAh)ZXhSPsH8c0^5%M&tWVQJ0q|;e;@RkW_PlxH1 zg4%Z$Uv@LggejR;+cIAVL!_&drNkPF$)O?nyQK0Rn({oH*jnvBsw(!fHLaBr!YQR zbd$?W{c_5v<-#83AMU#aq#qEg?l1AZdG+&mIdDl6V-M&6vUDMn3ZO}}-H*)>Cv)&n zP<>Q1kTTw7@3-I^jx7&KACu;nhm)TbTGUakE`>h)XE}{B?4SLw6Gr9+|1**LY^d&~ z_ivNoG_AJo3C?~yQk&@|kOYT|s!%<5sxxrt^5xjs-Sw%;oy?K*Y;HG6q=K%#{!25n zgM2+bJ*DTLbWx;Xzkln`&(C9vgHPD5z4GBq8rbrNWwL5S?S2&Xd&L+xW8Yk?UR6A)B~$5@77RoByi{FL z^e+P;Dh?3>3q9i#YlnkvCB!n5Es~bl#vH6{gSAy`Nb%Z_xfH6Wj#uRmwcSZfR{dee z<;9VzM*cn`AkSriO$H#?WTCSy21I@;G;$%MpbTrX8#A+lW9vqjGUKG0xu`YiYtxbp z`<k-M z;a^Szt1pa~=13%9mIq(vYH-k<WV&6|=r$F2RQYz!fE zU8H&yI-*S{R~gc-yN$UxpvefN6=xNoj_y}YuM*Igi`Z@%=+zc=g;IDhN%LJf5)Gi} zp_W0hMNS?&;Vku)yv_Yj-SA(dB^f8g35NxC8k>%Q>(-FzJD5qOwM&zl`$BzCTpk8@+)SKC_4A&8bJv!tvgvxS{ zi4dQ?cLBeE8$m1kV*4KeWjUAJ>(;Uai)Z7y?r+YZ`>WQZ0s}Y_^v3!UM(UN%%ge(n zCDI~U7(y*)jea|VzdbYt6mBuSsy4Z7-3qFM{BH8el&D(v&A4UkhAR#g@qvqkAU_cd z-lN*I5j~{D@?4OjB6NeYhZw_32H|8mv4c*nt12R)D%>lFEWS;|9+zsZJ^H{o@Cq&mVLM=#*g+`#vE+O-WO+TEQ~xf8-H1*#H0l diff --git a/hi16-app-kpdf.png b/hi16-app-kpdf.png index b4616cbd223381b957f20fbf3d5f681b89ada806..c8b832af5b23276f31c662e9ddb79bb6e33b0ab8 100644 GIT binary patch delta 676 zcmV;V0$ct51^xw)W`B`ONK|nY#()3&m>DNW9Un0@W(r2x!nD~Wxky^{ScD5HTDox| zZ4v_oqg=I!poI$;AuS>ZY_DwsTV$_=NkLJXCXJ$zsdMk#JCA<{86_7cb7_+S(rMT2oaO+e<*L+4e67GC8>PPu?{9R)5ROr;*35u?{!aN=h;w zJlY|C>o?4mLeriC8muKqZNS(zITjmO6Y>E#DR1@`koXDDR$w^`W;T%+_zm90=+RMov9WQkXm)lz0Uh&NzoURn zm50}_=XC*Fmw&JGQYJ|C_31C|?K)Lks~^M1ogErUrJ{kF8U>KeX7SQ#^7%YYDuuJO zgg-uxxxCDq{(jED(P^dX_zQ*uHCA;sSs}Tuiz5QAC}+Z9GQ-38p2vs5L7KX{cpnb0 zm%)pdN=3E>JUC`YBBX`v`aWr;@FymSClVChzRg5S3xCbc&3KMOvc6vX@G1%u&y_L& zj2zUfP>8gUebZ#$&=9%qZdNNQ_#BV3|JpTdtx1a|PpQy5=t#k0F+2eg9e58&r=xWS-F0ViDd%9v7>mJ#ZCZN(=e1t3azdVZ`<72q|R|0J7lE?lY*i&En3AQQ)m7&vpe&4aU=ThffrtQ-uK7z zAR_#0Qpkiyk4`3CUAO*wvtdJ?RRC(yw!a5ZPT<&IzG?O^tbbcK@n3+5uml$u*RCx` zaQ6@Rr5`X|2fJ4V2v~FAFT=xM&-whoB1|{J9uZ-6fC%5<@mH9yfLSRP2Y$fE%}}iR z7Qh3guB3f^r;I|u^%@#f>BWoBv*Y7mcJ%Z#@9pm1Dnmo|?9QFjHB(bdMd+Rp8KWu@ z;m)~psjR5Fe1Djk5fKr;zhB-TKQ4Yti`;`ZevHX|m?V4U#iwSZHYAU7^6nvuCkI2z{SOsq7eZ`!HJz_W=xn7BiDUYmGHD zgm?Wq`t)fG*X7N%YqaL`L|PMtA(2wn2@xrZ9LZ#}=|nDf-tujGi--_v&2nca%kAxa z9vR_nZ+|a`_V1^nH2`svpdH7ocHgD-$%jg6~Ry|S5=@N+m4vT!X63b$IbdUSMAgZoJ}@K_bv5)HqO=g*pd3109wkxOz}Ts(_zdup;bFW?6HUlokYtInkR=c^miS_#X1YzL+oDb&1d{=aIzY&_ zGNA2kd++h&25uUBkbRSHekV8W=X}q%=a%irh6DLCXQtDMM1OxZlmH67dxaV2(T79jP@j7%79o5yne1LqCR+-zSjbaRQHrM7GvniP_s7P*_B1usJ<-q* ze=ssqSE;JPv$WJWy?_6(SY18v)$HusFT)fLhGihfrhg{k!Y{XO3Cpq^7YYTD&*z;v zF)`uHTrMY49UWp>`tR0Ok?!dc7ek>G@EovbBdOx{2C%AWjYcGbZQG6|2nlwk$K!F< zW;zXCFXo*)gxcCz8W^ByeZ8y>Lcq#KQb92|<@1$mn&tpxGURlf&1Rhqa+8x-i;MUZ z3C8B4*RW*`37Oh7O)^zg48ggl;Ds;XeZap7 z*QderVf^ASvU z!zCcATM)|{h69vGcBcC9A>~6uWaROGIDDAa@^XG%UMAAqOjuU286xNLAfd*q&^rnh z&nwEg_k{Sf4{oYih?{``fLp`PsVNq2-{yN+LF=JI%uP%%-`Pn`O%1X#*Lhth20H<( z3x8glho3s*@r%t6*9Gjg48uta;M6cY%&r?ZsF0gnl?gMaPSH?T=bj31zy(bs0u_KK z1L?PfcqxLL47Xo^KTe+HK_bCD`Fy#wl(vQj_kPQ3>HZF;qEHIufEQpH z9vw@idH_RLVUH3Fx=;XH!i=siBC5*N)PIzFbO8A|*IDTu5H9+svw?NM)D?&*B_(7s z8K+}u=SzOS-?2>TSiUF@yi{%~?>qoGnYsi5fL?Tm1<3kM`0mNGXOGPG_v^N*l2;Vu zqyWyeyk2ot2oz0IBoQ_STkt;;0Nc$?|jbh@q1tyreU*x`0#Kcm+M&v6@P&BfA55r16I&THk%8@ zVjI5#nS%pB0WeEr{l><(t@if4%i(eklGBNVTY%YuZM#pwlR$K7oJ=MUYR4({!A_QG z)&zX|0Q}z_o9;jU05?xpKiMDO87dn6zu}rY}8s2lk$Vh|?Q~}{KSg&7yjOppU zeM-IF2_wMYJb!|TJ8*Ua%v-Prr~!m-ZvIebGT!I#8juH81Cd7oGY;>M)z+F@@GFp= z*|x2_RA29&g;y6rqrp~;L+VOCe_$@3-zsZstHL!kaco7TD&HA*R?lrmCEddg27a80$2AoPrfguTcQZMxzNK#6!@sODXaC`w3+- z{FF+O*tLuG`8+?gwo(Th`k)6$KGcd*I$fcZdMIPh^Uz~ssID$j=g;%!#f#{+HgdTf zuIo}S{0VsOGk6z>mEoab2!EeW+gfXU-+#v#gVq}3c|?yKVdKe@6oJ{?{guQqPTxQO$`k}RRBsUq-~R)KkaZ43U3(m!bgR|!FFg50UM0t1pNj0ecwLr z<#OC{946y&+M1ez{kCm8n1gFs#G$&Z4S$pHV9(T4H{gT>thJKK01BYvah%<|NejWy z&`?l1fH5ZUk}<4+)FP$Rz#QO)EJ#}w6%>m_JkP`PJd82KVliT|7*a~4l$1&(lv2dw zafFyxTTg2$AhDo1uz+QTJ)jo_QwldwPQ0zJ0+B*L{D9=78k?Dq;XurRwS)i*Xya0P^#vOnEve6k^#e zTW&hOKYclr9e`F~NGN;;`G#am%kTTk%F^7XIagqRkK+Vg@KHYmLLcyXp<0MCvPA~r z`~IOr{!O?jM}L-cn-={cOzVZLSkwJWmkwnhmd!9GV)W%}5 zagO5*Wq-5T8>zm&)_-+%rDxUFx`}vv?vUr@v+eD(oaM{$Iy!9g*!}Qa&zLbsE1Q~L zO}+m5wH@%(Z=ti4^KKz6_zbtR@X{~VtjYZK`0?O_4?hf2sZ=oB&bGJvFFx@^`n|R` zzpt+^$ZM{*r6tH7I1qHiV!jxBtA)W=Uh%KNjeqaJCg5ISHerE|V$nZC-@76X&G-Ev zpU(&KJQx}p3UV5oooa0j%xpfZ>-Fa5Ao%#>pl#W*pl!#Fpdc~VA^555=7F`se4%PI z@~FT;i1%tyRWga0$SD*GNB|E>n@Z`(%q)~%d+ z?KS>BV+IY{`vQCqh=;vlQ~|CD@H`SiBoZMSjbh{>>^>A?!fcIKRz{(%jX zry;3{$XQ*8JR{tA_E{#aUJVlPw~ZS?p08f90!w4Izn_80lTl%xaKQNyyio^J!+!=f zl7QO$`0)g#9EU|_MQG$mNF*LdJsq#Toy@9LOgw)cZ~b~MXx;Vu?xSw%RH9*;grK5= z0`wn(-%N*^Ux9v%72>zngG2FdiZ20S3XIsyB2W+lBNky|&mLC3^%fb4>Mgaj^C~{K zvXWXAUJ$0x3RX2z0afyTZw*X-0Do2=fuDUFo(8T7Ss@6+QIpj}?5Gt4BQ_vnUk@GA z(n5`hD^Hx@RDC^{)~#cb{y(#DAw5f%vRL7_eHJxGdjefeKpd)pA&L0GpWy5&_~t&) zEjI585fflk<9rE-DYs$Rb0SVF@6(PQqq?<~p1pf%*}0S6*|Yhayu7UcJAbxsr%t)9 znK+TKPQsIt_dMdoAo=!=__@ei;lll}P2;Vl=H!?FqIRR4`Nif_d;l>1;6YqH=)JBk z-q3iKNY}4fL!U&wD>0Eog86giFgQ3EdS6VNIiZ?yKdt=SY3TeVZ0LZC8yg#+Yleq` zN)tdt3q2hjzZk|MM3%U834badBA14C0o)!~f zp*QbMMDc$U43Vi&et$Vk!>1xLLe9iF5eXPH0Ycb>>>7^EJHO;%Ol!hZ5~eDAcNlCO z?k`w6fjX!z35Y;w#UN2S1`|?x4^-$BpfqGv(H7dFQvWYgYfTDqMaZ)dOGH)#nWBe8 zMOvmgI{}y=AZ{-zjkAj8_(GxTzr78e4D{5dQnaeFFNoMWpMN2u%_b4+4YpeZPj#j9r)VQTPO^S{!OXL36OjlHpgJ83sdrVG6n(kdKrnQ0YLtT!@1wxL)z<_~73xewJ;&0q08JgxQh4cAZjNA171_?q_^5 t`z1}>658l6gdpCU{yyQ7kQ(W$=-&tA?Wxx-h9m$0002ovPDHLkV1g&L$2$N3 delta 2029 zcmV32zx0D?i6J#ckk*mLSkNG2)eu0K z&J5gvVeWbCvsXWyGgqOY29oY%=YBZ%WUcl8uk~O51LtrosDBXd4rk8%>k$0rahM4B zfa3pghG1%P-+f{S2PJv>X*uqB?_Ua2f#TOq;v_7o%$RYTb1n(Y0nexdv_lrU2gm1lM|_^?ezELs!EOfGdD$`aBXaJ@AkQ8x;zq)hd&r zKCfP#65Ms4@yCt3s~X3LSHRl8!2oas7(CyBC>(%4?|%oWfZPPDff+zh3tlXC+u5_F z3WvWBE68|n1Il00D_{FKJqDC7*#DfuYMYZX5f9;Aim-H`rs)e-qr42cL0zaQF1?2Gq1^(*oc3Cj)Jc<21Rh z8^v*aynix0-20#Y{_6C$Hm?u_vm)O&@$TKz-GvMB`})u@ZX-M}c)MCZ?yIJ@Dx7mn{qbv3=CdPkkKcfv`69iPvKVJN`K%YK5x)7&-I%y{MNpGwP4m-F~&$7 z#}Y-6B*ut{$lJZWA|evUvBV;Bth-y}lTT#Vf(5c`-8xA(ZIWXkzx6x=Tm!TN4QC6k z0X9Q01Pu+vVzz9oB~4R|F~o6Kaz7wf|Tkedit0J$p!uVQxnU{de9;J@CCW zb$>cxd=B|po8}axX^PdFNQ4txwotcf6$7{5&dvuP#Lk}0;(7B38XMVu>7@)odK*0aW9S6x z&eR7QP!?vI2@|l!5JgdqccoMO%9TO|0io;S@7_(gWC<7U z-HU(y^?YP4$F91H8IvZV$7qToq+BM2kr&{PQ=sK}cpey+_k=n{h!jk;&CN9mj4_$a zDMhLj;=1^I_fmNLaTaggN|>e$<$sd4ckNod`g+=?PDREjj3Uxfi83^7fTvoZ^*UI( z1%CGvxEDAI#DI*!(Gu6!W7Cv0O;Ji^@VhQngbR9lXxX}z`W-uXd*)0IUVAMQl;XWh zE@5!~eCD;cXT4!9uInP!l9oyYnK_9zz%So`Jxk!`r(r{GT0B5$Kq+Xl^?&s^TGwDt zM5u-#lecZ7vA37Or=Fr`{d$Hjx`=Ni35P`JyXPKew6@Z6;f1w68JiU2`ve(C_6Q6; z0XO%;M_0qzCtyu3POi=yp@DK4n~P79Bp9H1^JYBX=iUB(UfR5w=^|XeY#GDbw(-{b z^{7ID_KPoObab>o*~!AoE(4L8YF4Y&OuR%$90xCR$zwE! zZ@|Ad!jC@q^wSTn>F9W5I<&Z55X9h>>*_GZV2nXTup%5-zMP9+d4GkuJ9lDs?&RZ+ z4mPb`%_SWjTse0xf#(s&F^=OPB8W(qM4Dn82R|FTF%=Y``Wk%rTBUN`gO$oH20Zr) zm@o5rj@jNekZY>JbB&a)ds`ywS1QI~I3R*{lfI<+|L}(070Ama`uh0pC z+LVk@HMTpn)-~l65mI9?nFVS*bSetubQtn67++~>qFgRRp?^R;I!clxM7jQ#ibaaW zB7yJYdmcInh(!pq3eieY3Ibf$1rZbwluD!`#EwIAnl^mdHgrQ6Y^zl0?dsyABq7b! zPdQGOqShEdxh{20O`J>;`d)q+qZFbPR%=9S+;W+Q@#Cp$ZpJGXp|20?x(uc1$uIGg zsPRyI3|2cZ-)4h}26PH4%^gJg1-xu#zXx0>m7uNw1s{Ss2m!aK?p0@G>x4i2knL8|~`4%6{gVV!5~1c{`cx;Vf8q2woUz zZ+Eib?1wi>YBLxSVtbnz&R;oV6@oNwaO>sjLbUtI`9c$o{-=ynWeY1XW{fQH~zP8cZQ--=eO`G zuvkbFi2 zzOuM=Yo*YC+$@2V9)cd=y6Sw<_`8q~RAG4#L|C|RVFUd@Vp6l$?bxNCH<4nl=|Kunv?`>$fYENtH+|ibnWT~?=6>4is zg&G?hV~IqvE|E}^u=BZGX?SF$FfuaI``T--J<->H*Z0qJWD6E7SY2CNyF>^^Rrd!6 z2h;h@n=hV?w`>7RpT54#I=~l1MmD zZ`Ng4p=9B_}#edFWflu9K4ip8RT5v^w@PT3a94wQtVyY-xrfM=kt0%5t+C29z`-Ui%}@SeMvAnp}l1n%5P_>xN~ zKJf(OH8m_tr3k(JGN*p=3r=YC>VT#BJoBInhZY*BwPe-x4<6(F(Ei(0U_up zqc)lJlXS&+NgKG=g$eTB>!p(?37iQlg-h@o-yr(#yYxT(G>5+UMNX|)!PsS&ar%xs z7yxENU>)=~7&)=UHhg!T$x)ztxiOiI>;&i$hNq790#yh8B2^T@Wf5my2qR~Yq) z{NN`)3CQagT}0yEdwE+qk_P6BLl67|keb%M*{5<=HXNoV9!D|m^{f}Z>r;nPQL%1G zK%%9EqxauWpDNGL%9W=7i!Z*IR4Qd0ap0P3=mjSL{4rd)9o7L2LRbh)YXoe6IIkct zMFqf1blUKi+~STM)G2wBa>($84fL&AWyrgpSLrqPnjA|cupqDpGD%>W1l$YP0(C-g zIs$Ouqq#`L2yjcJ1o$y2X?Fz7vC3+8{d(d`+Js7|^X+eQLj4XX=Jh|_-Q6@dHv>!v z2uP#@JPD8QgUUHz{TXbz4lV$H;(|3D0qr^82>3ng4;BA$S*5Y?na_|?y|3TCozPEy zLO(F{@sDGxUxf^<`p+fr3Lq9U0*=D_FT(c@0vAHV*WiaO&^lF8hdfE#nwO_K7gu-rxf$~2Op$d?R-#qb@Ef6GS75&c1}!?u1NrYw%+Rioe=vL zJo^#oh{4U5L-$tLx*F~nhXJ7IpWwWz8uRi*O-+rr!b}-P963VpuDggRWX@H{#0mxa z_wQ#+FUtx8rt zPwSQ~L>_p6@hh)nK%w!!ci+vRR-yBse3FH#^HJ6NBaUNgeopxiRd{rDb-5wqU1zyD zWSnLMlu9WNx#G`%VP6Dp3c?E?tFLboiTgID)5G@|pED+utg4E3)0qUgWCi>aS5m~I znn}w`mhjsvuHa?Oq9^CiXZC>uT(9MHSe56bynlGvG6t3|MSYpF8CHn6UiY`|NQ~>A zT5ttef-U6#3EtWPpMO1{A6fX>&jzlUGiQ?${YIcp2)SE-!43e{ z4lU4+cP5&fm+`P;1Q93-43ts9UQ!V&HDB03oruIgaCpt zJ0tHad?u<8fS30dJyPGN@dym|AC zx7~g7sKUu5WkmSA?3PSFd3RrJsm~w;XF>e<)JtevC<@~OZV06^@<1#W!|Sc7%lunlI0wFR{k=Z<>~ za6IQWFs$~YLK=vwja2_L_laOp$m@7e!fhQ3I6Af>5wjahATI$~ z2{-{95l#u?Q;P8rw1kKd^^g~4WOfz!o_7V{72_A@nW&0FTF47FOl|)MY6|xe=TyOW QVgLXD07*qoM6N<$f`v&MEdT%j delta 3411 zcmV-Z4XpCj8T=ZMBo78+OGiWi=>Px#0NjTj(UBo4e+>yqL_t(|+Rd7Ma8>1<$3M?G z=bm%la&z;Z5UKJKC|QHEplB6kwdfEXwsfW1sUVBkvUTg?cAZAt?YM-ZV7qn;Vp|~{ zu(KU)5qBMSasO~TySNIjs}?0xG6XO}E+iqjB=_~)bDsUI6 z`~AKDf1W3T%Wx#1z8qGX5FUc}u7}rpArDx9g&x+d%MhmISfN-ka>{De_$^#88CiZ=_RL6zr}v>#ayAQOTHhE zZ@3&*6c~V4hU)8O3glsU+XOk{kjUQ(w*i%adZ{lSsjXdXfA4$dIYp6!iZXB$EWR8B z)C15utSE8-qY>-1B--CY#<^b^tIJ3xV+IQ{Mt7Xm+#>g6Y6!<(a1BhKN0?MOMpMtX| zJ^SzIkOPJxe+_Q{^ISg|m%vM)<`iY8fBncKvH&s->A!(C7yL}19MCRjO3*)owgHg6 zAoII-%YGr`ad;oN0jRnF0g;34_T!IB8)ODDkHO=>!v8Pu07^4d4#SC0Kn`!&BKts| zgu}p1K=nA0NMzw@yS-i7j^k(l7QPMK4t&-%y~_^17*hWS{(QgzF3&g){k9uDe`?M{ zKxE)Cd*eoFtE$XG_V3||-xqjX6DjM54^M(jfb4cOFdwKbC2$T_7oK@WTEU>qL2f;) zbHUI0eSj}&;S~HNQCTSyP7Ig3U=wf!pnEqBz`gm+o9%pAnM_0eNm&1f03JZ;hnG_w z9kLf>AIP(idcXk}2h?6@&28Oke`TwyWfIJ%U;}W6n=dMU8}MGGr}%~nsLjpIy8A-S zn{%%V-?RSb0)4PQ{nAUaA7sBnKz71Az_bJK`Sg!}oKH74%Clf@f{m8~e$2&B;MT74 z@>>qp)=o>-)Wprk#!9WOu2QS0s0hYl@n|d-jKyMhCY?41hla94LqlC}f4=$V_U`WP zf1WyZ>eN}YW-W_EA~!@L5!EmZ+27wkoY}nj>S#P(Yy<>Q2XptqhO4)2`=Y&ZV<3I< zq_q>i-v++~PCAu2!$4ueVm}H`{!1(-U)Z)yX0us2(WAe=U$(cm%R`3_jk#u9mK>Ni zO{RbLGnoMS%SDUi8Ib2df2Mx;LwT;HMVG<5D9|k-#*lD*&RR0x2bhLIKONFimreS@5=h+ zwk)eS?_KjWQ6zu*G$NP7+Pxd~Ti?R?=pzy@yuh&)D>$=ge-Y=dyNKmhd?phTlZ^C<=E4L?Y~=+a~wgYp7GEkgBUAY#5x{zMbwBE9k%T zP5@@lo=t4+THbGHVAv@$>o>qZxKU_AeY2nCq*Ne4C>%xzF-o$fCNtiAsVU|5?nRk0 zg;-4upR8L)fA{j`479c)gy5QMuA#EBl0u=tk%bHC0x5t$hMPNJjaxDYE=HoL0UM@d z4Fkh)TGjD@UTFA3Zf@5uqI2dD4~H3SZ>M|dQU+REi;}OZszOTX_*g840^%Ty#DN8{ zX020dL@(wKMGZ*!Oj_4545Jt#Jre$LKG2>9q?FkCe>|zSHp0myvE#>)-}w%`x=!Ds zMMx=WX=$Oly1E#}Ow&Y!!$@EUJl_e{m7x3?Y`McJp~DyQ2S0)ObcqJe7gAR3KQU0prO{5%5a zPFqmz*nH+;`1XEyGvhSRcWi_2x|OM3>ePy_evW2iF%(4^H#`-p|tFbkW+S*#;@%R|$7eZi~CaS7pI%P%7#Z>q&=y?(DeFG9# z04+j1^aFUqRIH{EYF7&MR5q2W~C2Y?ibLh!#ygz z^0~6IDx`dT$clCfBKcLVB0oLO-)3j(Q(21O)0Nw1b<^5o^RSfW(OSD zW17qU`{zF&nfcH|>YrYB-PQ-;b3jCK9idJt3K&Mwi9O&&n@uL+jW?jH3&S+I_0?Co z>(nXcm6c&{-pt_3FVneX30?Qx147W$)I?of-MDpH~pX%f5cypwoqD*|Y4ZlJ7t49PS&-6)P6X!AHL~sRb@2Sgc?)2j;gAt zs(M}x6n9DH&nGi?Ek4UBh$LLp|%m_buhQ?YMOCX+=_{zT`k8?)BTWU(y~S|2w^NkA!KO$WREy zX>H3-Ic9XRW=0kXe`pX*1%nudQG9W!%8O6=K3qC)SymD7`M`V6`iXei*fI=Mpx#|> zoaip5_AHdCpp8T#R0IN}qJ^jWadqh{%1W1F{3J{7^J`F5Ri~*j3<6GrA1hg|yr3y) zXTVf}kzkNQUmyGT?)Yw5iwHA$Jc9fAQeKvXR4wu>ng6 zY$2Rq_iyRV0n+!k4GapwXM|uFFoZyNuSp@0ib76N$Ou8ds$we&wxS?a6-Cz(;V`ju znySG;gi|jYe74a4Ayo@htcRqn5;U zp@32WdK`i=Fk)bYK{vq~f=nNzPCzfv zg90f~18UTa8Dc4A#D$bNSkXvT+(3yM6%h9!S}v5)aYQ3JE+dMgNq~eXBBCfD$PV3X z{d#%*)_dmr?>&EUecFa@9JJi2?rIl$N??#tdVoPBn%MlivL^FcCmIQXwgXqtlM60)z}Og=BIy zHRdbr#v28Q`29Wz9Z5z1hafms3%jw89#z%P0skfdWOwg2nK^R|HNiCVIyH8zF=NIE z2)i!>#sKJGH|KoULf8U-^fc|-tu|ApxUT_Yk17DmfZ+ykQ%jbZcyX~w0?my;TtE== zv;+7MKtF2^;qUVMb-*Zd*<}aJ{{6<>daL;(aOqJ6fK+aPza%fe+#CdqOL~Xb!gwPo zVL_M)TnykCQZXs?U8uYZTx2FqN|_!#Or8Io{lkEt;3zgn7}^AXT#@VA)$ET%JchRe zn`n>gGaNTq0CoVc0yyqF&;m!^H^6Lj>Zz_9je0=yIx`2j3DgK2IyTWC{tpxoR5~oVGAe6^a_*52kNl;~vtmG@b450i0n$KB_H5Dx;+DO#)_* z-PBrORTFTae$XI)6StuJ3veNTUZj#Xn1R#PXZ}gUHHG=4zi#Rt;C29Kl7?DL>##nyC0Dm+iM;h00Ox9mB`8%3| zWquf`iv{O*w-wCK)n&kZXW}hAZH}Eik!L9Uv0}j1skpZ4Jqeq)uIBatM zdd)QWS$UE#QDDChEht(Hj1$Rk2h1+ZbcW$^Uo7U0mjaJjNp&Da4rkrTKJzb`(@!_K zvNB_=KbZmCY;AtX_szVvFe#PNXsJLfYW!uQi$Qj*^Iu5utH7xkoEJPxg%g(=pmp#D-~cw9yA zS}3kA!-NTQOj#MQbSczw3!Huvg(_k z4Hh(i0h7%5@!9P3>8kdbJ2c5rho@@)18?D%{KUxAGJNfpo+N-!ho1(}msBD1)Zx)K zCgw(uPG@G%)+8rKhdLK5ZfxkR{=qXJl;%2MTuO?eg$upJXfNr2Um9oc0j2=xX2Vxx z7ce?=^2v$pf(0hySClRt=0gA`Sf|9a#e9n? zrf!m?8!ss-3H9&aziUNBg%l_~NxdA$=}GEjj7b+26(t+lcrCO)m&?8X>AH3A$Ls2U z8r1;}8#b&{yLRoy@R^fklZ2R}`M{R8_)~s27gT*ht*yyfb|9rZzuwmf1aTCY<_{ReXq(iVE zR8UZWZ47-p6NKs02d1$RM%Dl_F(9Jo6YUG;4j3@L5(Hn4p#y%pGN?!r>_k# z?;cUPngFi(8(=Ow{&=%$!v=Gt?WS99F*UWd-#Vv(&Mz@iwcNT<_CCX>>8_ww7ZJ$s^4RTaLiB|iHM1t*?}9Mf1M`g_bV*gS6@8f8P()u>p$ z9GRg*alja?pyqtRW#u(eot1olvaP=-gms_}%B5`+b;Qcc;byaNBN5PCm2n@nPzbbN z?Y;X7N-CA|=7+;!P~AOXq%|}&$Q*CJHka3-iV7YK>_P#V&TiTS`BHtCF38H-C!K`C z*I!3^zyO34+}xo92F{#`p0B-z6GDF9A6wM=ZVi42v|epSLsa;<8ws?X3b_U$u7XQ+%v2_hL+4UucPFXrPD z?Ya{+ifs>e=SX7n+V660;%5%z?BjK z^!LOg2B47ZX2fBC5r7h^uP`7R7YRoq5mj?F0VS2RGAgPsOp3P1J@pN;jy&_6V=0|q z^!@ie?-k*@J2>tk2O{U5i_P!6gW7)mu>NLd;fQ=dm;e~j0B*9BBut5vrB}v8Q)TZTH7|q#tDRI#d0YaRk-1pa!p3f5t z7sBP7W5^JH#*D#6GQXG1@0>p$u6&0Y(YAH&T2rO=kPi430a0?l=M62aoH7xwdR}H_)^l{)S_~ zu*Ja5{t!iNEr!Sfx{?41OU8)p3aRP_lONR%4SRa6Ay38<`xPV)j4+vZ2vB0q93(0I z-aB>xjPq&M4K)DP-*p!pI#Q6~K~(pl%>IITLyq@D1iJ#gjRxL-e2p4uafnI3?swcF z^|dhX0TUNG`)q``j;ztUcW?16>T?tTKbhjX&3^1FSxu#R1-NGoV2T0s2TG>`_fv}9 zz_BJthXufJPImcH12{oYRqN-au)8 zHcg(4E(~jxfBh>Cj2oxt|6XiwpyR72C74f0i7iddOT(&sS2QikZ>Bho_(@Q5F7W2Z zz#mqN<@zA>SqMB5@wK_+pMelo>0iqiQtX?^dRg%dHF?$PMy5W zZ@cWAK-64%DGW^}OXei()z{a53)8}|ep5_Mz9j&7+LYpYIsdr0!b&x@7pPqTT)B~$ z%Gx7I)xf_#qv0_hgnR&^pkOQjMf`wzcXe`_`wOXG$cZ*^bJ(^GWsK#OJ9nbwiYpL# z_+d1yT#0(nK&jI2F@>#QsOvm%AUbW?0&%nlNgJ=d7AdJ5DeYdpdI`9H@?G^U9`kDZ zYL03Gt}o?E%akD{mvG6Kfh*Pk_4@#vNa{*Z9tEb`pV^BPgs%a>yPaeprEt_rS8b4e zko;_ploY!pLsh@{1u7qZ9O3ork>UBCFu0qHzxCjQSTt%By3q0U-ntc41UAj}wut&O z=Z}vV0ir4Sf`mO`+#_j!LBPcs>)Ap90ZDR>@l(G_<-yu`;t62on`C+=$C7Oh;oLsJ z_4fmpg7fnWr?3tpGy%r~AZjLRuJJsW187Jxq9yzGq5Jgdh^||QEY&{4)HTj?gungj zSJ=TaHp~rF*VJGrYy0+-CL#2|1K1?eXO&lT$t8%&DGwPsm36;=7Ek#(hK6EI#Y1FB z0C0S6R0EWu45{%E;LjBGG{>07PAe!V9L@vX(Dv=O-2udJ@lTPBo*sK4LbJe-+@&qM zfdWRGdS%&=Y+ByvIet8%fB!pjl%z}M*RY0PNk(0f6qzd}-AL(oxbsdFU3Z-)`6fES zbyR)Bke8!mhZ87&SyLRIW|YAsDp*nr07dMR;-marpdt?d*MiV+FR+9l{F>_X@aXpK z!zT?KSl}#OI`2kf8t$TH+Vmr>FFFyM24@IBK_IPF`ilDVSt0E@%GmDS%TH1Dw=<3} zyXYbqf=1-gkMaDh1q;xf2Oc5T^t*U3&J6Pd<^rOcSu)&zgNLrw)zz}T2ZA1#tHdb) zJ!d#nX_7JoQTAHq0}!&LEoaXP>+b|!`4IT+@-=H*LkB$Sy6d77!r@0Q2Tu0!LnIWa z13C$mvUq_ldc+=;f&~%Smwd>jxv2B>)9`?kBuI!1{D_Q>dh<=h$b6R4-cwhHy)1iI zvC0cEEJ_rA=)!ACUy~}0I%@Xz^oOE7UgpE zHK)vUU&OB-i-S(EeO3lsJZwXbARjym)0EdCCF%9?#1k-l=153lT042xEc~1) z?@6NmlK9ZJfwF8>;Tgv>cwON%$Hd`yeBs zLjZ*G0ZWI|w zY3>g`+jri1Xh#W`G4vVhO*cM2^csfA=SJ%{d zue~&X4SQM&OFArlRzRSm4f)A_WxfWq07Bh7;PrLDmZ^_FeoGHv)JJ|I>V3_*6{yOw zZ?q9WlN@dN$6n$j9ZGJ~Ll2?H%{QZhj?Vk~7hfPN1mH7 zL_(?snieZ*tTuFDJ9wT-vN-@FK=8aTxWR8Mgg~2r zE}}zoZoeJ-SO9I^ycvcXQc5XyB;%s;r}04ZAkX{+RDCaB!a_kaP>s{W6?K#u(GaTv zQK0xR0YKoFq%0|^z=W*>>`X#ja(sS7>v@%mkhc7a&=p`vh4O<2!`fh~xB@8sGM@8^ zgHw}I^$xUP!KL0mA8-Z7Plm)H`W%OUs(`Y+Up?A0Xt^0-T1e-HZ5_}_2KAy^_Gnv? zSLvt<2BjbDgC(<;uVr*r$_%}IepabtO}T^j^EEpBYSk3Y=JY5_Bp6&X2!y7++W20+-_gkA7eqE4 zE~i#i<)y=I0w4l(krkwn5mZ%T!iY*kDd@EF0nyEC5+x>}nxh~H<-eyfKX}9*Gy^>v zQ&2?%q#%-dBX&pwoHlEK^a6l?gfTe~6%z>l^sO12^g&X!4U+uHOb2Fqu~su0FF3w_Iu>WdDAAWm@(s! z0|dVQyFk7c1XMa`5?xs$?_l_w#TpYXvnbpg{s!yUI%NkFh*|Fe}+t@H)nE zqnN3r;p`KfXG5X>k71ilz|;YM=?R?jU##%-ud}k+2V#e@t3=Px#0NjTj(UBo4e->X!L_t(|+TELbkX?0^??1o& zJm>T|-F>>#>F!7;A)N;y3DAL{36CiV4k&}nIG3>?

B<;>8*msT!kzyu1j3h@it@ zVWb=!C+LV?)Jp`ejs#{HKnU*yf`Pn9cRK0QeI9$C{aE*p{mAZ42ua|Exp!CXI`6%I zzwht6f7bf0wSGr&_z(RpSZKnLO~}6tFPsgp1Acr4fbjq0@gx)k{y|z=Lb>WHkxMTX zfk5E5{|09P?SKtvhiORaaL!*7xKKcX9Xn*)v3$7*RPKmCm;~hhFM^zWAJ+cse;sF5Uzm>fFpqX2Ve>c&_g(1&O6VQsZ(Vny3g>j@TZ3p ze*gvKH^S$GDN|(FG^Gx*88*HJ>phUM7=SJC5ODMdzybvr0@uruC1Ge;QjPB6-3ng? z79Z|FV79_!fgMAdCWG;W*TBO9GP1`M>ha)u;;3*azCaxTmcT#C%$XAIVOaAH_#eO- zG02DY(179?-0pz96A$V|c(w++M(56ze@YC>U%+R8=|JHS%s@?vCcjGN&Xo|viLUG3 z0yhF52absW=5U*Vy#f{pc-vwS1cEo%$-vQ zD19q@i?h#O7H-&pHZ%lKy$r7ZHarcy0}RHuapQ#RLq80leK-6=736J@ciP%ydu$H( z!Z(5A-opfvIR6bf`)mmY29lK@y%4?(ERFq0cPy&(eTAhD>j(hn68KgNe^e9@Rw`*8 zya9H_X|e1lJ=O%S;FF*HDz1z6+;af+FThRr!8%|EFchzRb6+d}VFDn4_ph*H3*1?X z?LzH6HuWy1pa*afXP$Yh6pQfaqX6z#;O2XxeBzz=n*4u-Ljm?@VU7>7St;2LQi%l8 zn_8p>yZ506^%|Tfr=RZof0tjL(B8XgkH}fDKidCSJB*)2!bk>}E|u*dgCIW0I`|l2X^+yN_ylAB}WQ1}1D3Fm*E6p@{@3)vv6Uh`M?9>fw&+)hI@fe z01JUB2RnIVKS_%op9)ZgLP487d-jyp*4F93G+???YMN4NvWPTuxtvq2R;x;>s#0n= z2!f|ye&v;?DQ6bc2E%jL-Ba_G9w+m#Bkd^ytJk5sD&FbrN9%mn>u@aYwE=A2&m z!4JyK6HdSdo`Ro$3jR6v^n;nnhwm$0t;3i89ps{U^W@nL8|3{SU%mQj*)ce{-|vhq zT`Kk4ZWH%Me?O8Tkl%gjOY-9E*)jxD1F1}#Ce7DhmxfX@7*&ye2mCqkv6zjejFUX* z{Cu24a^T_-pzE*ynz>V_?mK{s5Cj39=h197aU6$cvq=!_&AcP0O=EIb*M0|4fAv-L z+#g5tU^zVBlg28BX_X0r*v*w`2%f>L`HDHK6# zZN=NR4gH8C@HcM62S$5)@ihÆ|WenoT69E?T-0bVSXXmgyNnCeZydq2&TaSS*S zOb6OVe@&CtVlkbxQfl1k`#zrM;dvge>r$`RX*3!s3k<`+wrv1B&jX;Pr3GErQvgH+ zrR!*}iw9_>65)$4;sTA%PL8_f8m9g7mpI2A$KdYW=&`c-%+L^RV4VQhr2xzQXL(9^o1mF7}b<3iEe|VVS)1PM3v(GXzZyv8+cO9Y>FJ5yEZv)lX z6uM#7PvDX`0vvKbaU1|PbbG*Cnk^uCNT}mvdHK2_`XlG z*+eOo`Ucy!$>;MF3I$qPTd|&gngB3G*z)w#Os!N1&pC%TAA5|!S+iJw!wulNe^9G2 z?WB|FSiPDJL@ngLDAB+4dN@7K73@QizvFy>0o?-B@_AbFc|?SIy`IuIae{_nq?A`m zrQt7Oi0}L9_mT+Wx^C)AqMI3v-G4u3Z!cT#xrgbycOy%e^5)vL?3_81Eh|=F0}=!r zHFqu@lP1C3xjcWu30TiO!~Dn}f9U7HH`l_(N8qJQGzbsL2dLNtn&mPQ1Zju^#(Dm% zPpDR_sZBQ;4P4hHh<|I_HencI7zVno69hqYoglzhiu!%`5!yCKJo5~katg1nUCYqS znQUFTlF;+0S1R=N_0iwokLS7swHj}pdoESrHJ~l>2OVFBm2vH`aIpShe_YW)i~4bB zU0o2{ZZh~J8YF-uv`@Tz5(zBJBA3gdX&UuT^C)~F-;RIpC{MWM(~^8ptrX( z^N)W-En38u|NKve`}_IhH@}HnuhXp6m^Et_M<0DOp65m2xh_U7hXS@kZFAf}EW@!6 zMwQ=k+*&`RWJoEPq5wKOe?f$1vq`hrOsSg{KM6aMu$R0}LY|1w($bQGRIk@D@_CeH zQNQ(8ocr!$#+EH`+;KG5tz!qU{^pxejsu>@+_`f(=9pu~>4w1b&~mwi--9nfTPt+T zjiliDx50B)!M|ioAvh=iB#JO-t*xmC2hzu6^^?~VeL(iJ#7`)tf3Wj;8bGtrpmy%L zn9U|LHf%u6pARp;%obqe)Kf7H16-HcM<30C1q*N-XB^W!&%?HDoQVFpFT={a;F?8X z&jsbeb)SLPR!5cK@Id^*xF`@nM-3tk0O-1oVHo3_SC;;XZ}5FTjRuJ}Fin%D=i%!* zj;0Yl^boZpk7UwWe`nEm(@m&C0bYKYMl9wlpZp}6?;|42m@$KDwVL{z1b}94%YtyZdnJC2WCUdrEo`AR6uDt5RsJ5YygZ9TE=vpd@hHG;5ZJh>*9G{y0VF# zTb6}snrUdu=kwUMjfl{29BQ72V_8hvvW2k)3#ctyM(+(bf6(^$)J#s9G*ZAN=XqGBNy9MEo6TekP4yDERn=UyRM59?J)LR|a%Lj~|PmoNcGhE}Ot)1yD8v41$1ADMHIatJNrc z;R~3@ACEmWL|11gIp1g7_U&xdb;44K9;FC@Ex?X5f6gH6>%#>4`ugbZ?xxvn?iE%O zjbZ3Iu4&>&rQc$l4US$0S8jxt*2hi%Uij0WM9r0Qra-FRH4K)ZI|Qn>jUCI_M8Sn& zh^A?&eOs2bCp;PkMxlV&-cHMpenk1t{*2O;DU?6@QF1T6#O~o?1}%#hF1w6oxlHHe z$(SN+e+E3I*zvi~A&!IZdCZzMi_y_hT-Qy-mth!~rirfWc%Fx87`T>25S5Et<5hKs zVDN6ZhYmAfy0T(4%4ia+Z~P_r%F1+P_|}r+y&_LqgMpx8J6? zXc28&w^I20=P|$Y9coWK#VGLb?AiQo^=ewzf32hYsH2#?X%jVIH}LuuSKx}^)@n?j zJ{{Y(QA(x0C2_zB1AO04O(2X`xhf(4kSiD{atbWQ+w94D^Q;C) zLXub(YUfV+F25Y>l~?emOu?&Es1%F*fBWD34O<2VFqEQa#}1BpDeDEbvHrf>Zpn=N%c4h5lX=n4RG7r2{Q@IxSn@!sU;tg$ zX*3$CqRfh@Y)b8U9yz6OEDJ5t0<9AO2xAb&Zih8F_*)$3J12K^7>kZNN>`6QdfRf5 zv76!HSbj896EI^L?6tR}XJl>af913E7r|b=8f)1y!rO0$_3PO@b0%xgKOb>jlnApr zI{3uhchk3O720*zu}y?ZYb(#(a09+l_>Bfrr%t7(r-vX2&~=@pT%N3WQd~(Cq33z{ zo`+W|p`zkQYdm>vLf5$ojD7=t@dx<(C)TYCrCet5l~-D48pd}oh7;pDe}buH@_@-Y z;FU_~anh66Wa5R>@|dnu_`@HdTt@xyhbX|aZN#>bT#k>mwzBx)hbgaGg@45ryfZSw zP;W2Ku3U-M*@-DaZ*MOH0|Tk3N}^6;_rC9^&M$F{K@br5KFvb3w<$NC0cu|$Tnj&b z6|Q~qfd_)1rG<~KTv@mPf4*f#*<(KI1Uvkw1%wfY9LI6SmBJFqtHKax(IWW%_mM^e z1!}Y&k}cCTDHIB+NqC-z-)!Qyw4m()K-&iZ2?#Dwxe9*pD170Ge;aSCjJ)syd6;n- zECLD!Q8+OKila(lnOe)Q4US6>bFI)1&*)V@CE&6|hgIOF7X67sT6H*tJH5RlL3qp<9G_{AbxB=+0h zg#i;m7`Y98^$KjdfArpaubv8vpO1v7VF2pu&=r8H#t|S9Ia%j7t|ILFs78a0ciqL* zuYHZy#~+XG{>B^lZ@hsIyt;TX&o5iXFCKf0zic$1*<``|`Skbq69mCtDRu&~>$)im zlE^czFw<<}*><$mY|kD-?LBs)xWLG-VcoCc(&L~z2Ea9ve`>G*qqd!D0LO7s7G!Gx z2{i$vr-v=~-%s_m*QnolCyi2xdb!Nbk9>q`M+XH>gL<8=a+&GVr&B7GQkA!_PE)pV zk}$$F%`_Y))nz}QM~eb_@jVzY5rhzMpN~3901X3Bts8-4K z_M&dQk)4}2fAiLxZz8@=OBgb#TxM!tA19r361#WrP6bW2fRfxN34e(hB#cXnD~Y4@ zT$eCrfVD^7Y6nmTOFBt@+)5+W0XlT+K*h2!G%d~NlU2#C*u;!53<3xOY+Yy0)Tzwx z?@s|V41=|6*HW+7Q{Mx(Kps>~|O1njH|%rYV| z1<&))l){Z?a1@k>_SOOix=AaN!U}q<*av7pE|=S9^(PTTiC>sl98JDTQO2=#2*D zJq%EX%mBd9fkvrBv89DvE;p|AohY`XCzzZQX{+lx?d|P!c6L%Om&xUFSe8YpRHE5z zvUTg$aV53{$U>n&u~?*3Dq))DxN1`ZisyNl@m>X`6gAUK5~9*UM1p2p6$r;^vnBT7Y^AL8!^N+FuIf9Lm^$K<_GDSVOWGr$*NH?UJFl&*7}VGvpt zGseaUBLEKdKSe13;dyZT&tO&uoMu8>5-7t7?Uf+w07b@i9l|U?$=)Ae8w|OyYdZAh zppfjp%NFR84Tmaz&&=%6%brH&H%(w`R9f5qezwRY_q5}};Uu7=6H4W1uo@HKfA!x5 z?uqZKs65>qiZ&}J_!uR~wLz{3b^+{C{MZ6k4s1Jqw7|+okERvBHsa5%=v1Sy`OEM_ zCu%S3h_?^;hq4ni0ih5tP8RI<^Y_(+5Xq@!c8jWgJb$&;BQ5=T&UwG} z`+q;ry081Hz1OCRLPtLgm6t|%W$R>bYWd0C)Y;ujQOOBmEZfnIawvXp{XuJN()k#j zK7InX-h;xme!i}5X*t^1N9c6TND5gID2IrRP|p}}e{^`9BMo7N5`Eha?A_Q{Pu5Al z8!bO1BO&j838(4uYkD}EJy{*iJetVG+eloUy>7@HO`YeF2)IaM{PrJJ^ z!aMJOUH>?FvhfJ;=hsi}nD6IzeK9zH8#|Dinkz|Gme$>t z+0&Wx?BC21M!RxS-QDKnd46x_R@SVWDl}2e)0NHYe|di)qWtaoWdB}|)NA_s(z)hr zqU89od-PIr)ui(;@P>{{XYQJD6N!$tE-{+9hF{uZ^Io|$U#PTQ5#Bc5A1^k@_E*$w z+#H_nb}TaqP2^-t+O&b{4?f{{JfUx%UJo`@bX@8Ln01FWw3wpo)3IpsRBzlLc8xl; zeVS|X+~2*qxXY9&C>K?bu$IU)%vyc=zj(b`Lz8Ag4fcClJ*ikcy;!`Pt*CIW zsXjX!$JjUTk?hR)`saJyZpAd^!ij%3ngD^z-F&Lvy4s;817WLbpHul7sosQ>$?A&# z^Y;A2Ud>LQo={7wUds_vZnt2nQ*mKe=Sv-Fa93?j#pKbmXxH8S>O5(x(0agg2#x9E z@{b=axsv!l@jPpWQgfev-z74t%VLYP3rAa{!^k{m&b14tBdm|yWu|g%>QuRT?juPO zasLpeGUK`%qEA?3rs_?cz4oSAKZjYjyZgA_U2M+g!X*j!4aE2}bt9e6zq5DglRxd; z?>zB`cXf2MKgDWHy?lO3C9?>K9snSTTuNtNn##zxljb^8G~X155qi@j>Y8Rzdw2v~ ze(pT2IbU5gWMqo?^!u|A$+wP*2h~~lrn;D)CCz-n8~!v0Ag9BW7`=wp}V zMRndjX`m(=%MDJcl++YgiDSnu5wev9E-+a-WNK)Dh=x?_nX=gSprgIj4~yAfLHUee zrk$F44=-e$gS*dbeCyBWt+<>sAx80G%aRj6H#QoUREIOtG~Z9$TjJp}xZ_1#5N=6c zUZTibtRL&Z%v8~5-{06Je>Sw2%8KhHoY=`?HSfAIGhTvKxDXQsKaj^GESlen+Fd=i zP9~u}rcsbx4y}IIm-rLI;EzZN{z<#G*&9qG@pGZs{^aNB6Tb28I$FG+h1_$m7sZ`M z%GcW{c1a5#Ump^Db?Em^m9056o@0;Ci$wSQi$u>G4g@)7qSu5)(-Lp9-GdKcYDwdd zzuhkminPwB3$+gVr`cH2RPW>tW^mO?{yzCcSoFrBIRvG2~2eV)^eW}EvD;I$g%oPvdnUyE-QijYKRf4MHcjo z;$t`NeMbmoW?TzZqP^pbnk=27a5GIx$(OIB_x(aeMjN(|w9R|5Vm2Pry(Obxx&?5< zGT(-bRiq9xY9rztsRyLllO%R3S$vNud6!guURm>B{h*}f zG)tU1Y4qZieeK&gg>NAmFp_rUNJo0;xy0Zi%;qGci@HmDJv6=6D%|prE?oGo$oJjY z)lFK9Pb)88v6wRi^qYQYWq=bgW4t^T@;XENF$s9N3|Vv9q@(42*R(o-k(K8DVadFQ zDKc~FbQwW&PmQdhQ+)S?Th$_uyl%$`MGiianHEXe+UM6%gz|~i&Tk~``UL3Qa{ke* z5qcsx{+hn8X(x+;P>D6x{zF#u6Cpgy8MjT4?t_fw*RAG8d|`s~$tSi~n9%L5DbI>c zVVyC~y6kauQKhesfySdnV8i85ie4R~RtG{snT%G^y@2;}&vStvvEtEt`>so!2n#GI zUgv+Im-IIsR5y@+G{Fl9kQg5yt1&TM3GfrveA6{;v_fWmXAgsRRoJ=D-6}iNjwn z+}Z2vCPwQjB}2uD%IhX8>s^n(gph>;#0LvVt%v6Cjc7KVZ-XBH*op24B0V|`+;)V= z`^^Qp>O4BBEJVr1nAC!4#0;Qq+8k}Y0dYSmWbENjK zm#JN;+}^OC)i?&83hLjf)1x&{CU>ZfpGH>_5}yAYg8C{TCV$mR& zj7R&r+TeXPAUaYC-Eq!n*!EP9ILlXGj4{2jhMZQU0^|6&Kux7K;WUv6iRA}+$mp`6 zy2a@mVt%(q?P2hCjA>7UyRN*fo2LDC$;T;VxiJeHBz!)8unT_f17`?rh62q~se3N^ zJ2_dd-+5A$v7MdEb@nic_2C2Oj^w?`$^~8c*4^Y_;KJpWwY}PowOy>g z>xrucH?iff_a|iqJn{77=cKKq4?h7bt5!H7meu&-^~Z04E}vf8V@es=g-FFYG^5FD zW@)1;XL=L4D8{7le=@TN(9e0WnB~tBTNRy@h{kFEaBRw`XI50S4>J<64ePO8n4>c^ z_QD=qXyPnwoie)NRGZJ&n8CWnXR^e-mQ_HgiC&gg2NT+_p8)!Jl3jC=4`^R3Top!? z_{w(k`ULsI$3)n)o<;sw;WpM{_wlLvPP+m~**EoGYa(jqHE7Ud?Srad#D5h_UxPqd!$~Fy3O`nb>a|MkC49 z&k%-rrC_8QZ zpI`l(e{QFe8j7Z+U;i-DE4ip6@15@L_& zEz2J|_8T@K95VOu&~sq9SEbWiZuI)eO*bOKJ6OTW3MD)Pg=@NaI;3S;|)t zqf>bIrSBnb@dMV5I{TB;y){(6Lw~Kq==DQknbj)}{G&G3K)+l^lmlWvQ_F3B+s!y* zIgE&rSq?2l0T8p48)Z4t`};yDlKsU`Y%93%&9FKw9~fs=eTJe%O$t&S&)xWAe|f$atw)oiMmu8m8Esr%Ub5Ffiobxx z%2M5pL|w&E(=z2pI_-kDc}9aB_I_(8N`-}NR^(?ZwIj|^4^kkBt-Tg}cPOy5!H{)@)s_F4MSglVDTaMn1o_Q8F#vc^Hy zJmPym0aDoj1cs=S@BxOZu@mw4z-!QLVvi#A3Y%7gA+Wx~b0k?n7ZwAK=2Z6UWpy;o z1Jw`i(^j7&FbMK8R>Bq4m0lIl780tKlUf|C@b#_|o-a%g_5oNzfztZ>KsW+-`49jr zt4t6OD$VK`RTmg~2!sd23WoqF!HGhE&>o9U(SKm=VwhQ!@}DJXuI6aZ(hOg)t_U;C8(#yw@32Ie z5c~%>yeF|I!g8e{U*By|k!g-?f?ye9(Ex&T&H>VQlQ?967s0?U6td6-DDbay1=w!@ z#$n~yeL7fhr9%lNPQ2Ksw{$Rf@~CpUYljH15%4R>W2FDD;;i_W*bzzK!IPG7Ry?vL zK))V#5P$>DIN3~cZ3yHm#-0siF9jBhdFDnK{X+mANCE>!7B5b*0;OP(4dv>|BD@7G zex3e6G7AXp3*X%+UIS>gwr6|KP(uVMQJ9OwL3@;TNbMuR8vPWG@IbGBwvja56H%Pa z2bmWKSsWzUlbrzx+!)>q+QFckvK+j{4zMESRn*0SFc2 z4Y^cIf#vczK0&206o#creBpAse{VTqB(FGc}E*m zhwlA;3Y>m? zqW|HzU$#d1Iba7mT@N2WGVbK|GDzaet{{`q+yn-3iu~cC;`0NnC(- zu8yplbyW4zpqL*31wyi2YJ0j?*HAnY=*_H!Fabf+hh* zntHG>BgY?QU101BGAE=+D~P**ePhx7zvhGw{1vIv3|qs6AyBi_edGt%4Zxr_-ZEVX z&fl0%tY60ua;tQ*w&?=9f2FiTAe*Iz>;NRu@yJMFM6))84EX=46bXRwE=$bv@Er$e z8>ZTZIS-AeY>E$c6NGO9ZhG@{=K$hy?b*nCP$0msQBI285NNgFz!PV(0{9_IQ58SGJqQq=WBtev#e89IbgqlT~RQ@{}A`hCw3 zIu5w|kZ%6~c>w}=%r2Uih@2A)bubOObR#c(yok`?E5cP`_zzV-9mdpRUUgkytkS@jex0`sECFtvcd{$f~I}sTFrl>wkkOsT2$g|uGTdsC- z|04f3oHej;(oy6+8VH5Jw0h+sZC55vIvfy*7l1jV1#jQXeuybdW?* zUI`HR`GM=Z5m1w)`J0>p1iMilD?#diwPnWHxAR9!bO#CyY0%L~5{DmQYeNQY zY!=w-hoN<2zP6(d(ZFDDktT+}fE!vT=|5Hh#NQg~V0-}DDK-0nG$Gp~1`soHn}1#7 zNdRD=_!1aD2b~1g5gIVf0f^($+p9oVbtC;ZhWwELWcq`DHHH2eV$nl;AjeEn1CVD=X--=LRFHoP)STKKir1m#a~lL? zE%l_y>%qnu9nY#40LIfFD*iXb-zcN<2_rVMtpe!Si1b*{wSybYJ}iMIK(D}s5>2w- z|JJh^^A*At(pNrkEO2JY#5+6Mw$A1kTDstsqJI73pQs z8nx~=Zzo3KX_oIt25}pJTD7wS{SL}Hr&^Mg;uH^lmi8q5`~OtCK1-lR;BaRwJ5y>U z;Qgv0G0YIC+s5e#ECrU^bC!4x7XWpc1PsS(i6KRhie6<7_(gfXXq+2A$g^m!ks0If zDyd+wzsl}+@g51r7X%?nPw0k@k{2MBaN2#ef?SOmyl4Hs^IMYaLjmz|;(kMUYiWK$ zbbOGq^#jtoS-1^BlokI1%|8uwfXvIDS9pES!m>pS2~)4oPv8K}Lv^c=DIm<_TU3E0L(woc=sIYB8kc=TT58W*mI7*&YdH{`|{(8bdMZv&OQ?dg<`Pb^D zEP<1Oir#;{p3DKS*CqV=w*|hoHSS=b~X8cN$`yt`-G&LdO)#q)FU)=5R`v}Eo9!-J6f z3Y+19w~U4>*GoWBsn!9mj&i-tGlJG?q}OTQV9v!%m`dKxI7(yHDqYA|=8v*WR{%SN zGaYI!5&^s_1sRw3Fr}(Co`!5DVeo9{F9Hz$$yjg4gqiw>N&&h_VHS@owxs67Kx`UA z`ab{#&pukg57siR?n#tAWfEmOJ={u(O|s<4%EVBl(zIqR<00k&d_(SuLSifEqG71I z-5#b~XyfxoWbP$z50g}!m4Yx2T68V0bL7O$pEBCEZ4g4tBZltmCL{)Fsy6Jyc|Yq& zn<_rDv?gfz3WG?V{zxHvDF)#wK~MrG3r_gZVEucPi}WHg3#-_qb^<{(!y^V9&7bbx zo5fLs+^^Cs<}ly>V75!&SS=w`te*Rlf%jcqWp>7EQL;SaW`?XVD3E01t<9*9f?Q$|Y+!dkQcQ3|$tz!zilp%X#Y&}q^%MI1G0R3y08CclluXQP;hMLBqclr|g6e`2 zBjL33v9!kL5FpO)y}*&i_~xuH(D%LVRoR0CRqNbmUKfJ;Q!P%mUGhjxTglK@cQ_iJ zSG(#}3La6w6z_?Od}^yS3}i!9yVs^nyq;lFU(Vi=jz%bX9Ueh7u>eS)+}q$?D6Wd%Jrs@rkwP*^ck$XPM?@{>7K)R{oDOi(BjAf0l>5 zNX%&*KNtv+AZm~uNKS|JBBoxOU=e=MrM%bwtt8XLJlQMTXcv(+;D(0OymElE$i!IE z4BpU`1Ag9d0e$`qM?6Rly$q8T@#$F@$F6ry>IT$DfS0D%K#&FZXDBX1JER-^$0wL6( zVd5zs*B*@{5>#k^h((t)&B8-G5IW%bJuZ03a$iRq=xam>&R$SeM8I?%Rk7e^MuWN} zv#DX17emG9gZP*;cK`IiO!y-qFzie@lu9O6FsfFrWv-WQzY>uPPL7-K-(+oVnRcE-->z;yY%-Amf{t zLe8A|7>lG{^4^pg7oO79v%1bCykb$D^anJO(g&{HEV-a0m$4Vq)!8eX_?3-^XKW`8 z)U7kz#zie6wyB&1*>Pla1EvV#G0@$eZED9FerE#%C_@oT2E3bZ)I7?)Y;0^i>o1Vw z7KpkWnL@5SS&OGlMCCH(<60#kTt@C0xctb$y-fX)$L0-}@WYVq0#)hT+Fm4E?6dbs zT5_!_Mj0DjB}2g)AA2#=rj>$`!_Mn#GkADay;Ej4XR6Evm|!RkQQrK+CnApKVXRvT zs6*i-tYUIT{nItCXnr5g=as(uR^*}ADB44vFp%dXK#}}(K@)-}=EyHgvRAN&B&dmP z%gb2)`WB1VD}G$84YK5hwnA88&bLlz-?Tu079HP{mS6}*nKV3Qky4dr&A!8SMW#T@ z^}kC9upP+u_i22U-M%h`Q6NAN65q$=Y!k1)TJt;hw)c&crkF*7bJX)f>1Cd)5XL~y z2h9&GaXx?=3d`1jyw~dQj>DaNBTp#3v=TA&Z#3F8ve4ckDu)TKyNoTmkG=1LGh?1L zG2bdDQ84GRbDu<;0($p_lGLS3R}zE<_Y=i{M)o41JJ$kK3DFYTA0%!ju5OQRxx>iJ zAMy+7KAIXu&{C#lpDR8hI8&-?rQhdsM(O*vL@gMXn;gl^jl6YvksEs=ysds~td}y% zUQx_O`~4*K5WoUGjL@21G{d0g2WaiWRS&&kR5O8c?My+eLb>lY6sanyz5)?Dh?=n9 zmAlm>rwbjvKCVlx(Y#1fV6x7xV^v#230)~AEfg9`3Fp1B*P6CbZr)BA4Ji4nG<-0P zp}aFyGFi-0Vt0z3vL8*R-X2gKix$xalfWeK?@|R%2soh{OwE+#Rbq{DX`qMvR7d;L z!6V@oKN@mWzwyhMUbrBhbr$fYeY$yo;A69Q-f?CzCkeAU<(j?>AP3;|UJ+?=vue%e z=m%2hgN^k3@MT!t;tl8PRtUv;7b!HeV0$2tKA|^Fp8PU7{g#wDA+sg@=*qV3YBG>^ zCtkreMy*kN_h~wYealgFj!S@ohJbRJFG(9BE%vqT%P#e0NL(!$PDsZxjFxZ*?#`5S zj$b}GiSZ#{hoJbp)NzH zCI$64(wYdID&Qt4U>?(nw6Qac`EE+0F*>3|5VKTpA6(vA0yTup7I{ zF(?wJF83;6L#4w?M#{HTN|zr`FESZjPxBI>b0_WooF##DWEIyVMapcvn;(C z(I4XP-_mHtPVORBoUlWD;Wz`L4e3FcL)#%eh2O2TKU1S>3*4FHM>tyLvJZ`0Stuv| zI1UV78a;$nE{>R9uHAU=dra%Cqv+`08a>=l@Utk~f4QktSV$ydOxSx+hL>ksS9LPK z`8CD>`q}7aLP*D;3es`lMC7musC8CeW9<)G+`g14H~{J+ooCz+k zXp`J}m&RWGGcp?5gYGdK?s8)HT8`G$am_saNuy$r{2=nVVl>;a^3!9_JEArq+B*Zl z7sFp&LL}!G-*AdlEa;UCi@B>ONI*s81Rd;?iT{sm`>aD;6bms4=3yxiYcEbF&cRMJp_S zWsmE@C9y)#TNmL}8b}aXTBg)1yuDGV?gVx0L)rm{_?K=)8(0r1gJ&CyK3?>Ip zGZ?_G=n%!?Yxmv)>@jYy`*WkLNgJql0U{mOu^m~v;l0T-2TG-pKIchTM$d@jy7?~O zSs)h&1tD$Aw+GvcEa8ZJB)@l}3g^R=21p35G?XTQ^!BE0PuqFrrZpi0|q~-nTk97ENV=pU)l+~Y)zh?`gvLcKHUsb3_B_O{k<~dY|`x@ zZo2AZ(?XS`pY!y4`a$n(t?SQKu2=WV*+W3U%cjhQw~%;(spr(f9t~pjCz^Ht``@EO z^Wlpx-aZePqoh3k5}dd+5?x}VlFwZ)Wf-Q9*EhANxtVv?4-IOew|P0T{IVV4zr)YE TB#|Xh?*l|tEIe9U5D@+!Az$41 literal 11018 zcmXwfWmFu%(kyPlbz$)(xGnA^!3it`cXxLQ?(P=c-5r9vySoL~;Lgjv-+lk*)ak0O zu9KL-FX7)r125h9jFHmWsH4Y<4sn>OR%ZVD{l}oxrC^Tyt8|u+9*kaMJ*$|Gn|1FNW zv?(=?tE2BvOu8*#GI>@%uO6?fS+CGF!5GVN(8dX40Xd6{&JMll}gdPVjNx zr>pz^D(v%8yZZi9`RzRA!|m=cWx8MTDvom=x~XUZCtO|Quax;)~QxqjVdQ3!v7@i z(W+@%_GEJJ7d&ZWduqW(7xC(@s-Lt*NUhFN-h8@${put zSmO5_Nc4Hy89Hf0Pc`P5d#+%Fsp~8)JL$Xgd_X|u?wowT-wR#cWUQ**JVPg{J|qAc zz<(Hj(zE&7b;x8;)+GL1xoN{<+8nW2yiUfct6ODq>ASnO_Ea}m(M9IvBe=Hva=T%{ z4e$DHEA(d0-sa`#)tcFv$wIx9a*FpJI3s{rSHG&00fqmC9>#9#^l5*;b8pwVL)~iW zk~@eyC1nmW6&%0WFAI90p=@fd9~*F4ZEzjr{?o9R9;}fJr=S|~vvE1>S5gd4T;m%@ z`qMS8Ip3jxvWdkwoFMhumP*^o(1^v0wds+k-0Att1X@hGE`)$P!Zl*ShJT^)0{itZ zg3@{`zRv(*Nf`l?e82Bg^-=@|N7yhDG%kua17U*ks3=S|K}N(;)zw__(iL)dS<+m>GgM4zk6bv4M#!vV0X z&a5U|gRfI6hsn!j8d*mz0t;Bfme!Vg-&QzA7HquMJVW@px2U6HjUw{fx17bKZQGX5 z)fb|d#~_EFELl9AgWR(o?Kc9=7gvZVG6sTXbDboWRIZn>=hbL_nekv z?81NF>%1__tSo`~-V#{{ii7C9P^e2f2do@1WDaD0O;VH=! zAsd$#R#G`AHZJ^;ZLm)hrNNVsq@AB^k#xUCksy8{GNiy1!^afEZ#|4Hm`f2ra9fZ( zzKrNW{P$D$3<7E6MO$!a&gnc@Z4BovndUhYZAL&4UGzPS0tMrqYc`=IZz`W&a9&_@ zLQEli#f(g@GM%hq`R1y{{BCKdh!f+WNQk?^Q`#kq>|T(W|E+Ju-3ID0@k~Hiz(dQW zD5U-d4BIGSQ0!rscyD~>gn_YeYdB~TGcbvWXrVhi86si%Y~I^AWq8;cw`y2_^BvU0 zrQO!qs;*`5wlWd2V!P&oJZUKGQ?JfA5+Z<_VE**p&)4Ghdi6s$5|uKX_}lX3Gk3$F zJOkd0`__`(7G@)RX6JmGg=IqR;ow&$5NVu|kMKyYgoC8>>_`c0ytQ@wl+K+bdf6g4 z9rB(cxrh=eKavd;`@o`Fdy$IviWebqK&QWxY-*g4e$jiO8sg&tTA##a$dCkpkF`ji zBx0>DXn617*XA`OfKD-go6Izmq9On;#zQX5hl z1%=e)9@u${naMn>yiiK>KP9vI#ei3Z$gH~E!yrBrid)E%kWA?6m!Zw29@?$1(UVa7 zw2{rN)$6&G?W)ven}pNSOLXuzoaU1caT)v}$uS*e6kWeT%c6DcjbK*oovUS!1lf}{ z_U?>~30>tmXPCkSjtA?OpfW`|xVd6Nar)D$Nt!h43X&_Qi&zsikDI5m3$S^oYKQB> zlmvK*ORd;3=Ah&lyT*f4l0zcn)hgj6f~yT0Gt4odL^$xkqtZ>qi=nEqIy0g+#&MF> zNq)abqJ9xtbZF8UE1hHc9*N)8Ciw^>_etl2qr8)Fid^K0_{C)X3!bJWx{?|tgsSo^ z*GiL?^@j6p&PjNrRiaML86p+bi4sw;tiWwLrm;qTB7fhl9$YG*O*B48jh&_g%lNf8Rms*iOx|2( z5?^UsMz)Qgf@ePPXay9C*yO+V1ga){=`?^OP4eiBwx@~0ZloK)Cxu6~sctTDnQNM3 zxH1N*BC@~Qrg}D~RyK{@9c&C7ZCEw8zCUJG;eD{HNcj9B_DT3HRG8Hm`07&M0>JW{ z3hTUVOB5vNm6`ne60EQ4L8{#Y(_}26s@+h{m$mRW+I*2X2`Gp9XZaX_kK=fi(u6@= zhU8dKdjr=-a$WC*P@r9}zRBpPvirC>CfSYIY_R}MiA&hMpo{aUIAQJFq)OA)#H)7)3`@q%B8SPag9V9{-_nGSES9$E{14JiWEf*!{ES&ps+<_M zq8%m0v`p0zshX$xr?Z%8dNux0GYoCUXOh#JIZ00uN%co@0=QY1{xR6pmxB3BdAA|+ z6H`-^-8igH)oFwGf}9l=f(Fr*uPSzN{UAIVF9}~IEOIMNa4r?^JtWT=nwa%gPwK|oDPDd z6!p>>K0AQ>Ei(NF5>_Y%mS4HyYqkH$aejh-9YGSYcu011&;SX_Sn6(FbHZk=EXY>8 zy)eaTF!6CkXo*$!$1DAm&g(C>YD&?tg0MGl*=ONTkq9pH?2&1&>!QW@y+*`zO&jy(XAhR!;e@38P+!y3+A{QH22NA?sqFW_AsjKkY1gt1& zHIohZ+6i$6o_O;PBlJ*X;6X6EPKeQ4&tE>WURNvSpa^G(KlOnp)erY<{MjE5m(3E8 zWqoZ(1EJZ zqEw?b9j)sr3XVB3`E59gskhWJ*AHo~7_?qH#~KfV%;`f60qn*$H>SO2nO&zm-Xwrr z$Cb@{{Xk2z3ckQNw8E1fvzk~#!A(D~0%IwT$$vDy=%Ko{HpqR-N1s6&%Xnz@!$Rys9?PV=pwd=ifV4x`9q~ea22?~! zobB>9&ichwfxq{v>M6nevgkE>luyNBGjx&R4a0GmXtlVNNhFqq*_#mxfiWb;jVx^% zJP`q4eZzJ~WTi~xT>l+1L&TF_dbyiJRx}>M3R9%!5cW^0#C=jDjQk+x8pz%Mi4d|~ zI(tV~?A6W2q!O#Ilo4Ib?$0X1%}Plf3X}SMU7FQGbr+Rs^ORKl7S`~VR9sPfh+12Y z^{2`flBL(dcf#&r)yE82`*20e;`@J^Vkk=Mo^u4pb6tOyXcdl1W<$w!w)a<6C$G=a zga+lY3PmNtnpWfb!kDwlTmO=Q0WE6B_E#{BItq?{eA+^cH#?;Sq?$i4F%fSyqPI6*>98 zbrT{K1lJGc^@zW%n{C_J(c>0VJTihw!A#FEYOJMbAA*M?p&ctjySr+wlzF<^SpP8V zGwKQ%{@z=#E1+lh*gLfrYXaQ;Y6BF|i5GDqAqRoX+Y$E(|Esfybb#0Vx9;9p5==gu zirR%*DjtBda15!=$kX0Fqi*~<^6&2!o|V5HmHC?5TfcdD9g|?+3*v41e3;ec4X3(7 z{{R6%v;3qJKb-#{hAh?VA`W&-C#ab?(&6T5H5`^B(;J`+HfC9ni{ltkr0?#!O{lhI zu^fIE*D3@QW*gg+191GkRU)Fbe@%BEJ!-`WCf2QwV?~ZS0)u!Q=o}5QMf_$kV8pX& zgF(qXax!R<6!r@k3(r>@s(v$efN$F~h?Yi|!@CB@2paGxeKa(=VaB0d4lXh%cL?Q&fU zkHmik9p3$dH+aDD=gb;5|5Im1EwR?=uG)mMl<&A*R*)W2_$ddh@wU+5ftr;2|VvpALw z)4b0AkG2x*a1yp3)JUygtfxx3|OoF0-w z{ut}eXlQc|gl1;+4wGUPdc5tLEJ!|%y&tokmXC`?Hmn~QjUqzCdBzI9hiwX9Rs=p3<9>M~QA|I3{Jw1{YiXp6$%n3-pzJ9G{|Xg^xS-S5ZP24$%r`YLj;70=(n zLV>dmY&`{%7;mn$#ep!b72bnvs|o8zxh}qnM>Nr0M_JbA?xeHC_Xw?RSBrmkvPV)U zuAv!)1=e}~cD7g2bA@AUmTu%GzEzxpQLiZr{7Ak0JUFwo7`VGDO4lwT+*fPh2d>}4 zDXnQLSTk?m!_`Jry1iJP8@7%vbCL1;Yxh4)6FL0k9}^nk?A+V|H9RAsAS3N>G2 z1W`@(OF{(;-uf`nA4@nT>E6e};}7>+C9CkV$3}VTn$=gWBCoYh+_GcP_6YEJUO*2r>HF8@}zN5hHyu4?v3lL4R z|MBk%cdIKrLA;M21Y)=b=N4M<4psL<&K+rs?V;>J3&8KlJW0a5hbWQTc`WcUt#o!A zf0S2?s`b<10riIIV#3%4pE);sk&;b~d!ZwPD>ONnBI7Jm&;*+ z;|7;Fpoz2g3OmmxtF>nTH>AI;m*9Q;42r*|QPtVRnTu@qDlXrRw+G)&=au>^qO$jx zF|C11RGHv`PGi3cD3h|pQly0$nR>_yhfa-UW8SnG9>x(-sm~?v`fF)uyPx;`HmVuj( zR;7pAT@=(=DgNNIyV?zw?)P8$PugBXAC?D@<#cIGK0}6gQKk4p_P~!sh%iqa-6kcSw0?T{quoCByo{UMkcQ$uM9Ym73TfB7p!wh6~0@s~>6FaO$sgBy&xk*3a-b8m~=Z z6vY(%2$ex{zhuy5uZ?gF?+Zy1#{Yw$% z^5HYOu$>zp+t(OFemkchHc*5q*Dl*;QnoO}>P8&Yb_ULqf%-ohJl+Jt0T|l@&=1m* z=uRk(mExEVVu-8@7b4NH-g4-rDB9&%$5xRhIj>u4<@RA%9MCBX%X4;L$L-alDnE?{ zh)ilk1*mJ8ouXh}-rdj|2>25q{{04x%54f5SRQnOQY8I%KIn6GPQ`*nMH6!|Y+(a4 zMGd$d!`&ujfhYKC=S!!y${uZl5<@t@1!tAx=T!^c^1o95AqjG`@2>b(56?kre(-sa zF1xJpKnw?l{z7W7NjeJfc`&aJTAu%hAAOE-FlcYqj+CmZ=RkfKLc#!^6z8f!p(d=d zGqUHTIQ=3xn~8TIC5%Bi=mf`tPCtQ?x_BApmIpWw9EOFjH8=kq77+PyRtd6C+PV62 zjyOMwtCvsyJDWH*sc*e5Du3N(aaHO83QXOWypHC)S|me|8CDxU4{O%SlQDew|4T(F zVM6LfdSF^?=;txh&*PLKbHFiV=96=W|_st8@rT2SkMasI(pxUH$KPz_CE! z)64q`cJsJl&O2u}d}S>mpMwlr9q-wO+$1A;Ke-wrB4j~Tb1PFq=8P5b_NbQ;4o!A{ zaqc~=C5aiF#ZjYAJ0wLncX*SEMM_-l>gE5L$x~e;6)eFuZ{hJRH5r=t1u(?{V6_qo zu(2BI_N~>dW^9IDZ^thEYO>nnA<&6#ZUK}>VEvHhgO4Yr_B7ttezhf9n zeHYbTq1=e`%41Ity0f4TpXOj_*X%J)*UK%z_P57F*ZZNd>!bHfL|YNj<5Xj|)*w1> z4lDcR`Q}BfdRbdO*6)_!OuffcK``6YCG{^ph>0Hl1{&})Y^ZH~{URV11_Cs;l=X&} zo$!s+Ye&9EnM{z6aZ{de zGpep)I#I;-+X%E2V6vW5`0Vt|&kcu=JDpIF9KX46f=eZ(oVpP_JSpt%GH$qmR=N*h z*RZUumjng5a|4@t;bTqf4H;KWzEN;DC~w>6sfEOCrco!%oI9E>uv-f_u-Nq@`h7>3 zZX|aUTQ8dD8ig9V4CU#kyqGX%Uld@%1y74Yi3V1q+;5EX$pBn?Er8y^~Z@;^#>& zpAxiO`2Fp)sW6ZYw&IJ^qMfBi9q$dZaw9N*6{T{f=8f1>5hlbFUk)NFICtyyb zE-{voMChsttiMEgOrHhED;j%IJY#w8^_ZICN00Q3>CJ0|n@&uCrTK@-<-t&HDMOp8 zI_BB3nfD9<4|5^hm);E@)^pxB_d7n`o-fBSUG8sBKFmqsHm4I%VCT|Lj^*RoHIqV> zA&+ZA$zs(Xtc`WJpO#_#*m$<|Q&gle9z56!^b&Jd@ZlV{;*yrWr!IzGxiCBCfzfV9 zh|W107zJq&OMbNBlkQuM=I)h_+`nQ@x!!)JWJpJ$ae!Gb+|INYye)X*=YaLG1x}Mp zUn74;gV_B@+W~}dqLcFRB?~ z2Y%~Ejk%W;tkR^m-wT+U@Mx)fd%9`u1Gnh`@n-sk22+X8)aok446^4=R#eEf5DWE? zjd}Z^uXY2@F2+%rtFioLVn+E;A)_!Jiz zq!p6oGDRJj@f8Ww%gH}GWt0MA2IY+8&UJ=tn>YyQljGQPuVJc}O=ttjKY^KluA4|E zBf&NlNg98nIF}P^?5ol3zrv@~MqA2TZJbteOt>&PryRBr>9>3_mA)?;MGB#d!fCh1 zF}En$<>1#VR$3Lx%2HR&x!XokxgbPhiKO{f0!wQZLN5Fl5Mv zHZ^PE{U6&`VBl%-$TJlh_9NM_n&{F=@ZxCvu<8eQ{b7m)h9#{Zr`Jo=!6ZM*S1af( z1HakQDGPKT`g8ifO?7?WUy_+vg|%B^1l3b2a&sClQOj55#mpBIqn%o+v8P!qE-|Gw z|1}_7mH#bB0J+kq>63ZFkk56zWM!vvUG-WBp{_(zRy;CiFO~;0bD2-dEg zNtSE^1AnQe@h+-evLqmtM)eIt}HqTF&TK8k-{~)FSoT1HgT`)Y8jmJY4sj5)_S{ zooKD)c%`CNTX#OC{j?N7VKj#QB6&XTnCL}XIwrZ)!!wtkLUTgrixc8N~+ha zh;zbOsX|pReF%kHt-HE)+UF5;epv;tChQpdMh#EitsgcVn{KTT`HBM&x8^R=PBEGl z^5wctEWPepB#^_-AXtKfMA;eMk_?e9UxN=4Tn1DMkuQEa9B&^p*21sg&SSL4c; zhU03$WW2du9WracgLg!quB}MuQAg|4TBb1X7!@!2a+gXmsD+p;6}DLJ0-XFjnO=-I zr8c`L)0PKMTe-J74jc?+2<$2ilt6_E9`tV`^pKY0SfT<7NlSvo+FEFy__*tU`h;WP zndES<#qa?PSX=6-HHKk%EX82?Wfa&vs8R&d6|wX7vu-uC*2!wtbe$R3vtnrS%%#Rg zA=v$ea&<{Kx(b;aiNsmE`X0`cm};JQZCkBP*<5sDLcNq86E}DK`(3oFO8D>aO@pEO zH~I#1YB_!(mWaB)(?m#I#j>gk!EkpaO}GP!Fmm12EWR~Ok02O7i=zHet3qwj^@_3PolJcuX+~!G6%YvQ z1pw*z)cr$57k}{AKa_yHIDaOyonCPUb-?7lFHf7Cn~QOTQFXr}%Ru!$HsW(j!Rfon zv?w7k;wptj|J&e>CH)H6DGy1M`Ht=GHjB9dmC2~)D;pxlWTw(14<|;82$0o3x31w3 zdw>x-9Chuxj+$XtiqBaND`Zf086&zuea~*9^%?1wb@>jz?wc2rC#Q9fLBeFII%CBU ze?i5L+$>$%hrs6LZ~5%<>?>kZ0j62gSumq24)wR5g8LA_Uz=eB;&4KjowSlvTVKmH zrlt0xDi)Ztb_R7+&Pe{!&lI}~vYg-M!G>m=jx`!9+!LWwE%} zA;vzH2?-z-jdN+jgOW6wK05&GJ+8s)&3#{9+hEsA=lX0jwCdwP#>RyOYoTq^PV{pu zcF_UW#zAQC$Pjn_bHeG9p{QoxDW4ycLHVl`a5?|VTLi3=xo86gN9%I-<>RGELy|MbGyn6t0JXJ8lNPfYj{?))~5KD!l_ z+w=luPX(uYSK-g2-h3MEB>9qIa@;UA>gXLLV1NDD2vsNt_dx5XN`s7y{4AeziGzlh zcKYTHy}!6ICRSk4u7^o)XIR2BaaH?vcQPR$03Oj@-kv|&dny8v%T>ke)n@cm84j&pXTbWqFpjVpz6KTVaz@@_)k4Ai|; z^K1XYRd~zDg7ck^dak|4>1@345zmp%54*Y5KWhLDdOB0|TO9lBX3^dr(oaP~1m!4G z`7dGo|9-lS@_-yVnv!KuV;w*v{y2Zm?h*lP=ZE?TzG)bKozq-Z7gzfk|^cJ@Wl~YNeF8wodOHbhpdI zmdM4vsFK9_+REe(-7Bo>c1q@P^So>c*52;wmq%iHfE|Jn2tzrP3oK1X%c=UzEY@sk zg*F=R?@@yqG#L+Vbt**F{wY9t0W6D*LbaPFAc}b#XLpo69QIv>}YF#@UiGJoOO<*WGHXy1w9=D zUz|faqaTsQ7@?@BWD*4xT#&DH76^>#7r)HO;YK81$ES=y1CuosZp{N-phzV*5{cEI z;{vH4=@~)cww=NO3!Y+-6C$Om`Iw3~FeM5srGgWoK9XeZW>< zM)Ss{_hi(c@8LRRdN(yA9ND%vzgX#-)4WGMnabo8m(}CmjrSc=6{M>+?Z2m2BxX60 zOm(&M?_MbdEV1S%m|;fpIn9SvGT$cL66+mDcm@3`+chGM!<#-{1f^01JT!!d4xuop ztS76aImPgh$)tQTG{Nn6Oio!o4qtt_ILwgQTLP!b;3Q4S6;<>7lufF*mvjv;HK9NT zDwve_widlwU}G^n{+V>uyZO?w3a4sdNm2qC44At@qB1bgCtpVTJojZk97pLBEwW`) zz{pgppHe|g)TB6jvjT+AuMm#f*>bQ64#oNwN|lW#oHez>>cXd&-6DH4i#%HfC&p;* zLlITr4ru=;f0B8>-BiQ>upY0w{Q5YdYE^^a?(~#7cqs^h_Y@yfvJxiPyA3=fF$LoOzGTG|~GNE@p zjOLHcuD&Ri_qU#c7Z$fCG@&(NH?%U0xL_Bwo#w4qXp;B)^bc4*StI9`W+ A>i_@% From a59ae53b590de2589fa1db2605acf821b2295280 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Sun, 12 Mar 2006 10:30:53 +0000 Subject: [PATCH 222/245] Add cmake support (not tested) svn path=/trunk/KDE/kdegraphics/doc/kpdf/; revision=517816 --- CMakeLists.txt | 70 ++++++++++++++++++++++++++++ conf/CMakeLists.txt | 31 ++++++++++++ core/CMakeLists.txt | 33 +++++++++++++ core/generator_kimgio/CMakeLists.txt | 23 +++++++++ core/generator_pdf/CMakeLists.txt | 27 +++++++++++ doc/CMakeLists.txt | 18 +++++++ shell/CMakeLists.txt | 44 +++++++++++++++++ ui/CMakeLists.txt | 33 +++++++++++++ 8 files changed, 279 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 conf/CMakeLists.txt create mode 100644 core/CMakeLists.txt create mode 100644 core/generator_kimgio/CMakeLists.txt create mode 100644 core/generator_pdf/CMakeLists.txt create mode 100644 doc/CMakeLists.txt create mode 100644 shell/CMakeLists.txt create mode 100644 ui/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..7214840fc --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,70 @@ +kde4_header() + +add_subdirectory( conf ) +add_subdirectory( core ) +add_subdirectory( ui ) +add_subdirectory( shell ) + +include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + + +########### next target ############### + +set(kpdfpart_PART_SRCS error.cpp part.cpp ) + +kde4_automoc(${kpdfpart_PART_SRCS}) + +kde4_add_dcop_skels(kpdfpart_PART_SRCS dcop.h ) + +kde4_add_plugin(kpdfpart WITH_PREFIX ${kpdfpart_PART_SRCS}) + +kde4_install_libtool_file( ${PLUGIN_INSTALL_DIR} kpdfpart ) + +target_link_libraries(kpdfpart ${QT_AND_KDECORE_LIBS} kpdfconf kpdfcore kpdfui kparts kdeprint kutils m ) + +install_targets(${LIB_INSTALL_DIR}/kde4 kpdfpart ) + + +########### install files ############### + +install_files( ${SERVICES_INSTALL_DIR} FILES kpdf_part.desktop ) +install_files( ${DATA_INSTALL_DIR}/kpdfpart FILES part.rc ) + +kde4_install_icons( ${ICON_INSTALL_DIR} hicolor ) + +kde4_footer() + + + +#original Makefile.am contents follow: + +#SUBDIRS = conf core ui shell +# +#INCLUDES = -I$(top_builddir)/kpdf $(all_includes) $(POPPLER_CFLAGS) +# +#METASOURCES = AUTO +# +#messages: rc.cpp +# $(EXTRACTRC) `find . -name "*.rc" -o -name "*.ui"` >> rc.cpp +# $(XGETTEXT) `find . -name "*.cpp" -o -name "*.cc" -o -name "*.h"` -o $(podir)/kpdf.pot +# +#KDE_ICON = kpdf +# +########################################################################## +## KPART SECTION +########################################################################## +#kde_module_LTLIBRARIES = libkpdfpart.la +# +#libkpdfpart_la_SOURCES = dcop.skel error.cpp part.cpp +#libkpdfpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +#libkpdfpart_la_LIBADD = $(POPPLER_LIBS) conf/libkpdfconf.la \ +# core/libkpdfcore.la ui/libkpdfui.la $(LIB_KPARTS) \ +# $(LIB_KFILE) $(LIB_KDEPRINT) $(LIB_KUTILS) -lm +# +#partdesktopdir = $(kde_servicesdir) +#partdesktop_DATA = kpdf_part.desktop +# +#partrcdir = $(kde_datadir)/kpdfpart +#partrc_DATA = part.rc +# +#part.lo: conf/settings.h diff --git a/conf/CMakeLists.txt b/conf/CMakeLists.txt new file mode 100644 index 000000000..ee1699d16 --- /dev/null +++ b/conf/CMakeLists.txt @@ -0,0 +1,31 @@ +kde4_header() + +include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + + +########### next target ############### + + +########### install files ############### + +install_files( ${KCFG_INSTALL_DIR} FILES kpdf.kcfg ) + +kde4_footer() + + + +#original Makefile.am contents follow: + +#INCLUDES = -I$(srcdir)/.. -I$(top_builddir)/kpdf $(all_includes) +# +#METASOURCES = AUTO +# +#libkpdfconf_la_SOURCES = dlggeneral.ui dlgperformance.ui dlgaccessibility.ui \ +# dlgpresentation.ui \ +# preferencesdialog.cpp settings.kcfgc +# +#noinst_LTLIBRARIES = libkpdfconf.la +# +#kde_kcfg_DATA = kpdf.kcfg +# +#preferencesdialog.lo: settings.h diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt new file mode 100644 index 000000000..dfe5bcece --- /dev/null +++ b/core/CMakeLists.txt @@ -0,0 +1,33 @@ +kde4_header() + +add_subdirectory( generator_pdf ) +add_subdirectory( generator_kimgio ) + +include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + + +########### next target ############### + + +########### install files ############### + + +kde4_footer() + + + +#original Makefile.am contents follow: + +#SUBDIRS = generator_pdf generator_kimgio +# +#INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(top_builddir)/kpdf $(POPPLER_CFLAGS) $(all_includes) +# +#METASOURCES = AUTO +# +#libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la ./generator_kimgio/libgeneratorkimgio.la +#libkpdfcore_la_SOURCES = document.cpp link.cpp page.cpp pagetransition.cpp +# +#noinst_LTLIBRARIES = libkpdfcore.la +# +#document.lo: ../conf/settings.h +#page.lo: ../conf/settings.h diff --git a/core/generator_kimgio/CMakeLists.txt b/core/generator_kimgio/CMakeLists.txt new file mode 100644 index 000000000..bd6d0c428 --- /dev/null +++ b/core/generator_kimgio/CMakeLists.txt @@ -0,0 +1,23 @@ +kde4_header() + +include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + + +########### next target ############### + + +########### install files ############### + + +kde4_footer() + + + +#original Makefile.am contents follow: + +#INCLUDES = -I$(srcdir)/../../ $(all_includes) +# +#libgeneratorkimgio_la_LDFLAGS = $(all_libraries) +#libgeneratorkimgio_la_SOURCES = generator_kimgio.cpp +# +#noinst_LTLIBRARIES = libgeneratorkimgio.la diff --git a/core/generator_pdf/CMakeLists.txt b/core/generator_pdf/CMakeLists.txt new file mode 100644 index 000000000..e2e61866a --- /dev/null +++ b/core/generator_pdf/CMakeLists.txt @@ -0,0 +1,27 @@ +kde4_header() + +include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + + +########### next target ############### + + +########### install files ############### + + +kde4_footer() + + + +#original Makefile.am contents follow: + +#INCLUDES = -I$(srcdir)/../.. -I$(top_builddir)/kpdf $(POPPLER_CFLAGS) $(all_includes) +# +#libgeneratorpdf_la_LDFLAGS = $(all_libraries) +#libgeneratorpdf_la_SOURCES = generator_pdf.cpp gp_outputdev.cpp pagetransition.cpp +# +#noinst_LTLIBRARIES = libgeneratorpdf.la +# +#KDE_OPTIONS = nofinal +# +#generator_pdf.lo: ../../conf/settings.h diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 000000000..140df82be --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,18 @@ +kde4_header() + +include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + + +########### install files ############### + + +kde4_footer() + + + +#original Makefile.am contents follow: + +# +#KDE_LANG = en +#KDE_DOCS = AUTO +# diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt new file mode 100644 index 000000000..79b553d0d --- /dev/null +++ b/shell/CMakeLists.txt @@ -0,0 +1,44 @@ +kde4_header() + +include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + + +########### next target ############### + +set(kpdf_SRCS main.cpp shell.cpp ) + +kde4_automoc(${kpdf_SRCS}) + +kde4_add_executable(kpdf ${kpdf_SRCS}) + +target_link_libraries(kpdf ${QT_AND_KDECORE_LIBS} kparts ) + +install_targets(/bin kpdf ) + + +########### install files ############### + +install_files( ${XDG_APPS_DIR} FILES kpdf.desktop ) +install_files( ${DATA_INSTALL_DIR}/kpdf FILES shell.rc ) + +kde4_footer() + + + +#original Makefile.am contents follow: + +#INCLUDES = -I$(top_builddir)/kpdf $(all_includes) +# +#METASOURCES = AUTO +# +#bin_PROGRAMS = kpdf +# +#kpdf_SOURCES = main.cpp shell.cpp +#kpdf_LDFLAGS = $(KDE_RPATH) $(all_libraries) +#kpdf_LDADD = $(LIB_KPARTS) +# +#EXTRA_DIST = kpdf.desktop +#xdg_apps_DATA = kpdf.desktop +# +#shellrcdir = $(kde_datadir)/kpdf +#shellrc_DATA = shell.rc diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt new file mode 100644 index 000000000..0da7f8e73 --- /dev/null +++ b/ui/CMakeLists.txt @@ -0,0 +1,33 @@ +kde4_header() + +include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + + +########### next target ############### + + +########### install files ############### + + +kde4_footer() + + + +#original Makefile.am contents follow: + +#INCLUDES = -I$(srcdir)/.. -I$(top_builddir)/kpdf $(all_includes) +# +#METASOURCES = AUTO +# +#libkpdfui_la_SOURCES = pagepainter.cpp pageview.cpp pageviewutils.cpp \ +# minibar.cpp thumbnaillist.cpp searchwidget.cpp \ +# toc.cpp propertiesdialog.cpp presentationwidget.cpp +# +#noinst_LTLIBRARIES = libkpdfui.la +# +#pageview.lo: ../conf/settings.h +#pageviewutils.lo: ../conf/settings.h +#presentationwidget.lo: ../conf/settings.h +#searchwidget.lo: ../conf/settings.h +#thumbnaillist.lo: ../conf/settings.h +# From ce8715fb8c5a0722a4325d2c0b6999286b4f7432 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Mon, 13 Mar 2006 13:24:31 +0000 Subject: [PATCH 223/245] adapt to new kdelibs api svn path=/trunk/KDE/kdegraphics/kpdf/; revision=518219 --- core/document.cpp | 2 +- core/document.h | 4 ++-- core/generator.h | 4 ++-- core/generator_kimgio/generator_kimgio.cpp | 2 +- core/generator_kimgio/generator_kimgio.h | 2 +- core/generator_pdf/generator_pdf.cpp | 10 +++++----- core/generator_pdf/generator_pdf.h | 6 +++--- ui/propertiesdialog.cpp | 4 ++-- ui/toc.cpp | 14 +++++++------- ui/toc.h | 6 +++--- 10 files changed, 27 insertions(+), 27 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 68d2609fa..212f6c078 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -426,7 +426,7 @@ bool KPDFDocument::hasFonts() const return generator ? generator->hasFonts() : false; } -void KPDFDocument::putFontInfo(KListView *list) +void KPDFDocument::putFontInfo(K3ListView *list) { if (generator) generator->putFontInfo(list); } diff --git a/core/document.h b/core/document.h index d190c016f..ce6a26318 100644 --- a/core/document.h +++ b/core/document.h @@ -28,7 +28,7 @@ class DocumentInfo; class DocumentSynopsis; class Generator; class PixmapRequest; -class KListView; +class K3ListView; class KPrinter; class KUrl; @@ -83,7 +83,7 @@ class KPDFDocument : public QObject QString getMetaData( const QString & key, const QString & option = QString() ) const; bool supportsSearching() const; bool hasFonts() const; - void putFontInfo(KListView *list); + void putFontInfo(K3ListView *list); // perform actions on document / pages void setViewportPage( int page, int excludeId = -1, bool smoothMove = false ); diff --git a/core/generator.h b/core/generator.h index d0a5af779..030514601 100644 --- a/core/generator.h +++ b/core/generator.h @@ -14,7 +14,7 @@ #include #include #include "core/document.h" -class KListView; +class K3ListView; class KPrinter; class KPDFPage; class KPDFLink; @@ -64,7 +64,7 @@ class Generator : public QObject virtual bool hasFonts() const = 0; // font related - virtual void putFontInfo(KListView *list) = 0; + virtual void putFontInfo(K3ListView *list) = 0; // print document using already configured kprinter virtual bool print( KPrinter& /*printer*/ ) { return false; } diff --git a/core/generator_kimgio/generator_kimgio.cpp b/core/generator_kimgio/generator_kimgio.cpp index 46bcc7f3d..1adae27b2 100644 --- a/core/generator_kimgio/generator_kimgio.cpp +++ b/core/generator_kimgio/generator_kimgio.cpp @@ -60,7 +60,7 @@ bool KIMGIOGenerator::hasFonts() const return false; } -void KIMGIOGenerator::putFontInfo( KListView * ) +void KIMGIOGenerator::putFontInfo( K3ListView * ) { } diff --git a/core/generator_kimgio/generator_kimgio.h b/core/generator_kimgio/generator_kimgio.h index 46041f0ec..05847441b 100644 --- a/core/generator_kimgio/generator_kimgio.h +++ b/core/generator_kimgio/generator_kimgio.h @@ -31,7 +31,7 @@ class KIMGIOGenerator : public Generator bool hasFonts() const; // font related - void putFontInfo(KListView *list); + void putFontInfo(K3ListView *list); // [INHERITED] print document using already configured kprinter bool print( KPrinter& printer ); diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 3c3936813..77109efb4 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -355,7 +355,7 @@ bool PDFGenerator::hasFonts() const return true; } -void PDFGenerator::putFontInfo(KListView *list) +void PDFGenerator::putFontInfo(K3ListView *list) { Page *page; Dict *resDict; @@ -537,7 +537,7 @@ static QString unicodeToQString(Unicode* u, int len) { return ret; } -void PDFGenerator::scanFonts(Dict *resDict, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize) +void PDFGenerator::scanFonts(Dict *resDict, K3ListView *list, Ref **fonts, int &fontsLen, int &fontsSize) { Object obj1, obj2, xObjDict, xObj, resObj; Ref r; @@ -592,7 +592,7 @@ void PDFGenerator::scanFonts(Dict *resDict, KListView *list, Ref **fonts, int &f xObjDict.free(); } -void PDFGenerator::scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize) +void PDFGenerator::scanFont(GfxFont *font, K3ListView *list, Ref **fonts, int &fontsLen, int &fontsSize) { Ref fontRef, embRef; Object fontObj, toUnicodeObj; @@ -651,7 +651,7 @@ void PDFGenerator::scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fo sPath = i18n("-"); } sEmb = emb ? i18n("Yes") : i18n("No"); - new KListViewItem(list, sName, fontTypeNames[font->getType()], sEmb, sPath); + new K3ListViewItem(list, sName, fontTypeNames[font->getType()], sEmb, sPath); // add this font to the list if (fontsLen == fontsSize) diff --git a/core/generator_pdf/generator_pdf.h b/core/generator_pdf/generator_pdf.h index 3b3024892..d983511de 100644 --- a/core/generator_pdf/generator_pdf.h +++ b/core/generator_pdf/generator_pdf.h @@ -72,7 +72,7 @@ class PDFGenerator : public Generator bool hasFonts() const; // [INHERITED] font related - void putFontInfo(KListView *list); + void putFontInfo(K3ListView *list); // [INHERITED] print page using an already configured kprinter bool print( KPrinter& printer ); @@ -87,8 +87,8 @@ class PDFGenerator : public Generator // friend class to access private document related variables friend class PDFPixmapGeneratorThread; - void scanFonts(Dict *resDict, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize); - void scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize); + void scanFonts(Dict *resDict, K3ListView *list, Ref **fonts, int &fontsLen, int &fontsSize); + void scanFont(GfxFont *font, K3ListView *list, Ref **fonts, int &fontsLen, int &fontsSize); void fillViewportFromLink( DocumentViewport &viewport, LinkDest *destination ); diff --git a/ui/propertiesdialog.cpp b/ui/propertiesdialog.cpp index cefa2f262..49b97fc3f 100644 --- a/ui/propertiesdialog.cpp +++ b/ui/propertiesdialog.cpp @@ -10,7 +10,7 @@ // qt/kde includes #include #include -#include +#include #include #include #include @@ -76,7 +76,7 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) { QFrame *page2 = addPage(i18n("Fonts")); page2Layout = new QVBoxLayout(page2, 0, KDialog::spacingHint()); - KListView *lv = new KListView(page2); + K3ListView *lv = new K3ListView(page2); page2Layout->add(lv); doc->putFontInfo(lv); } diff --git a/ui/toc.cpp b/ui/toc.cpp index fde4998fa..62de29ab4 100644 --- a/ui/toc.cpp +++ b/ui/toc.cpp @@ -21,11 +21,11 @@ // they're slow when converted to page number. drop the 2nd column idea. //#define TOC_ENABLE_PAGE_COLUMN -class TOCItem : public KListViewItem +class TOCItem : public K3ListViewItem { public: - TOCItem( KListView *parent, TOCItem *after, const QDomElement & e ) - : KListViewItem( parent, after, e.tagName() ), m_element( e ) + TOCItem( K3ListView *parent, TOCItem *after, const QDomElement & e ) + : K3ListViewItem( parent, after, e.tagName() ), m_element( e ) { #ifdef TOC_ENABLE_PAGE_COLUMN if ( e.hasAttribute( "Page" ) ) @@ -34,8 +34,8 @@ class TOCItem : public KListViewItem setMultiLinesEnabled( true ); } - TOCItem( KListViewItem *parent, TOCItem *after, const QDomElement & e ) - : KListViewItem( parent, after, e.tagName() ), m_element( e ) + TOCItem( K3ListViewItem *parent, TOCItem *after, const QDomElement & e ) + : K3ListViewItem( parent, after, e.tagName() ), m_element( e ) { #ifdef TOC_ENABLE_PAGE_COLUMN if ( e.hasAttribute( "Page" ) ) @@ -53,7 +53,7 @@ class TOCItem : public KListViewItem QDomElement m_element; }; -TOC::TOC(QWidget *parent, KPDFDocument *document) : KListView(parent), m_document(document) +TOC::TOC(QWidget *parent, KPDFDocument *document) : K3ListView(parent), m_document(document) { addColumn( i18n("Topic") ); #ifdef TOC_ENABLE_PAGE_COLUMN @@ -102,7 +102,7 @@ void TOC::notifySetup( const QVector< KPDFPage * > & /*pages*/, bool documentCha emit hasTOC( true ); } -void TOC::addChildren( const QDomNode & parentNode, KListViewItem * parentItem ) +void TOC::addChildren( const QDomNode & parentNode, K3ListViewItem * parentItem ) { // keep track of the current listViewItem TOCItem * currentItem = 0; diff --git a/ui/toc.h b/ui/toc.h index 897822479..11443ec9a 100644 --- a/ui/toc.h +++ b/ui/toc.h @@ -11,13 +11,13 @@ #define _KPDF_TOC_H_ #include -#include +#include #include "core/document.h" #include "core/observer.h" class KPDFDocument; -class TOC : public KListView, public DocumentObserver +class TOC : public K3ListView, public DocumentObserver { Q_OBJECT public: @@ -35,7 +35,7 @@ Q_OBJECT void slotExecuted(Q3ListViewItem *i); private: - void addChildren( const QDomNode & parentNode, KListViewItem * parentItem = 0 ); + void addChildren( const QDomNode & parentNode, K3ListViewItem * parentItem = 0 ); DocumentViewport getViewport( const QDomElement &e ) const; KPDFDocument *m_document; }; From 656e93612be5d8a4a3f5dd32b280766b3c2e2439 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Tue, 14 Mar 2006 13:38:48 +0000 Subject: [PATCH 224/245] Minor fix svn path=/trunk/KDE/kdegraphics/kpdf/; revision=518555 --- shell/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index 79b553d0d..c5f8472b6 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -11,7 +11,7 @@ kde4_automoc(${kpdf_SRCS}) kde4_add_executable(kpdf ${kpdf_SRCS}) -target_link_libraries(kpdf ${QT_AND_KDECORE_LIBS} kparts ) +target_link_libraries(kpdf ${LIB_KPARTS} ) install_targets(/bin kpdf ) From 59d8b30707695bbd9967d5057b88d020d2b62d2b Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Tue, 14 Mar 2006 13:42:24 +0000 Subject: [PATCH 225/245] error.cpp was removed svn path=/trunk/KDE/kdegraphics/kpdf/; revision=518556 --- CMakeLists.txt | 3 ++- Makefile.am | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7214840fc..e51d7348f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,10 +7,11 @@ add_subdirectory( shell ) include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) +macro_optional_find_package(KPDF) ########### next target ############### -set(kpdfpart_PART_SRCS error.cpp part.cpp ) +set(kpdfpart_PART_SRCS part.cpp ) kde4_automoc(${kpdfpart_PART_SRCS}) diff --git a/Makefile.am b/Makefile.am index 7b17f1833..6ff4d61e3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,7 @@ KDE_ICON = kpdf ######################################################################### kde_module_LTLIBRARIES = libkpdfpart.la -libkpdfpart_la_SOURCES = dcop.skel error.cpp part.cpp +libkpdfpart_la_SOURCES = dcop.skel part.cpp libkpdfpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) libkpdfpart_la_LIBADD = $(POPPLER_LIBS) conf/libkpdfconf.la \ core/libkpdfcore.la ui/libkpdfui.la $(LIB_KPARTS) \ From 65bfab83c02156f09e3ebffb326f331336b3bca2 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Tue, 14 Mar 2006 14:05:19 +0000 Subject: [PATCH 226/245] Try to fix compile svn path=/trunk/KDE/kdegraphics/kpdf/; revision=518569 --- CMakeLists.txt | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e51d7348f..28d5029e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,9 +9,40 @@ include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_D macro_optional_find_package(KPDF) +set(libkpdfconf_SRCS ${CMAKE_SOURCE_DIR}/kpdf/conf/preferencesdialog.cpp ) + +kde4_add_ui3_files(libkpdfconf_SRCS + ${CMAKE_SOURCE_DIR}/kpdf/conf/dlggeneral.ui + ${CMAKE_SOURCE_DIR}/kpdf/conf/dlgperformance.ui + ${CMAKE_SOURCE_DIR}/kpdf/conf/dlgaccessibility.ui + ${CMAKE_SOURCE_DIR}/kpdf/conf/dlgpresentation.ui + ) + +kde4_add_kcfg_files(libkpdfconf_SRCS ${CMAKE_SOURCE_DIR}/kpdf/conf/settings.kcfgc) + + +set(libkpdfui_SRCS + ${CMAKE_SOURCE_DIR}/kpdf/ui/pagepainter.cpp + ${CMAKE_SOURCE_DIR}/kpdf/ui/pageview.cpp + ${CMAKE_SOURCE_DIR}/kpdf/ui/pageviewutils.cpp + ${CMAKE_SOURCE_DIR}/kpdf/ui/minibar.cpp + ${CMAKE_SOURCE_DIR}/kpdf/ui/thumbnaillist.cpp + ${CMAKE_SOURCE_DIR}/kpdf/ui/searchwidget.cpp + ${CMAKE_SOURCE_DIR}/kpdf/ui/toc.cpp + ${CMAKE_SOURCE_DIR}/kpdf/ui/propertiesdialog.cpp + ${CMAKE_SOURCE_DIR}/kpdf/ui/presentationwidget.cpp +) + +set(libkpdfcore_SRCS + ${CMAKE_SOURCE_DIR}/kpdf/core/document.cpp + ${CMAKE_SOURCE_DIR}/kpdf/core/link.cpp + ${CMAKE_SOURCE_DIR}/kpdf/core/page.cpp + ${CMAKE_SOURCE_DIR}/kpdf/core/pagetransition.cpp + ) + ########### next target ############### -set(kpdfpart_PART_SRCS part.cpp ) +set(kpdfpart_PART_SRCS part.cpp ${libkpdfconf_SRCS} ${libkpdfui_SRCS} ${libkpdfcore_SRCS}) kde4_automoc(${kpdfpart_PART_SRCS}) @@ -21,7 +52,7 @@ kde4_add_plugin(kpdfpart WITH_PREFIX ${kpdfpart_PART_SRCS}) kde4_install_libtool_file( ${PLUGIN_INSTALL_DIR} kpdfpart ) -target_link_libraries(kpdfpart ${QT_AND_KDECORE_LIBS} kpdfconf kpdfcore kpdfui kparts kdeprint kutils m ) +target_link_libraries(kpdfpart ${LIB_KDE3SUPPORT} kpdfcore kpdfui kdeprint m ) install_targets(${LIB_INSTALL_DIR}/kde4 kpdfpart ) From cab83ac86af0a11df00884597e5897c033211b55 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Fri, 17 Mar 2006 08:48:17 +0000 Subject: [PATCH 227/245] add "project(...)" svn path=/trunk/KDE/kdegraphics/kpdf/; revision=519455 --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28d5029e0..22cdff55a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ kde4_header() +project(kpdf) add_subdirectory( conf ) add_subdirectory( core ) From 86f688fce1e232eac86b005c953e0a6e01d5b92f Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Wed, 22 Mar 2006 14:28:19 +0000 Subject: [PATCH 228/245] Use new cmake variable svn path=/trunk/KDE/kdegraphics/kpdf/; revision=521413 --- CMakeLists.txt | 2 +- shell/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22cdff55a..471e7cf95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,7 @@ kde4_add_plugin(kpdfpart WITH_PREFIX ${kpdfpart_PART_SRCS}) kde4_install_libtool_file( ${PLUGIN_INSTALL_DIR} kpdfpart ) -target_link_libraries(kpdfpart ${LIB_KDE3SUPPORT} kpdfcore kpdfui kdeprint m ) +target_link_libraries(kpdfpart ${KDE4_KDE3SUPPORT_LIBRARIES} kpdfcore kpdfui kdeprint m ) install_targets(${LIB_INSTALL_DIR}/kde4 kpdfpart ) diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index c5f8472b6..bf40a9c7c 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -11,7 +11,7 @@ kde4_automoc(${kpdf_SRCS}) kde4_add_executable(kpdf ${kpdf_SRCS}) -target_link_libraries(kpdf ${LIB_KPARTS} ) +target_link_libraries(kpdf ${KDE4_KPARTS_LIBRARIES} ) install_targets(/bin kpdf ) From eadc305fd6abe3ed7a44aa03c1c370c7c1ec56d9 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Wed, 22 Mar 2006 14:29:19 +0000 Subject: [PATCH 229/245] Fix with new kdelibs api svn path=/trunk/KDE/kdegraphics/kpdf/; revision=521415 --- ui/presentationwidget.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index fa870e4f6..b2df886ea 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -299,12 +299,12 @@ void PresentationWidget::paintEvent( QPaintEvent * pe ) // create top toolbar m_topBar = new QToolBar( this ); - m_topBar->addAction( QIcon(il->loadIcon("1leftarrow", KIcon::Toolbar)), i18n("Previous Page"), this, SLOT( slotPrevPage() ) ); - m_topBar->addAction( QIcon(il->loadIcon("1rightarrow", KIcon::Toolbar)), i18n("Next Page"), this, SLOT( slotNextPage() ) ); + m_topBar->addAction( QIcon(il->loadIcon("1leftarrow", K3Icon::Toolbar)), i18n("Previous Page"), this, SLOT( slotPrevPage() ) ); + m_topBar->addAction( QIcon(il->loadIcon("1rightarrow", K3Icon::Toolbar)), i18n("Next Page"), this, SLOT( slotNextPage() ) ); QWidget *spacer = new QWidget(m_topBar); spacer->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ); m_topBar->addWidget( spacer ); - m_topBar->addAction( QIcon(il->loadIcon("exit", KIcon::Toolbar)), i18n("Exit Presentation Mode"), this, SLOT( close() ) ); + m_topBar->addAction( QIcon(il->loadIcon("exit", K3Icon::Toolbar)), i18n("Exit Presentation Mode"), this, SLOT( close() ) ); m_topBar->setGeometry( 0, 0, m_width, 32 + 10 ); m_topBar->hide(); // change topbar background color From 93af1d400b78fdab4ef9060eb1613b61eec9f97c Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Fri, 24 Mar 2006 16:23:28 +0000 Subject: [PATCH 230/245] Fix use cmake variable svn path=/trunk/KDE/kdegraphics/kpdf/; revision=522168 --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 471e7cf95..e45899bfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,6 @@ kde4_add_ui3_files(libkpdfconf_SRCS kde4_add_kcfg_files(libkpdfconf_SRCS ${CMAKE_SOURCE_DIR}/kpdf/conf/settings.kcfgc) - set(libkpdfui_SRCS ${CMAKE_SOURCE_DIR}/kpdf/ui/pagepainter.cpp ${CMAKE_SOURCE_DIR}/kpdf/ui/pageview.cpp From 87280f3da183e7338d74e5f2cc562467b827b688 Mon Sep 17 00:00:00 2001 From: Chusslove Illich Date: Mon, 10 Apr 2006 11:45:42 +0000 Subject: [PATCH 231/245] Conversion to new i18n API (see KDE4PORTING.html->I18N->i18n calls). svn path=/trunk/KDE/kdegraphics/kpdf/; revision=528186 --- core/document.cpp | 4 ++-- core/generator_pdf/generator_pdf.cpp | 4 ++-- part.cpp | 10 +++++----- ui/pageview.cpp | 24 +++++++++++++----------- ui/presentationwidget.cpp | 6 +++--- ui/propertiesdialog.cpp | 4 ++-- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 212f6c078..e9908d512 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -779,7 +779,7 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar } } else if ( !noDialogs ) - KMessageBox::information( 0, i18n("No matches found for '%1'.").arg( text ) ); + KMessageBox::information( 0, i18n("No matches found for '%1'.", text ) ); } // 3. PREVMATCH //TODO else if ( type == PrevMatch ) @@ -998,7 +998,7 @@ void KPDFDocument::processLink( const KPDFLink * link ) KRun::run( *ptr, lst ); } else - KMessageBox::information( 0, i18n( "No application found for opening file of mimetype %1." ).arg( mime->name() ) ); + KMessageBox::information( 0, i18n( "No application found for opening file of mimetype %1.", mime->name() ) ); } break; case KPDFLink::Action: { diff --git a/core/generator_pdf/generator_pdf.cpp b/core/generator_pdf/generator_pdf.cpp index 77109efb4..b7ad74848 100644 --- a/core/generator_pdf/generator_pdf.cpp +++ b/core/generator_pdf/generator_pdf.cpp @@ -205,8 +205,8 @@ const DocumentInfo * PDFGenerator::generateDocumentInfo() docInfo.set( "mimeType", "application/pdf" ); if ( pdfdoc ) { - docInfo.set( "format", i18n( "PDF v. ", "PDF v. %1" ) - .arg( QString::number( pdfdoc->getPDFVersion() ) ), i18n( "Format" ) ); + docInfo.set( "format", i18nc( "PDF v. ", "PDF v. %1" , + pdfdoc->getPDFVersion() ), i18n( "Format" ) ); docInfo.set( "encryption", pdfdoc->isEncrypted() ? i18n( "Encrypted" ) : i18n( "Unencrypted" ), i18n("Security") ); docInfo.set( "optimization", pdfdoc->isLinearized() ? i18n( "Yes" ) : i18n( "No" ), diff --git a/part.cpp b/part.cpp index ea77be367..7663e28ef 100644 --- a/part.cpp +++ b/part.cpp @@ -454,7 +454,7 @@ bool Part::openURL(const KUrl &url) // this calls the above 'openURL' method bool b = KParts::ReadOnlyPart::openURL(url); if ( !b ) - KMessageBox::error( widget(), i18n("Could not open %1").arg( url.prettyURL() ) ); + KMessageBox::error( widget(), i18n("Could not open %1", url.prettyURL() ) ); else m_viewportDirty.pageNumber = -1; return b; @@ -704,17 +704,17 @@ void Part::slotSaveFileAs() { if (saveURL == url()) { - KMessageBox::information( widget(), i18n("You are trying to overwrite \"%1\" with itself. This is not allowed. Please save it in another location.").arg(saveURL.fileName()) ); + KMessageBox::information( widget(), i18n("You are trying to overwrite \"%1\" with itself. This is not allowed. Please save it in another location.", saveURL.fileName()) ); return; } if ( KIO::NetAccess::exists( saveURL, false, widget() ) ) { - if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.fileName()), QString::null, i18n("Overwrite")) != KMessageBox::Continue) + if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?", saveURL.fileName()), QString::null, i18n("Overwrite")) != KMessageBox::Continue) return; } if ( !KIO::NetAccess::file_copy( url(), saveURL, -1, true ) ) - KMessageBox::information( 0, i18n("File could not be saved in '%1'. Try to save it to another location.").arg( saveURL.prettyURL() ) ); + KMessageBox::information( 0, i18n("File could not be saved in '%1'. Try to save it to another location.", saveURL.prettyURL() ) ); } } @@ -841,7 +841,7 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) fitPageWidth = 0; if (page) { - popup->addTitle( i18n( "Page %1" ).arg( page->number() + 1 ) ); + popup->addTitle( i18n( "Page %1", page->number() + 1 ) ); if ( page->hasBookmark() ) toggleBookmark = popup->addAction( QIcon(SmallIcon("bookmark")), i18n("Remove Bookmark") ); else diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 1d7005016..789ca7620 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -283,7 +283,7 @@ void PageView::notifySetup( const QVector< KPDFPage * > & pageSet, bool document // OSD to display pages if ( documentChanged && pageSet.count() > 0 && KpdfSettings::showOSD() ) d->messageWindow->display( - i18n(" Loaded a one-page document.", + i18np(" Loaded a one-page document.", " Loaded a %n-page document.", pageSet.count() ), PageViewMessage::Info, 4000 ); @@ -586,8 +586,9 @@ void PageView::keyPressEvent( QKeyEvent * e ) d->typeAheadString = d->typeAheadString.left( d->typeAheadString.length() - 1 ); bool found = d->document->searchText( PAGEVIEW_SEARCH_ID, d->typeAheadString, true, false, KPDFDocument::NextMatch, true, qRgb( 128, 255, 128 ), true ); - QString status = found ? i18n("Text found: \"%1\".") : i18n("Text not found: \"%1\"."); - d->messageWindow->display( status.arg(d->typeAheadString.toLower()), + QString text = d->typeAheadString.toLower(); + QString status = found ? i18n("Text found: \"%1\".", text) : i18n("Text not found: \"%1\".", text); + d->messageWindow->display( status, found ? PageViewMessage::Find : PageViewMessage::Warning, 4000 ); d->findTimeoutTimer->start( 3000, true ); } @@ -607,7 +608,7 @@ void PageView::keyPressEvent( QKeyEvent * e ) // because it activates the accel releaseKeyboard(); if ( d->document->continueSearch( PAGEVIEW_SEARCH_ID ) ) - d->messageWindow->display( i18n("Text found: \"%1\".").arg(d->typeAheadString.toLower()), + d->messageWindow->display( i18n("Text found: \"%1\".", d->typeAheadString.toLower()), PageViewMessage::Find, 3000 ); d->findTimeoutTimer->start( 3000, true ); // it is needed to grab the keyboard becase people may have Space assigned to a @@ -626,8 +627,9 @@ void PageView::keyPressEvent( QKeyEvent * e ) d->typeAheadString += e->text(); bool found = d->document->searchText( PAGEVIEW_SEARCH_ID, d->typeAheadString, false, false, KPDFDocument::NextMatch, true, qRgb( 128, 255, 128 ), true ); - QString status = found ? i18n("Text found: \"%1\".") : i18n("Text not found: \"%1\"."); - d->messageWindow->display( status.arg(d->typeAheadString.toLower()), + QString text = d->typeAheadString.toLower(); + QString status = found ? i18n("Text found: \"%1\".", text) : i18n("Text not found: \"%1\".", text); + d->messageWindow->display( status, found ? PageViewMessage::Find : PageViewMessage::Warning, 4000 ); d->findTimeoutTimer->start( 3000, true ); } @@ -1027,14 +1029,14 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) QAction *textToClipboard = 0, *speakText = 0, *imageToClipboard = 0, *imageToFile = 0; if ( !selectedText.isEmpty() ) { - menu.addTitle( i18n( "Text (1 character)", "Text (%n characters)", selectedText.length() ) ); + menu.addTitle( i18np( "Text (1 character)", "Text (%n characters)", selectedText.length() ) ); textToClipboard = menu.addAction( QIcon(SmallIcon("editcopy")), i18n( "Copy to Clipboard" ) ); if ( !d->document->isAllowed( KPDFDocument::AllowCopy ) ) menu.setItemEnabled( 1, false ); if ( KpdfSettings::useKTTSD() ) speakText = menu.addAction( QIcon(SmallIcon("kttsd")), i18n( "Speak Text" ) ); } - menu.addTitle( i18n( "Image (%1 by %2 pixels)" ).arg( selectionRect.width() ).arg( selectionRect.height() ) ); + menu.addTitle( i18n( "Image (%1 by %2 pixels)", selectionRect.width(), selectionRect.height() ) ); imageToClipboard = menu.addAction( QIcon(SmallIcon("image")), i18n( "Copy to Clipboard" ) ); imageToFile = menu.addAction( QIcon(SmallIcon("filesave")), i18n( "Save to File..." ) ); QAction *choice = menu.exec( e->globalPos() ); @@ -1054,7 +1056,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) cb->setPixmap( copyPix, QClipboard::Clipboard ); if ( cb->supportsSelection() ) cb->setPixmap( copyPix, QClipboard::Selection ); - d->messageWindow->display( i18n( "Image [%1x%2] copied to clipboard." ).arg( copyPix.width() ).arg( copyPix.height() ) ); + d->messageWindow->display( i18n( "Image [%1x%2] copied to clipboard.", copyPix.width(), copyPix.height() ) ); } else if ( choice == imageToFile ) { @@ -1071,7 +1073,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) else type = mime->name(); copyPix.save( fileName, type.toLatin1() ); - d->messageWindow->display( i18n( "Image [%1x%2] saved to %3 file." ).arg( copyPix.width() ).arg( copyPix.height() ).arg( type ) ); + d->messageWindow->display( i18n( "Image [%1x%2] saved to %3 file.", copyPix.width(), copyPix.height(), type ) ); } } } @@ -1100,7 +1102,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) QString error; if (KToolInvocation::startServiceByDesktopName("kttsd", QStringList(), &error)) { - d->messageWindow->display( i18n("Starting KTTSD Failed: %1").arg(error) ); + d->messageWindow->display( i18n("Starting KTTSD Failed: %1", error) ); KpdfSettings::setUseKTTSD(false); KpdfSettings::writeConfig(); } diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index b2df886ea..8f91f89ab 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -137,11 +137,11 @@ void PresentationWidget::notifySetup( const QVector< KPDFPage * > & pageSet, boo if ( info ) { if ( !info->get( "title" ).isNull() ) - m_metaStrings += i18n( "Title: %1" ).arg( info->get( "title" ) ); + m_metaStrings += i18n( "Title: %1", info->get( "title" ) ); if ( !info->get( "author" ).isNull() ) - m_metaStrings += i18n( "Author: %1" ).arg( info->get( "author" ) ); + m_metaStrings += i18n( "Author: %1", info->get( "author" ) ); } - m_metaStrings += i18n( "Pages: %1" ).arg( m_document->pages() ); + m_metaStrings += i18n( "Pages: %1", m_document->pages() ); m_metaStrings += i18n( "Click to begin" ); } diff --git a/ui/propertiesdialog.cpp b/ui/propertiesdialog.cpp index 49b97fc3f..0035a8981 100644 --- a/ui/propertiesdialog.cpp +++ b/ui/propertiesdialog.cpp @@ -35,7 +35,7 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) // mime name based on mimetype id QString mimeName = info->get( "mimeType" ).section( '/', -1 ).toUpper(); - setCaption( i18n("%1 Properties").arg( mimeName ) ); + setCaption( i18n("%1 Properties", mimeName ) ); QDomElement docElement = info->documentElement(); @@ -50,7 +50,7 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) continue; // create labels and layout them - QLabel *key = new QLabel( i18n( "%1:" ).arg( titleString ), page ); + QLabel *key = new QLabel( i18n( "%1:", titleString ), page ); QLabel *value = new KSqueezedTextLabel( valueString, page ); layout->addWidget( key, row, 0, Qt::AlignRight ); layout->addWidget( value, row, 1 ); From 49ae28b2bf00b993e34ecd4761f33ef31a0a62bd Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Fri, 14 Apr 2006 12:26:13 +0000 Subject: [PATCH 232/245] fix cmake variabl svn path=/trunk/KDE/kdegraphics/kpdf/; revision=529774 --- CMakeLists.txt | 2 +- shell/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e45899bfe..9beaab3ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ kde4_add_plugin(kpdfpart WITH_PREFIX ${kpdfpart_PART_SRCS}) kde4_install_libtool_file( ${PLUGIN_INSTALL_DIR} kpdfpart ) -target_link_libraries(kpdfpart ${KDE4_KDE3SUPPORT_LIBRARIES} kpdfcore kpdfui kdeprint m ) +target_link_libraries(kpdfpart ${KDE4_KDE3SUPPORT_LIBS} kpdfcore kpdfui kdeprint m ) install_targets(${LIB_INSTALL_DIR}/kde4 kpdfpart ) diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index bf40a9c7c..4d6183f7b 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -11,7 +11,7 @@ kde4_automoc(${kpdf_SRCS}) kde4_add_executable(kpdf ${kpdf_SRCS}) -target_link_libraries(kpdf ${KDE4_KPARTS_LIBRARIES} ) +target_link_libraries(kpdf ${KDE4_KPARTS_LIBS} ) install_targets(/bin kpdf ) From 66aca20f53b8078a11827b89cc5f5820fda38ddb Mon Sep 17 00:00:00 2001 From: Carsten Pfeiffer Date: Tue, 18 Apr 2006 00:25:07 +0000 Subject: [PATCH 233/245] forward port: - consistency: use KCursor everywhere, not just in some places svn path=/trunk/KDE/kdegraphics/kpdf/; revision=530902 --- ui/pageview.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 789ca7620..fdd10a574 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -830,7 +831,7 @@ void PageView::contentsMousePressEvent( QMouseEvent * e ) if ( e->button() & Qt::MidButton ) { d->mouseMidStartY = e->globalPos().y(); - setCursor( Qt::SizeHorCursor ); + setCursor( KCursor::sizeHorCursor() ); return; } @@ -847,7 +848,7 @@ void PageView::contentsMousePressEvent( QMouseEvent * e ) { d->mouseGrabPos = d->mouseOnRect ? QPoint() : d->mousePressPos; if ( !d->mouseOnRect ) - setCursor( Qt::SizeAllCursor ); + setCursor( KCursor::sizeAllCursor() ); } break; @@ -1517,16 +1518,16 @@ void PageView::updateCursor( const QPoint &p ) // if over a ObjectRect (of type Link) change cursor to hand d->mouseOnRect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY ); if ( d->mouseOnRect ) - setCursor( Qt::PointingHandCursor ); + setCursor( KCursor::pointingHandCursor() ); else - setCursor( Qt::ArrowCursor ); + setCursor( KCursor::arrowCursor() ); } else { // if there's no page over the cursor and we were showing the pointingHandCursor // go back to the normal one d->mouseOnRect = false; - setCursor( Qt::ArrowCursor ); + setCursor( KCursor::arrowCursor() ); } } From 1c424c1738cabaf315886589309a6a8b5cf07038 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Tue, 18 Apr 2006 07:55:37 +0000 Subject: [PATCH 234/245] better use svn path=/trunk/KDE/kdegraphics/kpdf/; revision=530950 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9beaab3ea..dc9c4aceb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ kde4_install_libtool_file( ${PLUGIN_INSTALL_DIR} kpdfpart ) target_link_libraries(kpdfpart ${KDE4_KDE3SUPPORT_LIBS} kpdfcore kpdfui kdeprint m ) -install_targets(${LIB_INSTALL_DIR}/kde4 kpdfpart ) +install_targets(${PLUGIN_INSTALL_DIR} kpdfpart ) ########### install files ############### From 655d2607edac0405b799d99c364db591cbdbb79b Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 28 Apr 2006 18:05:32 +0000 Subject: [PATCH 235/245] fordwardport r535156 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=535159 --- part.cpp | 1 + shell/shell.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/part.cpp b/part.cpp index 7663e28ef..eb82d00d6 100644 --- a/part.cpp +++ b/part.cpp @@ -457,6 +457,7 @@ bool Part::openURL(const KUrl &url) KMessageBox::error( widget(), i18n("Could not open %1", url.prettyURL() ) ); else m_viewportDirty.pageNumber = -1; + emit enablePrintAction(b); return b; } diff --git a/shell/shell.cpp b/shell/shell.cpp index 7beedd28f..d0c17c1fe 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -119,7 +119,6 @@ void Shell::openURL( const KUrl & url ) bool openOk = m_part->openURL( url ); if ( openOk ) m_recent->addURL( url ); else m_recent->removeURL( url ); - m_printAction->setEnabled( openOk ); } } From 7e58d7094346db1e35284286df94b08c1fa146e5 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Sun, 30 Apr 2006 18:04:43 +0000 Subject: [PATCH 236/245] replaced QColorGroup:: with QPalette:: svn path=/trunk/KDE/kdegraphics/kpdf/; revision=535911 --- ui/minibar.cpp | 2 +- ui/pageviewutils.cpp | 2 +- ui/presentationwidget.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/minibar.cpp b/ui/minibar.cpp index b5d4951fd..0ab165715 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -434,7 +434,7 @@ void HoverButton::paintEvent( QPaintEvent * e ) else { QPainter p( this ); - p.fillRect(e->rect(), parentWidget() ? parentWidget()->palette().brush(QPalette::Active, QColorGroup::Background) : QBrush(paletteBackgroundColor())); + p.fillRect(e->rect(), parentWidget() ? parentWidget()->palette().brush(QPalette::Active, QPalette::Background) : QBrush(paletteBackgroundColor())); #warning drawButtonLabel does not exists in Qt4 // drawButtonLabel( &p ); } diff --git a/ui/pageviewutils.cpp b/ui/pageviewutils.cpp index 3a8488207..39464fecb 100644 --- a/ui/pageviewutils.cpp +++ b/ui/pageviewutils.cpp @@ -27,7 +27,7 @@ PageViewMessage::PageViewMessage( QWidget * parent ) { setFocusPolicy( Qt::NoFocus ); setBackgroundMode( Qt::NoBackground ); - setPaletteBackgroundColor(kapp->palette().color(QPalette::Active, QColorGroup::Background)); + setPaletteBackgroundColor(kapp->palette().color(QPalette::Active, QPalette::Background)); move( 10, 10 ); resize( 0, 0 ); hide(); diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp index 8f91f89ab..8c8ce3986 100644 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -309,8 +309,8 @@ void PresentationWidget::paintEvent( QPaintEvent * pe ) m_topBar->hide(); // change topbar background color QPalette p = m_topBar->palette(); - p.setColor( QPalette::Active, QColorGroup::Button, Qt::gray ); - p.setColor( QPalette::Active, QColorGroup::Background, Qt::darkGray ); + p.setColor( QPalette::Active, QPalette::Button, Qt::gray ); + p.setColor( QPalette::Active, QPalette::Background, Qt::darkGray ); m_topBar->setPalette( p ); // register this observer in document. events will come immediately From 1adaaa3828399fc2ae7efa83b4ddb3f0dea7df1e Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 1 May 2006 18:59:41 +0000 Subject: [PATCH 237/245] moved messages targets out of the Makefile.am svn path=/trunk/KDE/kdegraphics/kpdf/; revision=536282 --- Makefile.am | 3 --- Messages.sh | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 Messages.sh diff --git a/Makefile.am b/Makefile.am index 6ff4d61e3..5b02049c2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,9 +4,6 @@ INCLUDES = -I$(top_builddir)/kpdf $(all_includes) $(POPPLER_CFLAGS) METASOURCES = AUTO -messages: rc.cpp - $(EXTRACTRC) `find . -name "*.rc" -o -name "*.ui"` >> rc.cpp - $(XGETTEXT) `find . -name "*.cpp" -o -name "*.cc" -o -name "*.h"` -o $(podir)/kpdf.pot KDE_ICON = kpdf diff --git a/Messages.sh b/Messages.sh new file mode 100644 index 000000000..ed6c82316 --- /dev/null +++ b/Messages.sh @@ -0,0 +1,3 @@ +#! /bin/sh +$EXTRACTRC `find . -name "*.rc" -o -name "*.ui"` >> rc.cpp || exit 11 +$XGETTEXT `find . -name "*.cpp" -o -name "*.cc" -o -name "*.h"` -o $podir/kpdf.pot From 2805d4cb34be16a60e824cf02b8ef41c1303e016 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Wed, 3 May 2006 19:22:26 +0000 Subject: [PATCH 238/245] deprecated-- svn path=/trunk/KDE/kdegraphics/kpdf/; revision=537038 --- part.cpp | 4 +++- ui/minibar.cpp | 4 +++- ui/propertiesdialog.cpp | 8 ++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/part.cpp b/part.cpp index eb82d00d6..17227f66b 100644 --- a/part.cpp +++ b/part.cpp @@ -611,7 +611,9 @@ public: QWidget *w = new QWidget(this); setMainWidget(w); - QVBoxLayout *topLayout = new QVBoxLayout( w, 0, spacingHint() ); + QVBoxLayout *topLayout = new QVBoxLayout( w ); + topLayout->setSpacing( spacingHint() ); + topLayout->setMargin( 0 ); e1 = new KIntNumInput(current, w); e1->setRange(1, max); e1->setEditFocus(true); diff --git a/ui/minibar.cpp b/ui/minibar.cpp index 0ab165715..c4d2551f4 100644 --- a/ui/minibar.cpp +++ b/ui/minibar.cpp @@ -89,7 +89,9 @@ MiniBar::MiniBar( QWidget * parent, KPDFDocument * document ) horLayout->addItem( spacerL ); // central 2r by 3c grid layout that contains all components - QGridLayout * gridLayout = new QGridLayout( 0, 3,5, 2,1 ); + QGridLayout * gridLayout = new QGridLayout(); + gridLayout->setSpacing( 1 ); + gridLayout->setMargin( 2 ); // top spacer 6x6 px // QSpacerItem * spacerTop = new QSpacerItem( 6, 6, QSizePolicy::Fixed, QSizePolicy::Fixed ); // gridLayout->addMultiCell( spacerTop, 0, 0, 0, 4 ); diff --git a/ui/propertiesdialog.cpp b/ui/propertiesdialog.cpp index 0035a8981..6878dc61f 100644 --- a/ui/propertiesdialog.cpp +++ b/ui/propertiesdialog.cpp @@ -24,7 +24,9 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) { // Properties QFrame *page = addPage(i18n("Properties")); - QGridLayout *layout = new QGridLayout( page, 2, 2, marginHint(), spacingHint() ); + QGridLayout *layout = new QGridLayout( page ); + layout->setSpacing( spacingHint() ); + layout->setMargin( marginHint() ); // get document info, if not present display blank data and a warning const DocumentInfo * info = doc->documentInfo(); @@ -75,7 +77,9 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) if (doc->hasFonts()) { QFrame *page2 = addPage(i18n("Fonts")); - page2Layout = new QVBoxLayout(page2, 0, KDialog::spacingHint()); + page2Layout = new QVBoxLayout(page2); + page2Layout->setSpacing(KDialog::spacingHint()); + page2Layout->setMargin(0); K3ListView *lv = new K3ListView(page2); page2Layout->add(lv); doc->putFontInfo(lv); From 6816aa5cf0c19448e2da5c51858bec966c43c4d0 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Mon, 8 May 2006 11:57:23 +0000 Subject: [PATCH 239/245] Add missing include svn path=/trunk/KDE/kdegraphics/kpdf/; revision=538595 --- shell/shell.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/shell.h b/shell/shell.h index 353928345..a08ddb972 100644 --- a/shell/shell.h +++ b/shell/shell.h @@ -19,7 +19,7 @@ #ifdef HAVE_CONFIG_H #include #endif - +#include #include namespace KPDF From 202ed24f9d7fe09e74dbbe01f849e550a8555dfe Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Mon, 8 May 2006 12:11:18 +0000 Subject: [PATCH 240/245] Fix some missing include Fix compile svn path=/trunk/KDE/kdegraphics/kpdf/; revision=538600 --- part.cpp | 2 +- shell/shell.cpp | 2 +- shell/shell.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/part.cpp b/part.cpp index 17227f66b..3b6efe8d8 100644 --- a/part.cpp +++ b/part.cpp @@ -54,7 +54,7 @@ #include #include #include - +#include // poppler includes #include "GlobalParams.h" #include "Error.h" diff --git a/shell/shell.cpp b/shell/shell.cpp index d0c17c1fe..7b13fe804 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -35,7 +35,7 @@ #include #include #include - +#include // local includes #include "shell.h" diff --git a/shell/shell.h b/shell/shell.h index a08ddb972..75d349e47 100644 --- a/shell/shell.h +++ b/shell/shell.h @@ -21,7 +21,7 @@ #endif #include #include - +class KToggleAction; namespace KPDF { class Part; From e194587700310f9fe04057635566a4794471dd72 Mon Sep 17 00:00:00 2001 From: Alexander Neundorf Date: Thu, 11 May 2006 23:46:05 +0000 Subject: [PATCH 241/245] -cleanup the toplevel CMakeLists.txt a bit -remove include_directories( CMAKE_CURRENT_SOURCE_DIR CMAKE_CURRENT_BINARY_DIR) in the subdirs, since this is done now automatically by cmake (the CMAKE_INCLUDE_CURRENT_DIR option -include_directories(KDE4_INCLUDES) in the toplevel CMakeLists.txt, so it doesn't have to be done in every subdir Alex svn path=/trunk/KDE/kdegraphics/doc/kpdf/; revision=539905 --- CMakeLists.txt | 2 +- conf/CMakeLists.txt | 2 +- core/CMakeLists.txt | 2 +- core/generator_kimgio/CMakeLists.txt | 2 +- core/generator_pdf/CMakeLists.txt | 2 +- doc/CMakeLists.txt | 2 +- shell/CMakeLists.txt | 2 +- ui/CMakeLists.txt | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc9c4aceb..9954e526c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ add_subdirectory( core ) add_subdirectory( ui ) add_subdirectory( shell ) -include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + macro_optional_find_package(KPDF) diff --git a/conf/CMakeLists.txt b/conf/CMakeLists.txt index ee1699d16..68077025e 100644 --- a/conf/CMakeLists.txt +++ b/conf/CMakeLists.txt @@ -1,6 +1,6 @@ kde4_header() -include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + ########### next target ############### diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index dfe5bcece..c1224178b 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -3,7 +3,7 @@ kde4_header() add_subdirectory( generator_pdf ) add_subdirectory( generator_kimgio ) -include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + ########### next target ############### diff --git a/core/generator_kimgio/CMakeLists.txt b/core/generator_kimgio/CMakeLists.txt index bd6d0c428..c3b740f89 100644 --- a/core/generator_kimgio/CMakeLists.txt +++ b/core/generator_kimgio/CMakeLists.txt @@ -1,6 +1,6 @@ kde4_header() -include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + ########### next target ############### diff --git a/core/generator_pdf/CMakeLists.txt b/core/generator_pdf/CMakeLists.txt index e2e61866a..5ca623853 100644 --- a/core/generator_pdf/CMakeLists.txt +++ b/core/generator_pdf/CMakeLists.txt @@ -1,6 +1,6 @@ kde4_header() -include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + ########### next target ############### diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 140df82be..b8a30d853 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,6 +1,6 @@ kde4_header() -include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + ########### install files ############### diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index 4d6183f7b..52575c6f0 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -1,6 +1,6 @@ kde4_header() -include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + ########### next target ############### diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index 0da7f8e73..8113aeb36 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -1,6 +1,6 @@ kde4_header() -include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) + ########### next target ############### From b7a0191bc4f266d1d677e61ecaec81fcde61699d Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Fri, 12 May 2006 08:33:46 +0000 Subject: [PATCH 242/245] Remove Makefile.am, all is into CMakeLists.txt Keep for the moment configure.in.in (need for avoid to lose check) svn path=/trunk/KDE/kdegraphics/kpdf/; revision=539985 --- Makefile.am | 27 --------------------------- conf/Makefile.am | 13 ------------- core/Makefile.am | 13 ------------- core/generator_kimgio/Makefile.am | 6 ------ core/generator_pdf/Makefile.am | 10 ---------- doc/Makefile.am | 4 ---- shell/Makefile.am | 15 --------------- ui/Makefile.am | 16 ---------------- 8 files changed, 104 deletions(-) delete mode 100644 Makefile.am delete mode 100644 conf/Makefile.am delete mode 100644 core/Makefile.am delete mode 100644 core/generator_kimgio/Makefile.am delete mode 100644 core/generator_pdf/Makefile.am delete mode 100644 doc/Makefile.am delete mode 100644 shell/Makefile.am delete mode 100644 ui/Makefile.am diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 5b02049c2..000000000 --- a/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -SUBDIRS = conf core ui shell - -INCLUDES = -I$(top_builddir)/kpdf $(all_includes) $(POPPLER_CFLAGS) - -METASOURCES = AUTO - - -KDE_ICON = kpdf - -######################################################################### -# KPART SECTION -######################################################################### -kde_module_LTLIBRARIES = libkpdfpart.la - -libkpdfpart_la_SOURCES = dcop.skel part.cpp -libkpdfpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -libkpdfpart_la_LIBADD = $(POPPLER_LIBS) conf/libkpdfconf.la \ - core/libkpdfcore.la ui/libkpdfui.la $(LIB_KPARTS) \ - $(LIB_KFILE) $(LIB_KDEPRINT) $(LIB_KUTILS) -lm - -partdesktopdir = $(kde_servicesdir) -partdesktop_DATA = kpdf_part.desktop - -partrcdir = $(kde_datadir)/kpdfpart -partrc_DATA = part.rc - -part.lo: conf/settings.h diff --git a/conf/Makefile.am b/conf/Makefile.am deleted file mode 100644 index d115e8f97..000000000 --- a/conf/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -INCLUDES = -I$(srcdir)/.. -I$(top_builddir)/kpdf $(all_includes) - -METASOURCES = AUTO - -libkpdfconf_la_SOURCES = dlggeneral.ui dlgperformance.ui dlgaccessibility.ui \ - dlgpresentation.ui \ - preferencesdialog.cpp settings.kcfgc - -noinst_LTLIBRARIES = libkpdfconf.la - -kde_kcfg_DATA = kpdf.kcfg - -preferencesdialog.lo: settings.h diff --git a/core/Makefile.am b/core/Makefile.am deleted file mode 100644 index 1f0dd72d1..000000000 --- a/core/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -SUBDIRS = generator_pdf generator_kimgio - -INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(top_builddir)/kpdf $(POPPLER_CFLAGS) $(all_includes) - -METASOURCES = AUTO - -libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la ./generator_kimgio/libgeneratorkimgio.la -libkpdfcore_la_SOURCES = document.cpp link.cpp page.cpp pagetransition.cpp - -noinst_LTLIBRARIES = libkpdfcore.la - -document.lo: ../conf/settings.h -page.lo: ../conf/settings.h diff --git a/core/generator_kimgio/Makefile.am b/core/generator_kimgio/Makefile.am deleted file mode 100644 index 5a93221d1..000000000 --- a/core/generator_kimgio/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -INCLUDES = -I$(srcdir)/../../ $(all_includes) - -libgeneratorkimgio_la_LDFLAGS = $(all_libraries) -libgeneratorkimgio_la_SOURCES = generator_kimgio.cpp - -noinst_LTLIBRARIES = libgeneratorkimgio.la diff --git a/core/generator_pdf/Makefile.am b/core/generator_pdf/Makefile.am deleted file mode 100644 index b049bf42c..000000000 --- a/core/generator_pdf/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -INCLUDES = -I$(srcdir)/../.. -I$(top_builddir)/kpdf $(POPPLER_CFLAGS) $(all_includes) - -libgeneratorpdf_la_LDFLAGS = $(all_libraries) -libgeneratorpdf_la_SOURCES = generator_pdf.cpp gp_outputdev.cpp pagetransition.cpp - -noinst_LTLIBRARIES = libgeneratorpdf.la - -KDE_OPTIONS = nofinal - -generator_pdf.lo: ../../conf/settings.h diff --git a/doc/Makefile.am b/doc/Makefile.am deleted file mode 100644 index 085981d9b..000000000 --- a/doc/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ - -KDE_LANG = en -KDE_DOCS = AUTO - diff --git a/shell/Makefile.am b/shell/Makefile.am deleted file mode 100644 index b0e0857fa..000000000 --- a/shell/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -INCLUDES = -I$(top_builddir)/kpdf $(all_includes) - -METASOURCES = AUTO - -bin_PROGRAMS = kpdf - -kpdf_SOURCES = main.cpp shell.cpp -kpdf_LDFLAGS = $(KDE_RPATH) $(all_libraries) -kpdf_LDADD = $(LIB_KPARTS) - -EXTRA_DIST = kpdf.desktop -xdg_apps_DATA = kpdf.desktop - -shellrcdir = $(kde_datadir)/kpdf -shellrc_DATA = shell.rc diff --git a/ui/Makefile.am b/ui/Makefile.am deleted file mode 100644 index 5cbc6ba39..000000000 --- a/ui/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -INCLUDES = -I$(srcdir)/.. -I$(top_builddir)/kpdf $(all_includes) - -METASOURCES = AUTO - -libkpdfui_la_SOURCES = pagepainter.cpp pageview.cpp pageviewutils.cpp \ - minibar.cpp thumbnaillist.cpp searchwidget.cpp \ - toc.cpp propertiesdialog.cpp presentationwidget.cpp - -noinst_LTLIBRARIES = libkpdfui.la - -pageview.lo: ../conf/settings.h -pageviewutils.lo: ../conf/settings.h -presentationwidget.lo: ../conf/settings.h -searchwidget.lo: ../conf/settings.h -thumbnaillist.lo: ../conf/settings.h - From fc37531425c391128bc0dd5bbccd710ddb7fed5e Mon Sep 17 00:00:00 2001 From: Alexander Neundorf Date: Fri, 12 May 2006 18:24:50 +0000 Subject: [PATCH 243/245] kde4_header and kde4_footer() are gone now svn path=/trunk/KDE/kdegraphics/doc/kpdf/; revision=540219 --- CMakeLists.txt | 2 -- conf/CMakeLists.txt | 2 -- core/CMakeLists.txt | 2 -- core/generator_kimgio/CMakeLists.txt | 2 -- core/generator_pdf/CMakeLists.txt | 2 -- doc/CMakeLists.txt | 2 -- shell/CMakeLists.txt | 2 -- ui/CMakeLists.txt | 2 -- 8 files changed, 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9954e526c..4064bac3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,3 @@ -kde4_header() project(kpdf) add_subdirectory( conf ) @@ -64,7 +63,6 @@ install_files( ${DATA_INSTALL_DIR}/kpdfpart FILES part.rc ) kde4_install_icons( ${ICON_INSTALL_DIR} hicolor ) -kde4_footer() diff --git a/conf/CMakeLists.txt b/conf/CMakeLists.txt index 68077025e..58cb56665 100644 --- a/conf/CMakeLists.txt +++ b/conf/CMakeLists.txt @@ -1,4 +1,3 @@ -kde4_header() @@ -10,7 +9,6 @@ kde4_header() install_files( ${KCFG_INSTALL_DIR} FILES kpdf.kcfg ) -kde4_footer() diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index c1224178b..7799c5f96 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,4 +1,3 @@ -kde4_header() add_subdirectory( generator_pdf ) add_subdirectory( generator_kimgio ) @@ -12,7 +11,6 @@ add_subdirectory( generator_kimgio ) ########### install files ############### -kde4_footer() diff --git a/core/generator_kimgio/CMakeLists.txt b/core/generator_kimgio/CMakeLists.txt index c3b740f89..56df1c8c5 100644 --- a/core/generator_kimgio/CMakeLists.txt +++ b/core/generator_kimgio/CMakeLists.txt @@ -1,4 +1,3 @@ -kde4_header() @@ -9,7 +8,6 @@ kde4_header() ########### install files ############### -kde4_footer() diff --git a/core/generator_pdf/CMakeLists.txt b/core/generator_pdf/CMakeLists.txt index 5ca623853..cdc16a3c2 100644 --- a/core/generator_pdf/CMakeLists.txt +++ b/core/generator_pdf/CMakeLists.txt @@ -1,4 +1,3 @@ -kde4_header() @@ -9,7 +8,6 @@ kde4_header() ########### install files ############### -kde4_footer() diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index b8a30d853..83995916c 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,4 +1,3 @@ -kde4_header() @@ -6,7 +5,6 @@ kde4_header() ########### install files ############### -kde4_footer() diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index 52575c6f0..0bea56e74 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -1,4 +1,3 @@ -kde4_header() @@ -21,7 +20,6 @@ install_targets(/bin kpdf ) install_files( ${XDG_APPS_DIR} FILES kpdf.desktop ) install_files( ${DATA_INSTALL_DIR}/kpdf FILES shell.rc ) -kde4_footer() diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index 8113aeb36..f2268e4fb 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -1,4 +1,3 @@ -kde4_header() @@ -9,7 +8,6 @@ kde4_header() ########### install files ############### -kde4_footer() From c639623097fc192eaa004ad969419642086c9444 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 14 May 2006 16:29:24 +0000 Subject: [PATCH 244/245] port r540804 svn path=/trunk/KDE/kdegraphics/kpdf/; revision=540807 --- part.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/part.cpp b/part.cpp index 3b6efe8d8..16c79630f 100644 --- a/part.cpp +++ b/part.cpp @@ -644,7 +644,7 @@ void Part::slotGoToPage() void Part::slotPreviousPage() { - if ( m_document->isOpened() && !m_document->currentPage() < 1 ) + if ( m_document->isOpened() && !(m_document->currentPage() < 1) ) m_document->setViewportPage( m_document->currentPage() - 1 ); } @@ -752,8 +752,8 @@ void Part::slotNewConfig() } bool showSearch = KpdfSettings::showSearchBar(); - if ( m_searchWidget->isShown() != showSearch ) - m_searchWidget->setShown( showSearch ); + if ( !m_searchWidget->isHidden() != showSearch ) + m_searchWidget->setVisible( showSearch ); // Main View (pageView) Q3ScrollView::ScrollBarMode scrollBarMode = KpdfSettings::showScrollBars() ? From 10d319c010b4ac3f057313ac8421560a86156aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burkhard=20L=C3=BCck?= Date: Sun, 21 May 2006 21:43:45 +0000 Subject: [PATCH 245/245] updated documentation CCMAIL:kde-doc-english@kde.org svn path=/trunk/KDE/kdegraphics/doc/kpdf/; revision=543381 --- doc/index.docbook | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/index.docbook b/doc/index.docbook index 823354d6a..7da3ab5fb 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -28,7 +28,7 @@ &FDLNotice; - 2006-01-14 + 2006-05-20 0.5 @@ -59,8 +59,8 @@ Opening Files To view a PDF file in &kpdf;, select FileOpen... - , choose a file in the dialogue and click Open. - As long as you selected a valid PDF file, your file should now be displayed in the main window. + , choose a PDF or PS file in the dialogue and click Open. + Your file should now be displayed in the main window. If you have already opened files in &kpdf; before, you can quickly access them by selecting them in @@ -178,13 +178,13 @@ To navigate between pages you may use the &LMB; (next page) and the &RMB; (previous page), the mouse - wheel, the arrow icons that appear as soon as you move the mouse to the top of the screen, + wheel, the arrow icons that appear as soon as you move the mouse cursor to the top of the screen, or the keys specified in the Navigating section. You can exit presentation mode at any time by pressing the ESC key or clicking - the Quit icon appearing if you move the mouse to the top of the + the Quit icon appearing if you move the mouse cursor to the top of the screen. @@ -212,7 +212,7 @@ - Open a PDF file. If there is already an opened file it will be closed. + Open a PDF or PS file. If there is already an opened file it will be closed. For more information, see the section about Opening Files. @@ -557,7 +557,7 @@ - The mouse will work as a select tool. In that mode clicking &LMB; and dragging will give the option of copying the text/image of current the selected area to the clipboard, or to save it to a file. + The mouse will work as a select tool. In that mode clicking &LMB; and dragging will give the option of copying the text/image of current the selected area to the clipboard, speak a text or to save an image to a file. @@ -691,7 +691,7 @@ The configuration dialogue - + The configuration dialogue