Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Kretzschmar <mkretzschmar@src.gnome.org>2003-03-31 16:45:09 (GMT)
committer Martin Kretzschmar <mkretzschmar@src.gnome.org>2003-03-31 16:45:09 (GMT)
commit6112dfe4b45b0305c7a6f61bd8a847f69f892cbb (patch)
treef75410ae7f3554f92ac89c4a42a0a8bc2da53f57
parent0152000b294f88a4e659fdbce1ee7558ba29111a (diff)
Initial revision
-rw-r--r--pdf/aconf2.h28
-rw-r--r--pdf/xpdf/JBIG2Stream.cc3473
-rw-r--r--pdf/xpdf/JBIG2Stream.h143
-rw-r--r--pdf/xpdf/Outline.cc140
-rw-r--r--pdf/xpdf/Outline.h74
-rw-r--r--pdf/xpdf/PDFDocEncoding.cc44
-rw-r--r--pdf/xpdf/PDFDocEncoding.h16
-rw-r--r--pdf/xpdf/XPDFApp.cc386
-rw-r--r--pdf/xpdf/XPDFApp.h104
-rw-r--r--pdf/xpdf/XPDFCore.cc1913
-rw-r--r--pdf/xpdf/XPDFCore.h296
-rw-r--r--pdf/xpdf/XPDFTree.cc929
-rw-r--r--pdf/xpdf/XPDFTree.h43
-rw-r--r--pdf/xpdf/XPDFTreeP.h85
-rw-r--r--pdf/xpdf/XPDFViewer.cc2318
-rw-r--r--pdf/xpdf/XPDFViewer.h236
-rw-r--r--pdf/xpdf/XPixmapOutputDev.cc84
-rw-r--r--pdf/xpdf/XPixmapOutputDev.h63
-rw-r--r--pdf/xpdf/about-text.h47
-rw-r--r--pdf/xpdf/backArrowDis.xbm6
-rw-r--r--pdf/xpdf/dblLeftArrowDis.xbm6
-rw-r--r--pdf/xpdf/dblRightArrowDis.xbm6
-rw-r--r--pdf/xpdf/findDis.xbm6
-rw-r--r--pdf/xpdf/forwardArrowDis.xbm6
-rw-r--r--pdf/xpdf/leftArrowDis.xbm5
-rw-r--r--pdf/xpdf/print.xbm6
-rw-r--r--pdf/xpdf/printDis.xbm6
-rw-r--r--pdf/xpdf/rightArrowDis.xbm5
28 files changed, 10474 insertions, 0 deletions
diff --git a/pdf/aconf2.h b/pdf/aconf2.h
new file mode 100644
index 0000000..379eea2
--- /dev/null
+++ b/pdf/aconf2.h
@@ -0,0 +1,28 @@
+/*
+ * aconf2.h
+ *
+ * This gets included by aconf.h, and contains miscellaneous global
+ * settings not directly controlled by autoconf. This is a separate
+ * file because otherwise the configure script will munge any
+ * #define/#undef constructs.
+ *
+ * Copyright 2002 Glyph & Cog, LLC
+ */
+
+#ifndef ACONF2_H
+#define ACONF2_H
+
+/*
+ * This controls the use of the interface/implementation pragmas.
+ */
+#ifdef __GNUC__
+#define USE_GCC_PRAGMAS
+#endif
+/* There is a bug in the version of gcc which ships with MacOS X 10.2 */
+#ifdef MAC_OS_X_VERSION_MAX_ALLOWED
+# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2
+# undef USE_GCC_PRAGMAS
+# endif
+#endif
+
+#endif
diff --git a/pdf/xpdf/JBIG2Stream.cc b/pdf/xpdf/JBIG2Stream.cc
new file mode 100644
index 0000000..716fee1
--- /dev/null
+++ b/pdf/xpdf/JBIG2Stream.cc
@@ -0,0 +1,3473 @@
+//========================================================================
+//
+// JBIG2Stream.cc
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include "GList.h"
+#include "Error.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 };
+
+//------------------------------------------------------------------------
+// JBIG2ArithmeticDecoderStats
+//------------------------------------------------------------------------
+
+class JBIG2ArithmeticDecoderStats {
+public:
+
+ JBIG2ArithmeticDecoderStats(int contextSizeA);
+ ~JBIG2ArithmeticDecoderStats();
+ JBIG2ArithmeticDecoderStats *copy();
+ void reset();
+ int getContextSize() { return contextSize; }
+ void copyFrom(JBIG2ArithmeticDecoderStats *stats);
+
+private:
+
+ Guchar *cxTab; // cxTab[cx] = (i[cx] << 1) + mps[cx]
+ int contextSize;
+
+ friend class JBIG2ArithmeticDecoder;
+};
+
+JBIG2ArithmeticDecoderStats::JBIG2ArithmeticDecoderStats(int contextSizeA) {
+ contextSize = contextSizeA;
+ cxTab = (Guchar *)gmalloc((1 << contextSize) * sizeof(Guchar));
+ reset();
+}
+
+JBIG2ArithmeticDecoderStats::~JBIG2ArithmeticDecoderStats() {
+ gfree(cxTab);
+}
+
+JBIG2ArithmeticDecoderStats *JBIG2ArithmeticDecoderStats::copy() {
+ JBIG2ArithmeticDecoderStats *stats;
+
+ stats = new JBIG2ArithmeticDecoderStats(contextSize);
+ memcpy(stats->cxTab, cxTab, 1 << contextSize);
+ return stats;
+}
+
+void JBIG2ArithmeticDecoderStats::reset() {
+ memset(cxTab, 0, 1 << contextSize);
+}
+
+void JBIG2ArithmeticDecoderStats::copyFrom(
+ JBIG2ArithmeticDecoderStats *stats) {
+ memcpy(cxTab, stats->cxTab, 1 << contextSize);
+}
+
+//------------------------------------------------------------------------
+// JBIG2ArithmeticDecoder
+//------------------------------------------------------------------------
+
+class JBIG2ArithmeticDecoder {
+public:
+
+ JBIG2ArithmeticDecoder();
+ ~JBIG2ArithmeticDecoder();
+ void setStream(Stream *strA) { str = strA; }
+ void start();
+ int decodeBit(Guint context, JBIG2ArithmeticDecoderStats *stats);
+ int decodeByte(Guint context, JBIG2ArithmeticDecoderStats *stats);
+
+ // Returns false for OOB, otherwise sets *<x> and returns true.
+ GBool decodeInt(int *x, JBIG2ArithmeticDecoderStats *stats);
+
+ Guint decodeIAID(Guint codeLen,
+ JBIG2ArithmeticDecoderStats *stats);
+
+private:
+
+ int decodeIntBit(JBIG2ArithmeticDecoderStats *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;
+};
+
+Guint JBIG2ArithmeticDecoder::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 JBIG2ArithmeticDecoder::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 JBIG2ArithmeticDecoder::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 JBIG2ArithmeticDecoder::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
+};
+
+JBIG2ArithmeticDecoder::JBIG2ArithmeticDecoder() {
+ str = NULL;
+}
+
+JBIG2ArithmeticDecoder::~JBIG2ArithmeticDecoder() {
+}
+
+void JBIG2ArithmeticDecoder::start() {
+ buf0 = (Guint)str->getChar() & 0xff;
+ buf1 = (Guint)str->getChar() & 0xff;
+
+ // INITDEC
+ c = (buf0 ^ 0xff) << 16;
+ byteIn();
+ c <<= 7;
+ ct -= 7;
+ a = 0x80000000;
+}
+
+int JBIG2ArithmeticDecoder::decodeBit(Guint context,
+ JBIG2ArithmeticDecoderStats *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 JBIG2ArithmeticDecoder::decodeByte(Guint context,
+ JBIG2ArithmeticDecoderStats *stats) {
+ int byte;
+ int i;
+
+ byte = 0;
+ for (i = 0; i < 8; ++i) {
+ byte = (byte << 1) | decodeBit(context, stats);
+ }
+ return byte;
+}
+
+GBool JBIG2ArithmeticDecoder::decodeInt(int *x,
+ JBIG2ArithmeticDecoderStats *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 JBIG2ArithmeticDecoder::decodeIntBit(JBIG2ArithmeticDecoderStats *stats) {
+ int bit;
+
+ bit = decodeBit(prev, stats);
+ if (prev < 0x100) {
+ prev = (prev << 1) | bit;
+ } else {
+ prev = (((prev << 1) | bit) & 0x1ff) | 0x100;
+ }
+ return bit;
+}
+
+Guint JBIG2ArithmeticDecoder::decodeIAID(Guint codeLen,
+ JBIG2ArithmeticDecoderStats *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 JBIG2ArithmeticDecoder::byteIn() {
+ if (buf0 == 0xff) {
+ if (buf1 > 0x8f) {
+ ct = 8;
+ } else {
+ buf0 = buf1;
+ buf1 = (Guint)str->getChar() & 0xff;
+ c = c + 0xfe00 - (buf0 << 9);
+ ct = 7;
+ }
+ } else {
+ buf0 = buf1;
+ buf1 = (Guint)str->getChar() & 0xff;
+ c = c + 0xff00 - (buf0 << 8);
+ ct = 8;
+ }
+}
+
+//------------------------------------------------------------------------
+// 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 *<x> 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) {
+ //~ if buildTable removes the entries with prefixLen=0, this is unneeded
+ if (table[i].prefixLen > 0) {
+ 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;
+}
+
+static int cmpHuffmanTabEntries(const void *p1, const void *p2) {
+ return ((JBIG2HuffmanTable *)p1)->prefixLen
+ - ((JBIG2HuffmanTable *)p2)->prefixLen;
+}
+
+//~ should remove entries with prefixLen = 0
+void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) {
+ Guint i, prefix;
+
+ qsort(table, len, sizeof(JBIG2HuffmanTable), &cmpHuffmanTabEntries);
+ for (i = 0; i < len && table[i].prefixLen == 0; ++i) {
+ table[i].prefix = 0;
+ }
+ prefix = 0;
+ table[i++].prefix = prefix++;
+ for (; i < len; ++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
+//------------------------------------------------------------------------
+
+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 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;
+ data = (Guchar *)gmalloc(h * line);
+}
+
+JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap):
+ JBIG2Segment(segNumA)
+{
+ w = bitmap->w;
+ h = bitmap->h;
+ line = bitmap->line;
+ data = (Guchar *)gmalloc(h * line);
+ memcpy(data, bitmap->data, h * line);
+}
+
+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) {
+ return;
+ }
+ data = (Guchar *)grealloc(data, newH * line);
+ if (pixel) {
+ memset(data + h * line, 0xff, (newH - h) * line);
+ } else {
+ memset(data + h * line, 0x00, (newH - h) * line);
+ }
+ h = newH;
+}
+
+void JBIG2Bitmap::clearToZero() {
+ memset(data, 0, h * line);
+}
+
+void JBIG2Bitmap::clearToOne() {
+ memset(data, 0xff, h * line);
+}
+
+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
+ 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(JBIG2ArithmeticDecoderStats *stats)
+ { genericRegionStats = stats; }
+ void setRefinementRegionStats(JBIG2ArithmeticDecoderStats *stats)
+ { refinementRegionStats = stats; }
+ JBIG2ArithmeticDecoderStats *getGenericRegionStats()
+ { return genericRegionStats; }
+ JBIG2ArithmeticDecoderStats *getRefinementRegionStats()
+ { return refinementRegionStats; }
+
+private:
+
+ Guint size;
+ JBIG2Bitmap **bitmaps;
+ JBIG2ArithmeticDecoderStats *genericRegionStats;
+ JBIG2ArithmeticDecoderStats *refinementRegionStats;
+};
+
+JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA):
+ JBIG2Segment(segNumA)
+{
+ size = sizeA;
+ bitmaps = (JBIG2Bitmap **)gmalloc(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 **)gmalloc(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 JBIG2ArithmeticDecoder();
+ genericRegionStats = new JBIG2ArithmeticDecoderStats(1);
+ refinementRegionStats = new JBIG2ArithmeticDecoderStats(1);
+ iadhStats = new JBIG2ArithmeticDecoderStats(9);
+ iadwStats = new JBIG2ArithmeticDecoderStats(9);
+ iaexStats = new JBIG2ArithmeticDecoderStats(9);
+ iaaiStats = new JBIG2ArithmeticDecoderStats(9);
+ iadtStats = new JBIG2ArithmeticDecoderStats(9);
+ iaitStats = new JBIG2ArithmeticDecoderStats(9);
+ iafsStats = new JBIG2ArithmeticDecoderStats(9);
+ iadsStats = new JBIG2ArithmeticDecoderStats(9);
+ iardxStats = new JBIG2ArithmeticDecoderStats(9);
+ iardyStats = new JBIG2ArithmeticDecoderStats(9);
+ iardwStats = new JBIG2ArithmeticDecoderStats(9);
+ iardhStats = new JBIG2ArithmeticDecoderStats(9);
+ iariStats = new JBIG2ArithmeticDecoderStats(9);
+ iaidStats = new JBIG2ArithmeticDecoderStats(1);
+ huffDecoder = new JBIG2HuffmanDecoder();
+ mmrDecoder = new JBIG2MMRDecoder();
+
+ segments = new GList();
+ if (globalsStream->isStream()) {
+ curStr = globalsStream->getStream();
+ curStr->reset();
+ arithDecoder->setStream(curStr);
+ huffDecoder->setStream(curStr);
+ mmrDecoder->setStream(curStr);
+ readSegments();
+ }
+ globalSegments = segments;
+
+ 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(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 *)gmalloc(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:
+ readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs);
+ 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;
+
+ eofError2:
+ gfree(refSegs);
+ eofError1:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+void 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 **)gmalloc((numInputSyms + numNewSyms) *
+ sizeof(JBIG2Bitmap *));
+ 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());
+ if (refAgg) {
+ resetRefinementStats(sdrTemplate,
+ inputSymbolDict->getRefinementRegionStats());
+ }
+ } else {
+ resetGenericStats(sdTemplate, NULL);
+ if (refAgg) {
+ resetRefinementStats(sdrTemplate, NULL);
+ }
+ }
+ resetIntStats(symCodeLen);
+ arithDecoder->start();
+ }
+
+ // allocate symbol widths storage
+ symWidths = NULL;
+ if (huff && !refAgg) {
+ symWidths = (Guint *)gmalloc(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);
+ }
+ 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;
+ }
+ }
+ 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 (refAggNum == 1) {
+ 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);
+ if (huff) {
+ 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++ = str->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;
+
+ eofError:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+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, sOffset, templ;
+ 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;
+ 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) {
+ seg = findSegment(refSegs[i]);
+ if (seg->getType() == jbig2SegSymbolDict) {
+ numSyms += ((JBIG2SymbolDict *)seg)->getSize();
+ } else if (seg->getType() == jbig2SegCodeTable) {
+ codeTables->append(seg);
+ }
+ }
+ symCodeLen = 0;
+ i = 1;
+ while (i < numSyms) {
+ ++symCodeLen;
+ i <<= 1;
+ }
+
+ // get the symbol bitmaps
+ syms = (JBIG2Bitmap **)gmalloc(numSyms * sizeof(JBIG2Bitmap *));
+ kk = 0;
+ for (i = 0; i < nRefSegs; ++i) {
+ 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].rangeLen = jbig2HuffmanEOT;
+ huffDecoder->buildTable(runLengthTab, 35);
+ symCodeTab = (JBIG2HuffmanTable *)gmalloc((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].rangeLen = jbig2HuffmanEOT;
+ huffDecoder->buildTable(symCodeTab, numSyms);
+ huffDecoder->reset();
+
+ // set up the arithmetic decoder
+ } else {
+ symCodeTab = NULL;
+ resetIntStats(symCodeLen);
+ if (refine) {
+ resetRefinementStats(templ, NULL);
+ }
+ arithDecoder->start();
+ }
+
+ 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,
+ Guint 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 *= -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);
+ }
+
+ // 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] = -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;
+ }
+ 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 *)gmalloc(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;
+ 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 *)gmalloc((w + 2) * sizeof(int));
+ codingLine = (int *)gmalloc((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);
+ }
+ 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;
+ }
+ }
+
+ // set up the context
+ switch (templ) {
+ case 0:
+ cx0 = (bitmap->getPixel(0, y-2) << 1) |
+ bitmap->getPixel(1, y-2);
+ cx1 = (bitmap->getPixel(0, y-1) << 2) |
+ (bitmap->getPixel(1, y-1) << 1) |
+ bitmap->getPixel(2, y-1);
+ cx2 = 0;
+ break;
+ case 1:
+ cx0 = (bitmap->getPixel(0, y-2) << 2) |
+ (bitmap->getPixel(1, y-2) << 1) |
+ bitmap->getPixel(2, y-2);
+ cx1 = (bitmap->getPixel(0, y-1) << 2) |
+ (bitmap->getPixel(1, y-1) << 1) |
+ bitmap->getPixel(2, y-1);
+ cx2 = 0;
+ break;
+ case 2:
+ cx0 = (bitmap->getPixel(0, y-2) << 1) |
+ bitmap->getPixel(1, y-2);
+ cx1 = (bitmap->getPixel(0, y-1) << 1) |
+ bitmap->getPixel(1, y-1);
+ cx2 = 0;
+ break;
+ case 3:
+ cx1 = (bitmap->getPixel(0, y-1) << 1) |
+ bitmap->getPixel(1, y-1);
+ cx2 = 0;
+ break;
+ }
+
+ // decode the row
+ for (x = 0; x < w; ++x) {
+
+ // check for a skipped pixel
+ if (useSkip && skip->getPixel(x, y)) {
+ pix = 0;
+
+ } else {
+
+ // build the context
+ switch (templ) {
+ case 0:
+ cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) |
+ (bitmap->getPixel(x + atx[0], y + aty[0]) << 3) |
+ (bitmap->getPixel(x + atx[1], y + aty[1]) << 2) |
+ (bitmap->getPixel(x + atx[2], y + aty[2]) << 1) |
+ bitmap->getPixel(x + atx[3], y + aty[3]);
+ break;
+ case 1:
+ cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) |
+ bitmap->getPixel(x + atx[0], y + aty[0]);
+ break;
+ case 2:
+ cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) |
+ bitmap->getPixel(x + atx[0], y + aty[0]);
+ break;
+ case 3:
+ cx = (cx1 << 5) | (cx2 << 1) |
+ bitmap->getPixel(x + atx[0], y + aty[0]);
+ break;
+ }
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ bitmap->setPixel(x, y);
+ }
+ }
+
+ // update the context
+ switch (templ) {
+ case 0:
+ cx0 = ((cx0 << 1) | bitmap->getPixel(x+2, y-2)) & 0x07;
+ cx1 = ((cx1 << 1) | bitmap->getPixel(x+3, y-1)) & 0x1f;
+ cx2 = ((cx2 << 1) | pix) & 0x0f;
+ break;
+ case 1:
+ cx0 = ((cx0 << 1) | bitmap->getPixel(x+3, y-2)) & 0x0f;
+ cx1 = ((cx1 << 1) | bitmap->getPixel(x+3, y-1)) & 0x1f;
+ cx2 = ((cx2 << 1) | pix) & 0x07;
+ break;
+ case 2:
+ cx0 = ((cx0 << 1) | bitmap->getPixel(x+2, y-2)) & 0x07;
+ cx1 = ((cx1 << 1) | bitmap->getPixel(x+2, y-1)) & 0x0f;
+ cx2 = ((cx2 << 1) | pix) & 0x03;
+ break;
+ case 3:
+ cx1 = ((cx1 << 1) | bitmap->getPixel(x+2, y-1)) & 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;
+ int x, y, pix;
+
+ 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) {
+
+ // set up the context
+ if (templ) {
+ cx0 = bitmap->getPixel(0, y-1);
+ cx2 = 0; // unused
+ cx3 = (refBitmap->getPixel(-1-refDX, y-refDY) << 1) |
+ refBitmap->getPixel(-refDX, y-refDY);
+ cx4 = refBitmap->getPixel(-refDX, y+1-refDY);
+ } else {
+ cx0 = bitmap->getPixel(0, y-1);
+ cx2 = refBitmap->getPixel(-refDX, y-1-refDY);
+ cx3 = (refBitmap->getPixel(-1-refDX, y-refDY) << 1) |
+ refBitmap->getPixel(-refDX, y-refDY);
+ cx4 = (refBitmap->getPixel(-1-refDX, y+1-refDY) << 1) |
+ refBitmap->getPixel(-refDX, y+1-refDY);
+ }
+
+ // set up the typical prediction context
+ tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy
+ if (tpgrOn) {
+ tpgrCX0 = (refBitmap->getPixel(-1-refDX, y-1-refDY) << 2) |
+ (refBitmap->getPixel(-refDX, y-1-refDY) << 1) |
+ refBitmap->getPixel(1-refDX, y-1-refDY);
+ tpgrCX1 = (refBitmap->getPixel(-1-refDX, y-refDY) << 2) |
+ (refBitmap->getPixel(-refDX, y-refDY) << 1) |
+ refBitmap->getPixel(1-refDX, y-refDY);
+ tpgrCX2 = (refBitmap->getPixel(-1-refDX, y+1-refDY) << 2) |
+ (refBitmap->getPixel(-refDX, y+1-refDY) << 1) |
+ refBitmap->getPixel(1-refDX, y+1-refDY);
+ }
+
+ for (x = 0; x < w; ++x) {
+
+ // update the context
+ if (templ) {
+ cx0 = ((cx0 << 1) | bitmap->getPixel(x+1, y-1)) & 7;
+ cx3 = ((cx3 << 1) | refBitmap->getPixel(x+1-refDX, y-refDY)) & 7;
+ cx4 = ((cx4 << 1) | refBitmap->getPixel(x+1-refDX, y+1-refDY)) & 3;
+ } else {
+ cx0 = ((cx0 << 1) | bitmap->getPixel(x+1, y-1)) & 3;
+ cx2 = ((cx2 << 1) | refBitmap->getPixel(x+1-refDX, y-1-refDY)) & 3;
+ cx3 = ((cx3 << 1) | refBitmap->getPixel(x+1-refDX, y-refDY)) & 7;
+ cx4 = ((cx4 << 1) | refBitmap->getPixel(x+1-refDX, y+1-refDY)) & 7;
+ }
+
+ if (tpgrOn) {
+ // update the typical predictor context
+ tpgrCX0 = ((tpgrCX0 << 1) |
+ refBitmap->getPixel(x+1-refDX, y-1-refDY)) & 7;
+ tpgrCX1 = ((tpgrCX1 << 1) |
+ refBitmap->getPixel(x+1-refDX, y-refDY)) & 7;
+ tpgrCX2 = ((tpgrCX2 << 1) |
+ refBitmap->getPixel(x+1-refDX, y+1-refDY)) & 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
+ if (templ) {
+ cx = (cx0 << 7) | (bitmap->getPixel(x-1, y) << 6) |
+ (refBitmap->getPixel(x-refDX, y-1-refDY) << 5) |
+ (cx3 << 2) | cx4;
+ } else {
+ cx = (cx0 << 11) | (bitmap->getPixel(x-1, y) << 10) |
+ (cx2 << 8) | (cx3 << 5) | (cx4 << 2) |
+ (bitmap->getPixel(x+atx[0], y+aty[0]) << 1) |
+ refBitmap->getPixel(x+atx[1]-refDX, y+aty[1]-refDY);
+ }
+
+ // 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;
+ rangeBits = (flags >> 4) & 7;
+
+ huffDecoder->reset();
+ huffTabSize = 8;
+ huffTab = (JBIG2HuffmanTable *)
+ gmalloc(huffTabSize * sizeof(JBIG2HuffmanTable));
+ i = 0;
+ val = lowVal;
+ while (val < highVal) {
+ if (i == huffTabSize) {
+ huffTabSize *= 2;
+ huffTab = (JBIG2HuffmanTable *)
+ grealloc(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 *)
+ grealloc(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;
+ ++i;
+ 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) {
+ globalSegments->del(i);
+ return;
+ }
+ }
+}
+
+void JBIG2Stream::resetGenericStats(Guint templ,
+ JBIG2ArithmeticDecoderStats *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 JBIG2ArithmeticDecoderStats(size);
+ }
+ }
+}
+
+void JBIG2Stream::resetRefinementStats(
+ Guint templ,
+ JBIG2ArithmeticDecoderStats *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 JBIG2ArithmeticDecoderStats(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 JBIG2ArithmeticDecoderStats(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 - 0xffffffff;
+ }
+ return gTrue;
+}
diff --git a/pdf/xpdf/JBIG2Stream.h b/pdf/xpdf/JBIG2Stream.h
new file mode 100644
index 0000000..e15c3ac
--- /dev/null
+++ b/pdf/xpdf/JBIG2Stream.h
@@ -0,0 +1,143 @@
+//========================================================================
+//
+// JBIG2Stream.h
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef JBIG2STREAM_H
+#define JBIG2STREAM_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+#include "Stream.h"
+
+class GList;
+class JBIG2Segment;
+class JBIG2Bitmap;
+class JBIG2ArithmeticDecoder;
+class JBIG2ArithmeticDecoderStats;
+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(char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ void readSegments();
+ void 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,
+ Guint 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,
+ JBIG2ArithmeticDecoderStats *prevStats);
+ void resetRefinementStats(Guint templ,
+ JBIG2ArithmeticDecoderStats *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;
+
+ JBIG2ArithmeticDecoder *arithDecoder;
+ JBIG2ArithmeticDecoderStats *genericRegionStats;
+ JBIG2ArithmeticDecoderStats *refinementRegionStats;
+ JBIG2ArithmeticDecoderStats *iadhStats;
+ JBIG2ArithmeticDecoderStats *iadwStats;
+ JBIG2ArithmeticDecoderStats *iaexStats;
+ JBIG2ArithmeticDecoderStats *iaaiStats;
+ JBIG2ArithmeticDecoderStats *iadtStats;
+ JBIG2ArithmeticDecoderStats *iaitStats;
+ JBIG2ArithmeticDecoderStats *iafsStats;
+ JBIG2ArithmeticDecoderStats *iadsStats;
+ JBIG2ArithmeticDecoderStats *iardxStats;
+ JBIG2ArithmeticDecoderStats *iardyStats;
+ JBIG2ArithmeticDecoderStats *iardwStats;
+ JBIG2ArithmeticDecoderStats *iardhStats;
+ JBIG2ArithmeticDecoderStats *iariStats;
+ JBIG2ArithmeticDecoderStats *iaidStats;
+ JBIG2HuffmanDecoder *huffDecoder;
+ JBIG2MMRDecoder *mmrDecoder;
+};
+
+#endif
diff --git a/pdf/xpdf/Outline.cc b/pdf/xpdf/Outline.cc
new file mode 100644
index 0000000..256d38d
--- /dev/null
+++ b/pdf/xpdf/Outline.cc
@@ -0,0 +1,140 @@
+//========================================================================
+//
+// Outline.cc
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "gmem.h"
+#include "GString.h"
+#include "GList.h"
+#include "Link.h"
+#include "PDFDocEncoding.h"
+#include "Outline.h"
+
+//------------------------------------------------------------------------
+
+Outline::Outline(Object *outlineObj, XRef *xref) {
+ Object first;
+
+ items = NULL;
+ if (!outlineObj->isDict()) {
+ return;
+ }
+ items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first),
+ xref);
+ first.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 *)gmalloc(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));
+ for (i = 0; i < titleLen; ++i) {
+ title[i] = pdfDocEncoding[s->getChar(i) & 0xff];
+ }
+ }
+ }
+ obj1.free();
+
+ if (!dict->lookup("Dest", &obj1)->isNull()) {
+ action = LinkAction::parseDest(&obj1);
+ } else {
+ obj1.free();
+ if (dict->lookup("A", &obj1)) {
+ action = LinkAction::parseAction(&obj1);
+ }
+ }
+ obj1.free();
+
+ dict->lookupNF("First", &firstRef);
+ 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) {
+ delete title;
+ }
+ if (action) {
+ delete action;
+ }
+ firstRef.free();
+ nextRef.free();
+}
+
+GList *OutlineItem::readItemList(Object *itemRef, XRef *xrefA) {
+ GList *items;
+ OutlineItem *item;
+ Object obj;
+ Object *p;
+
+ items = new GList();
+ p = itemRef;
+ while (p->isRef()) {
+ if (!p->fetch(xrefA, &obj)->isDict()) {
+ obj.free();
+ break;
+ }
+ item = new OutlineItem(obj.getDict(), xrefA);
+ obj.free();
+ items->append(item);
+ p = &item->nextRef;
+ }
+ return items;
+}
+
+void OutlineItem::open() {
+ if (!kids) {
+ kids = readItemList(&firstRef, xref);
+ }
+}
+
+void OutlineItem::close() {
+ if (kids) {
+ deleteGList(kids, OutlineItem);
+ kids = NULL;
+ }
+}
diff --git a/pdf/xpdf/Outline.h b/pdf/xpdf/Outline.h
new file mode 100644
index 0000000..dc79252
--- /dev/null
+++ b/pdf/xpdf/Outline.h
@@ -0,0 +1,74 @@
+//========================================================================
+//
+// Outline.h
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef OUTLINE_H
+#define OUTLINE_H
+
+#include <aconf.h>
+
+#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 *itemRef, 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 nextRef;
+ GBool startsOpen;
+ GList *kids; // NULL unless this item is open [OutlineItem]
+};
+
+#endif
diff --git a/pdf/xpdf/PDFDocEncoding.cc b/pdf/xpdf/PDFDocEncoding.cc
new file mode 100644
index 0000000..4f1e201
--- /dev/null
+++ b/pdf/xpdf/PDFDocEncoding.cc
@@ -0,0 +1,44 @@
+//========================================================================
+//
+// PDFDocEncoding.h
+//
+// Copyright 2002 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/pdf/xpdf/PDFDocEncoding.h b/pdf/xpdf/PDFDocEncoding.h
new file mode 100644
index 0000000..6fc157f
--- /dev/null
+++ b/pdf/xpdf/PDFDocEncoding.h
@@ -0,0 +1,16 @@
+//========================================================================
+//
+// PDFDocEncoding.h
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef PDFDOCENCODING_H
+#define PDFDOCENCODING_H
+
+#include "CharTypes.h"
+
+extern Unicode pdfDocEncoding[256];
+
+#endif
diff --git a/pdf/xpdf/XPDFApp.cc b/pdf/xpdf/XPDFApp.cc
new file mode 100644
index 0000000..e456310
--- /dev/null
+++ b/pdf/xpdf/XPDFApp.cc
@@ -0,0 +1,386 @@
+//========================================================================
+//
+// XPDFApp.cc
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "GString.h"
+#include "GList.h"
+#include "Error.h"
+#include "XPDFViewer.h"
+#include "XPDFApp.h"
+#include "config.h"
+
+// these macro defns conflict with xpdf's Object class
+#ifdef LESSTIF_VERSION
+#undef XtDisplay
+#undef XtScreen
+#undef XtWindow
+#undef XtParent
+#undef XtIsRealized
+#endif
+
+//------------------------------------------------------------------------
+
+#define remoteCmdSize 512
+
+//------------------------------------------------------------------------
+
+static String fallbackResources[] = {
+ "*XmTextField.fontList: -*-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1",
+ "*.fontList: -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1",
+ "*XmTextField.translations: #override\\n"
+ " Ctrl<Key>a:beginning-of-line()\\n"
+ " Ctrl<Key>b:backward-character()\\n"
+ " Ctrl<Key>d:delete-next-character()\\n"
+ " Ctrl<Key>e:end-of-line()\\n"
+ " Ctrl<Key>f:forward-character()\\n"
+ " Ctrl<Key>u:beginning-of-line()delete-to-end-of-line()\\n"
+ " Ctrl<Key>k:delete-to-end-of-line()\\n",
+ NULL
+};
+
+static XrmOptionDescRec xOpts[] = {
+ {"-display", ".display", XrmoptionSepArg, NULL},
+ {"-foreground", "*Foreground", XrmoptionSepArg, NULL},
+ {"-fg", "*Foreground", XrmoptionSepArg, NULL},
+ {"-background", "*Background", XrmoptionSepArg, NULL},
+ {"-bg", "*Background", XrmoptionSepArg, NULL},
+ {"-geometry", ".geometry", XrmoptionSepArg, NULL},
+ {"-g", ".geometry", XrmoptionSepArg, NULL},
+ {"-font", "*.fontList", XrmoptionSepArg, NULL},
+ {"-fn", "*.fontList", XrmoptionSepArg, NULL},
+ {"-title", ".title", XrmoptionSepArg, NULL},
+ {"-cmap", ".installCmap", XrmoptionNoArg, (XPointer)"on"},
+ {"-rgb", ".rgbCubeSize", XrmoptionSepArg, NULL},
+ {"-rv", ".reverseVideo", XrmoptionNoArg, (XPointer)"true"},
+ {"-papercolor", ".paperColor", XrmoptionSepArg, NULL},
+ {"-z", ".initialZoom", XrmoptionSepArg, NULL}
+};
+
+#define nXOpts (sizeof(xOpts) / sizeof(XrmOptionDescRec))
+
+struct XPDFAppResources {
+ String geometry;
+ String title;
+ Bool installCmap;
+ int rgbCubeSize;
+ Bool reverseVideo;
+ String paperColor;
+ String initialZoom;
+ Bool viKeys;
+};
+
+static Bool defInstallCmap = False;
+static int defRGBCubeSize = defaultRGBCube;
+static Bool defReverseVideo = False;
+static Bool defViKeys = False;
+
+static XtResource xResources[] = {
+ { "geometry", "Geometry", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, geometry), XtRString, (XtPointer)NULL },
+ { "title", "Title", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, title), XtRString, (XtPointer)NULL },
+ { "installCmap", "InstallCmap", XtRBool, sizeof(Bool), XtOffsetOf(XPDFAppResources, installCmap), XtRBool, (XtPointer)&defInstallCmap },
+ { "rgbCubeSize", "RgbCubeSize", XtRInt, sizeof(int), XtOffsetOf(XPDFAppResources, rgbCubeSize), XtRInt, (XtPointer)&defRGBCubeSize },
+ { "reverseVideo", "ReverseVideo", XtRBool, sizeof(Bool), XtOffsetOf(XPDFAppResources, reverseVideo), XtRBool, (XtPointer)&defReverseVideo },
+ { "paperColor", "PaperColor", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, paperColor), XtRString, (XtPointer)NULL },
+ { "initialZoom", "InitialZoom", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, initialZoom), XtRString, (XtPointer)NULL },
+ { "viKeys", "ViKeys", XtRBool, sizeof(Bool), XtOffsetOf(XPDFAppResources, viKeys), XtRBool, (XtPointer)&defViKeys }
+};
+
+#define nXResources (sizeof(xResources) / sizeof(XtResource))
+
+//------------------------------------------------------------------------
+// XPDFApp
+//------------------------------------------------------------------------
+
+#if 0 //~ for debugging
+static int xErrorHandler(Display *display, XErrorEvent *ev) {
+ printf("X error:\n");
+ printf(" resource ID = %08lx\n", ev->resourceid);
+ printf(" serial = %lu\n", ev->serial);
+ printf(" error_code = %d\n", ev->error_code);
+ printf(" request_code = %d\n", ev->request_code);
+ printf(" minor_code = %d\n", ev->minor_code);
+ fflush(stdout);
+ abort();
+}
+#endif
+
+XPDFApp::XPDFApp(int *argc, char *argv[]) {
+ appShell = XtAppInitialize(&appContext, xpdfAppName, xOpts, nXOpts,
+ argc, argv, fallbackResources, NULL, 0);
+ display = XtDisplay(appShell);
+ screenNum = XScreenNumberOfScreen(XtScreen(appShell));
+#if XmVERSION > 1
+ XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
+ XmNenableButtonTab, True, NULL);
+#endif
+#if XmVERSION > 1
+ // Drag-and-drop appears to be buggy -- I'm seeing weird crashes
+ // deep in the Motif code when I destroy widgets in the XpdfForms
+ // code. Xpdf doesn't use it, so just turn it off.
+ XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)),
+ XmNdragInitiatorProtocolStyle, XmDRAG_NONE,
+ XmNdragReceiverProtocolStyle, XmDRAG_NONE,
+ NULL);
+#endif
+
+#if 0 //~ for debugging
+ XSynchronize(display, True);
+ XSetErrorHandler(&xErrorHandler);
+#endif
+
+ fullScreen = gFalse;
+ remoteAtom = None;
+ remoteViewer = NULL;
+ remoteWin = None;
+
+ getResources();
+
+ viewers = new GList();
+
+}
+
+void XPDFApp::getResources() {
+ XPDFAppResources resources;
+ XColor xcol, xcol2;
+ Colormap colormap;
+
+ XtGetApplicationResources(appShell, &resources, xResources, nXResources,
+ NULL, 0);
+ geometry = resources.geometry ? new GString(resources.geometry)
+ : (GString *)NULL;
+ title = resources.title ? new GString(resources.title) : (GString *)NULL;
+ installCmap = (GBool)resources.installCmap;
+ rgbCubeSize = resources.rgbCubeSize;
+ reverseVideo = (GBool)resources.reverseVideo;
+ paperColor = reverseVideo ? BlackPixel(display, screenNum) :
+ WhitePixel(display, screenNum);
+ if (resources.paperColor) {
+ XtVaGetValues(appShell, XmNcolormap, &colormap, NULL);
+ if (XAllocNamedColor(display, colormap, resources.paperColor,
+ &xcol, &xcol2)) {
+ paperColor = xcol.pixel;
+ } else {
+ error(-1, "Couldn't allocate color '%s'", resources.paperColor);
+ }
+ }
+ initialZoom = resources.initialZoom ? new GString(resources.initialZoom)
+ : (GString *)NULL;
+ viKeys = (GBool)resources.viKeys;
+}
+
+XPDFApp::~XPDFApp() {
+ deleteGList(viewers, XPDFViewer);
+ if (geometry) {
+ delete geometry;
+ }
+ if (title) {
+ delete title;
+ }
+ if (initialZoom) {
+ delete initialZoom;
+ }
+}
+
+XPDFViewer *XPDFApp::open(GString *fileName, int page,
+ GString *ownerPassword, GString *userPassword) {
+ XPDFViewer *viewer;
+
+ viewer = new XPDFViewer(this, fileName, page, NULL,
+ ownerPassword, userPassword);
+ if (!viewer->isOk()) {
+ delete viewer;
+ return NULL;
+ }
+ if (remoteAtom != None) {
+ remoteViewer = viewer;
+ remoteWin = viewer->getWindow();
+ XtAddEventHandler(remoteWin, PropertyChangeMask, False,
+ &remoteMsgCbk, this);
+ XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
+ }
+ viewers->append(viewer);
+ return viewer;
+}
+
+XPDFViewer *XPDFApp::openAtDest(GString *fileName, GString *dest,
+ GString *ownerPassword,
+ GString *userPassword) {
+ XPDFViewer *viewer;
+
+ viewer = new XPDFViewer(this, fileName, 1, dest,
+ ownerPassword, userPassword);
+ if (!viewer->isOk()) {
+ delete viewer;
+ return NULL;
+ }
+ if (remoteAtom != None) {
+ remoteViewer = viewer;
+ remoteWin = viewer->getWindow();
+ XtAddEventHandler(remoteWin, PropertyChangeMask, False,
+ &remoteMsgCbk, this);
+ XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime);
+ }
+ viewers->append(viewer);
+ return viewer;
+}
+
+void XPDFApp::close(XPDFViewer *viewer, GBool closeLast) {
+ int i;
+
+ if (viewers->getLength() == 1) {
+ if (viewer != (XPDFViewer *)viewers->get(0)) {
+ return;
+ }
+ if (closeLast) {
+ quit();
+ } else {
+ viewer->clear();
+ }
+ } else {
+ for (i = 0; i < viewers->getLength(); ++i) {
+ if (((XPDFViewer *)viewers->get(i)) == viewer) {
+ viewers->del(i);
+ if (remoteAtom != None && remoteViewer == viewer) {
+ remoteViewer = (XPDFViewer *)viewers->get(viewers->getLength() - 1);
+ remoteWin = remoteViewer->getWindow();
+ XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin),
+ CurrentTime);
+ }
+ delete viewer;
+ return;
+ }
+ }
+ }
+}
+
+void XPDFApp::quit() {
+ if (remoteAtom != None) {
+ XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
+ }
+ while (viewers->getLength() > 0) {
+ delete (XPDFViewer *)viewers->del(0);
+ }
+ XtAppSetExitFlag(appContext);
+}
+
+void XPDFApp::run() {
+ XtAppMainLoop(appContext);
+}
+
+void XPDFApp::setRemoteName(char *remoteName) {
+ remoteAtom = XInternAtom(display, remoteName, False);
+ remoteXWin = XGetSelectionOwner(display, remoteAtom);
+}
+
+GBool XPDFApp::remoteServerRunning() {
+ return remoteXWin != None;
+}
+
+void XPDFApp::remoteOpen(GString *fileName, int page, GBool raise) {
+ char cmd[remoteCmdSize];
+
+ sprintf(cmd, "%c %d %.200s",
+ raise ? 'D' : 'd', page, fileName->getCString());
+ XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
+ PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
+ XFlush(display);
+}
+
+void XPDFApp::remoteOpenAtDest(GString *fileName, GString *dest, GBool raise) {
+ char cmd[remoteCmdSize];
+
+ sprintf(cmd, "%c +%.256s %.200s",
+ raise ? 'D' : 'd', dest->getCString(), fileName->getCString());
+ XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
+ PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1);
+ XFlush(display);
+}
+
+void XPDFApp::remoteRaise() {
+ XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
+ PropModeReplace, (Guchar *)"r", 2);
+ XFlush(display);
+}
+
+void XPDFApp::remoteQuit() {
+ XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8,
+ PropModeReplace, (Guchar *)"q", 2);
+ XFlush(display);
+}
+
+void XPDFApp::remoteMsgCbk(Widget widget, XtPointer ptr,
+ XEvent *event, Boolean *cont) {
+ XPDFApp *app = (XPDFApp *)ptr;
+ char *cmd;
+ Atom type;
+ int format;
+ Gulong size, remain;
+ char *p, *q;
+ GString *fileName;
+ int page;
+ GString *destName;
+
+ if (event->xproperty.atom != app->remoteAtom) {
+ *cont = True;
+ return;
+ }
+ *cont = False;
+
+ // get command
+ if (XGetWindowProperty(app->display, XtWindow(app->remoteWin),
+ app->remoteAtom, 0, remoteCmdSize/4,
+ True, app->remoteAtom,
+ &type, &format, &size, &remain,
+ (Guchar **)&cmd) != Success) {
+ return;
+ }
+ if (size == 0) {
+ return;
+ }
+
+ // raise window
+ if (cmd[0] == 'D' || cmd[0] == 'r'){
+ XMapRaised(app->display, XtWindow(app->remoteWin));
+ XFlush(app->display);
+ }
+
+ // display file / page
+ if (cmd[0] == 'd' || cmd[0] == 'D') {
+ p = cmd + 2;
+ q = strchr(p, ' ');
+ if (!q) {
+ return;
+ }
+ *q++ = '\0';
+ page = 1;
+ destName = NULL;
+ if (*p == '+') {
+ destName = new GString(p + 1);
+ } else {
+ page = atoi(p);
+ }
+ if (q) {
+ fileName = new GString(q);
+ app->remoteViewer->open(fileName, page, destName);
+ delete fileName;
+ }
+ XFree((XPointer)cmd);
+ if (destName) {
+ delete destName;
+ }
+
+ // quit
+ } else if (cmd[0] == 'q') {
+ app->quit();
+ }
+}
diff --git a/pdf/xpdf/XPDFApp.h b/pdf/xpdf/XPDFApp.h
new file mode 100644
index 0000000..4875456
--- /dev/null
+++ b/pdf/xpdf/XPDFApp.h
@@ -0,0 +1,104 @@
+//========================================================================
+//
+// XPDFApp.h
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef XPDFAPP_H
+#define XPDFAPP_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#define Object XtObject
+#include <Xm/XmAll.h>
+#undef Object
+#include "gtypes.h"
+
+class GString;
+class GList;
+class XPDFViewer;
+
+//------------------------------------------------------------------------
+
+#define xpdfAppName "Xpdf"
+
+//------------------------------------------------------------------------
+// XPDFApp
+//------------------------------------------------------------------------
+
+class XPDFApp {
+public:
+
+ XPDFApp(int *argc, char *argv[]);
+ ~XPDFApp();
+
+ XPDFViewer *open(GString *fileName, int page = 1,
+ GString *ownerPassword = NULL,
+ GString *userPassword = NULL);
+ XPDFViewer *openAtDest(GString *fileName, GString *dest,
+ GString *ownerPassword = NULL,
+ GString *userPassword = NULL);
+ void close(XPDFViewer *viewer, GBool closeLast);
+ void quit();
+
+ void run();
+
+ //----- remote server
+ void setRemoteName(char *remoteName);
+ GBool remoteServerRunning();
+ void remoteOpen(GString *fileName, int page, GBool raise);
+ void remoteOpenAtDest(GString *fileName, GString *dest, GBool raise);
+ void remoteRaise();
+ void remoteQuit();
+
+ //----- resource/option values
+ GString *getGeometry() { return geometry; }
+ GString *getTitle() { return title; }
+ GBool getInstallCmap() { return installCmap; }
+ int getRGBCubeSize() { return rgbCubeSize; }
+ GBool getReverseVideo() { return reverseVideo; }
+ Gulong getPaperColor() { return paperColor; }
+ GString *getInitialZoom() { return initialZoom; }
+ GBool getViKeys() { return viKeys; }
+ void setFullScreen(GBool fullScreenA) { fullScreen = fullScreenA; }
+ GBool getFullScreen() { return fullScreen; }
+
+ XtAppContext getAppContext() { return appContext; }
+ Widget getAppShell() { return appShell; }
+
+private:
+
+ void getResources();
+ static void remoteMsgCbk(Widget widget, XtPointer ptr,
+ XEvent *event, Boolean *cont);
+
+ Display *display;
+ int screenNum;
+ XtAppContext appContext;
+ Widget appShell;
+ GList *viewers; // [XPDFViewer]
+
+ Atom remoteAtom;
+ Window remoteXWin;
+ XPDFViewer *remoteViewer;
+ Widget remoteWin;
+
+ //----- resource/option values
+ GString *geometry;
+ GString *title;
+ GBool installCmap;
+ int rgbCubeSize;
+ GBool reverseVideo;
+ Gulong paperColor;
+ GString *initialZoom;
+ GBool viKeys;
+ GBool fullScreen;
+};
+
+#endif
diff --git a/pdf/xpdf/XPDFCore.cc b/pdf/xpdf/XPDFCore.cc
new file mode 100644
index 0000000..8376ce9
--- /dev/null
+++ b/pdf/xpdf/XPDFCore.cc
@@ -0,0 +1,1913 @@
+//========================================================================
+//
+// XPDFCore.cc
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <X11/keysym.h>
+#include <X11/cursorfont.h>
+#include "gmem.h"
+#include "GString.h"
+#include "GList.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "PDFDoc.h"
+#include "ErrorCodes.h"
+#include "GfxState.h"
+#include "PSOutputDev.h"
+#include "TextOutputDev.h"
+#include "XPixmapOutputDev.h"
+#include "XPDFCore.h"
+
+// these macro defns conflict with xpdf's Object class
+#ifdef LESSTIF_VERSION
+#undef XtDisplay
+#undef XtScreen
+#undef XtWindow
+#undef XtParent
+#undef XtIsRealized
+#endif
+
+// hack around old X includes which are missing these symbols
+#ifndef XK_Page_Up
+#define XK_Page_Up 0xFF55
+#endif
+#ifndef XK_Page_Down
+#define XK_Page_Down 0xFF56
+#endif
+#ifndef XK_KP_Home
+#define XK_KP_Home 0xFF95
+#endif
+#ifndef XK_KP_Left
+#define XK_KP_Left 0xFF96
+#endif
+#ifndef XK_KP_Up
+#define XK_KP_Up 0xFF97
+#endif
+#ifndef XK_KP_Right
+#define XK_KP_Right 0xFF98
+#endif
+#ifndef XK_KP_Down
+#define XK_KP_Down 0xFF99
+#endif
+#ifndef XK_KP_Prior
+#define XK_KP_Prior 0xFF9A
+#endif
+#ifndef XK_KP_Page_Up
+#define XK_KP_Page_Up 0xFF9A
+#endif
+#ifndef XK_KP_Next
+#define XK_KP_Next 0xFF9B
+#endif
+#ifndef XK_KP_Page_Down
+#define XK_KP_Page_Down 0xFF9B
+#endif
+#ifndef XK_KP_End
+#define XK_KP_End 0xFF9C
+#endif
+#ifndef XK_KP_Begin
+#define XK_KP_Begin 0xFF9D
+#endif
+#ifndef XK_KP_Insert
+#define XK_KP_Insert 0xFF9E
+#endif
+#ifndef XK_KP_Delete
+#define XK_KP_Delete 0xFF9F
+#endif
+
+//------------------------------------------------------------------------
+
+#define highlightNone 0
+#define highlightNormal 1
+#define highlightSelected 2
+
+//------------------------------------------------------------------------
+
+static int zoomDPI[maxZoom - minZoom + 1] = {
+ 29, 35, 42, 50, 60,
+ 72,
+ 86, 104, 124, 149, 179
+};
+
+//------------------------------------------------------------------------
+
+GString *XPDFCore::currentSelection = NULL;
+XPDFCore *XPDFCore::currentSelectionOwner = NULL;
+
+//------------------------------------------------------------------------
+// XPDFCore
+//------------------------------------------------------------------------
+
+XPDFCore::XPDFCore(Widget shellA, Widget parentWidgetA,
+ Gulong paperColorA, GBool fullScreenA, GBool reverseVideo,
+ GBool installCmap, int rgbCubeSize) {
+ GString *initialZoom;
+ int i;
+
+ shell = shellA;
+ parentWidget = parentWidgetA;
+ display = XtDisplay(parentWidget);
+ screenNum = XScreenNumberOfScreen(XtScreen(parentWidget));
+
+ paperColor = paperColorA;
+ fullScreen = fullScreenA;
+
+ // for some reason, querying XmNvisual doesn't work (even if done
+ // after the window is mapped)
+ visual = DefaultVisual(display, screenNum);
+ XtVaGetValues(shell, XmNcolormap, &colormap, NULL);
+
+ scrolledWin = NULL;
+ hScrollBar = NULL;
+ vScrollBar = NULL;
+ drawAreaFrame = NULL;
+ drawArea = NULL;
+ out = NULL;
+
+ doc = NULL;
+ page = 0;
+ rotate = 0;
+
+ // get the initial zoom value
+ initialZoom = globalParams->getInitialZoom();
+ if (!initialZoom->cmp("page")) {
+ zoom = zoomPage;
+ } else if (!initialZoom->cmp("width")) {
+ zoom = zoomWidth;
+ } else {
+ zoom = atoi(initialZoom->getCString());
+ if (zoom < minZoom) {
+ zoom = minZoom;
+ } else if (zoom > maxZoom) {
+ zoom = maxZoom;
+ }
+ }
+
+ scrollX = 0;
+ scrollY = 0;
+ linkAction = NULL;
+ selectXMin = selectXMax = 0;
+ selectYMin = selectYMax = 0;
+ dragging = gFalse;
+ lastDragLeft = lastDragTop = gTrue;
+
+ panning = gFalse;
+
+
+ updateCbk = NULL;
+ actionCbk = NULL;
+ keyPressCbk = NULL;
+ mouseCbk = NULL;
+ reqPasswordCbk = NULL;
+
+ // no history yet
+ historyCur = xpdfHistorySize - 1;
+ historyBLen = historyFLen = 0;
+ for (i = 0; i < xpdfHistorySize; ++i) {
+ history[i].fileName = NULL;
+ }
+
+ // optional features default to on
+ hyperlinksEnabled = gTrue;
+ selectEnabled = gTrue;
+
+ // do X-specific initialization and create the widgets
+ initWindow();
+
+ // create the OutputDev
+ out = new XPixmapOutputDev(display, screenNum, visual, colormap,
+ reverseVideo, paperColor,
+ installCmap, rgbCubeSize, gTrue,
+ &outputDevRedrawCbk, this);
+ out->startDoc(NULL);
+}
+
+XPDFCore::~XPDFCore() {
+ int i;
+
+ if (out) {
+ delete out;
+ }
+ if (doc) {
+ delete doc;
+ }
+ if (currentSelectionOwner == this && currentSelection) {
+ delete currentSelection;
+ currentSelection = NULL;
+ currentSelectionOwner = NULL;
+ }
+ for (i = 0; i < xpdfHistorySize; ++i) {
+ if (history[i].fileName) {
+ delete history[i].fileName;
+ }
+ }
+ if (selectGC) {
+ XFreeGC(display, selectGC);
+ XFreeGC(display, highlightGC);
+ }
+ if (drawAreaGC) {
+ XFreeGC(display, drawAreaGC);
+ }
+ if (drawArea) {
+ XtDestroyWidget(drawArea);
+ }
+ if (drawAreaFrame) {
+ XtDestroyWidget(drawAreaFrame);
+ }
+ if (vScrollBar) {
+ XtDestroyWidget(vScrollBar);
+ }
+ if (hScrollBar) {
+ XtDestroyWidget(hScrollBar);
+ }
+ if (scrolledWin) {
+ XtDestroyWidget(scrolledWin);
+ }
+ if (busyCursor) {
+ XFreeCursor(display, busyCursor);
+ }
+ if (linkCursor) {
+ XFreeCursor(display, linkCursor);
+ }
+ if (selectCursor) {
+ XFreeCursor(display, selectCursor);
+ }
+}
+
+//------------------------------------------------------------------------
+// loadFile / displayPage / displayDest
+//------------------------------------------------------------------------
+
+int XPDFCore::loadFile(GString *fileName, GString *ownerPassword,
+ GString *userPassword) {
+ PDFDoc *newDoc;
+ GString *password;
+ GBool again;
+ int err;
+
+ // busy cursor
+ setCursor(busyCursor);
+
+ // open the PDF file
+ newDoc = new PDFDoc(fileName->copy(), ownerPassword, userPassword);
+ if (!newDoc->isOk()) {
+ err = newDoc->getErrorCode();
+ delete newDoc;
+ if (err != errEncrypted || !reqPasswordCbk) {
+ setCursor(None);
+ return err;
+ }
+
+ // try requesting a password
+ again = ownerPassword != NULL || userPassword != NULL;
+ while (1) {
+ if (!(password = (*reqPasswordCbk)(reqPasswordCbkData, again))) {
+ setCursor(None);
+ return errEncrypted;
+ }
+ newDoc = new PDFDoc(fileName->copy(), password, password);
+ if (newDoc->isOk()) {
+ break;
+ }
+ err = newDoc->getErrorCode();
+ delete newDoc;
+ if (err != errEncrypted) {
+ setCursor(None);
+ return err;
+ }
+ again = gTrue;
+ }
+ }
+
+ // replace old document
+ if (doc) {
+ delete doc;
+ }
+ doc = newDoc;
+ if (out) {
+ out->startDoc(doc->getXRef());
+ }
+
+ // nothing displayed yet
+ page = -99;
+
+ // save the modification time
+ modTime = getModTime(doc->getFileName()->getCString());
+
+ // update the parent window
+ if (updateCbk) {
+ (*updateCbk)(updateCbkData, doc->getFileName(), -1,
+ doc->getNumPages(), NULL);
+ }
+
+ // back to regular cursor
+ setCursor(None);
+
+ return errNone;
+}
+
+void XPDFCore::resizeToPage(int pg) {
+ Dimension width, height;
+ double width1, height1;
+ Dimension topW, topH, topBorder, daW, daH;
+ Dimension displayW, displayH;
+
+ displayW = DisplayWidth(display, screenNum);
+ displayH = DisplayHeight(display, screenNum);
+ if (fullScreen) {
+ width = displayW;
+ height = displayH;
+ } else {
+ if (pg < 0 || pg > doc->getNumPages()) {
+ width1 = 612;
+ height1 = 792;
+ } else if (doc->getPageRotate(pg) == 90 ||
+ doc->getPageRotate(pg) == 270) {
+ width1 = doc->getPageHeight(pg);
+ height1 = doc->getPageWidth(pg);
+ } else {
+ width1 = doc->getPageWidth(pg);
+ height1 = doc->getPageHeight(pg);
+ }
+ if (zoom == zoomPage || zoom == zoomWidth) {
+ width = (Dimension)((width1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5);
+ height = (Dimension)((height1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5);
+ } else {
+ width = (Dimension)((width1 * zoomDPI[zoom - minZoom]) / 72 + 0.5);
+ height = (Dimension)((height1 * zoomDPI[zoom - minZoom]) / 72 + 0.5);
+ }
+ if (width > displayW - 100) {
+ width = displayW - 100;
+ }
+ if (height > displayH - 150) {
+ height = displayH - 150;
+ }
+ }
+
+ if (XtIsRealized(shell)) {
+ XtVaGetValues(shell, XmNwidth, &topW, XmNheight, &topH,
+ XmNborderWidth, &topBorder, NULL);
+ XtVaGetValues(drawArea, XmNwidth, &daW, XmNheight, &daH, NULL);
+ XtVaSetValues(shell, XmNwidth, width + (topW - daW),
+ XmNheight, height + (topH - daH), NULL);
+ } else {
+ XtVaSetValues(drawArea, XmNwidth, width, XmNheight, height, NULL);
+ }
+}
+
+void XPDFCore::clear() {
+ if (!doc) {
+ return;
+ }
+
+ // no document
+ delete doc;
+ doc = NULL;
+ out->clear();
+
+ // no page displayed
+ page = -99;
+
+ // redraw
+ scrollX = scrollY = 0;
+ updateScrollBars();
+ redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
+}
+
+void XPDFCore::displayPage(int pageA, int zoomA, int rotateA,
+ GBool scrollToTop, GBool addToHist) {
+ double hDPI, vDPI;
+ int rot;
+ XPDFHistory *h;
+ GBool newZoom;
+ XGCValues gcValues;
+ time_t newModTime;
+ int oldScrollX, oldScrollY;
+
+ // update the zoom and rotate values
+ newZoom = zoomA != zoom;
+ zoom = zoomA;
+ rotate = rotateA;
+
+ // check for document and valid page number
+ if (!doc || pageA <= 0 || pageA > doc->getNumPages()) {
+ return;
+ }
+
+ // busy cursor
+ setCursor(busyCursor);
+
+
+ // check for changes to the file
+ newModTime = getModTime(doc->getFileName()->getCString());
+ if (newModTime != modTime) {
+ if (loadFile(doc->getFileName()) == errNone) {
+ if (pageA > doc->getNumPages()) {
+ pageA = doc->getNumPages();
+ }
+ }
+ modTime = newModTime;
+ }
+
+ // free the old GCs
+ if (selectGC) {
+ XFreeGC(display, selectGC);
+ XFreeGC(display, highlightGC);
+ }
+
+ // new page number
+ page = pageA;
+
+ // scroll to top
+ if (scrollToTop) {
+ scrollY = 0;
+ }
+
+ // if zoom level changed, scroll to the top-left corner
+ if (newZoom) {
+ scrollX = scrollY = 0;
+ }
+
+ // initialize mouse-related stuff
+ linkAction = NULL;
+ selectXMin = selectXMax = 0;
+ selectYMin = selectYMax = 0;
+ dragging = gFalse;
+ lastDragLeft = lastDragTop = gTrue;
+
+ // draw the page
+ rot = rotate + doc->getPageRotate(page);
+ if (rot >= 360) {
+ rot -= 360;
+ } else if (rotate < 0) {
+ rot += 360;
+ }
+ if (zoom == zoomPage) {
+ if (rot == 90 || rot == 270) {
+ hDPI = (drawAreaWidth / doc->getPageHeight(page)) * 72;
+ vDPI = (drawAreaHeight / doc->getPageWidth(page)) * 72;
+ } else {
+ hDPI = (drawAreaWidth / doc->getPageWidth(page)) * 72;
+ vDPI = (drawAreaHeight / doc->getPageHeight(page)) * 72;
+ }
+ dpi = (hDPI < vDPI) ? hDPI : vDPI;
+ } else if (zoom == zoomWidth) {
+ if (rot == 90 || rot == 270) {
+ dpi = (drawAreaWidth / doc->getPageHeight(page)) * 72;
+ } else {
+ dpi = (drawAreaWidth / doc->getPageWidth(page)) * 72;
+ }
+ } else {
+ dpi = zoomDPI[zoom - minZoom];
+ }
+ out->setWindow(XtWindow(drawArea));
+ doc->displayPage(out, page, dpi, rotate, gTrue);
+ oldScrollX = scrollX;
+ oldScrollY = scrollY;
+ updateScrollBars();
+ if (scrollX != oldScrollX || scrollY != oldScrollY) {
+ redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
+ }
+
+
+ // add to history
+ if (addToHist) {
+ if (++historyCur == xpdfHistorySize) {
+ historyCur = 0;
+ }
+ h = &history[historyCur];
+ if (h->fileName) {
+ delete h->fileName;
+ }
+ h->fileName = doc->getFileName()->copy();
+ h->page = page;
+ if (historyBLen < xpdfHistorySize) {
+ ++historyBLen;
+ }
+ historyFLen = 0;
+ }
+
+ // update the parent window
+ if (updateCbk) {
+ (*updateCbk)(updateCbkData, NULL, page, -1, "");
+ }
+
+ // allocate new GCs
+ gcValues.foreground = BlackPixel(display, screenNum) ^
+ WhitePixel(display, screenNum);
+ gcValues.function = GXxor;
+ selectGC = XCreateGC(display, out->getPixmap(),
+ GCForeground | GCFunction, &gcValues);
+ highlightGC = XCreateGC(display, out->getPixmap(),
+ GCForeground | GCFunction, &gcValues);
+
+ // back to regular cursor
+ setCursor(None);
+}
+
+void XPDFCore::displayDest(LinkDest *dest, int zoomA, int rotateA,
+ GBool addToHist) {
+ Ref pageRef;
+ int pg;
+ int dx, dy;
+
+ if (dest->isPageRef()) {
+ pageRef = dest->getPageRef();
+ pg = doc->findPage(pageRef.num, pageRef.gen);
+ } else {
+ pg = dest->getPageNum();
+ }
+ if (pg <= 0 || pg > doc->getNumPages()) {
+ pg = 1;
+ }
+ if (pg != page) {
+ displayPage(pg, zoomA, rotateA, gTrue, addToHist);
+ }
+
+ if (fullScreen) {
+ return;
+ }
+ switch (dest->getKind()) {
+ case destXYZ:
+ out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
+ if (dest->getChangeLeft() || dest->getChangeTop()) {
+ scrollTo(dest->getChangeLeft() ? dx : scrollX,
+ dest->getChangeTop() ? dy : scrollY);
+ }
+ //~ what is the zoom parameter?
+ break;
+ case destFit:
+ case destFitB:
+ //~ do fit
+ scrollTo(0, 0);
+ break;
+ case destFitH:
+ case destFitBH:
+ //~ do fit
+ out->cvtUserToDev(0, dest->getTop(), &dx, &dy);
+ scrollTo(0, dy);
+ break;
+ case destFitV:
+ case destFitBV:
+ //~ do fit
+ out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy);
+ scrollTo(dx, 0);
+ break;
+ case destFitR:
+ //~ do fit
+ out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
+ scrollTo(dx, dy);
+ break;
+ }
+}
+
+//------------------------------------------------------------------------
+// page/position changes
+//------------------------------------------------------------------------
+
+void XPDFCore::gotoNextPage(int inc, GBool top) {
+ int pg;
+
+ if (!doc || doc->getNumPages() == 0) {
+ return;
+ }
+ if (page < doc->getNumPages()) {
+ if ((pg = page + inc) > doc->getNumPages()) {
+ pg = doc->getNumPages();
+ }
+ displayPage(pg, zoom, rotate, top, gTrue);
+ } else {
+ XBell(display, 0);
+ }
+}
+
+void XPDFCore::gotoPrevPage(int dec, GBool top, GBool bottom) {
+ int pg;
+
+ if (!doc || doc->getNumPages() == 0) {
+ return;
+ }
+ if (page > 1) {
+ if (!fullScreen && bottom) {
+ scrollY = out->getPixmapHeight() - drawAreaHeight;
+ if (scrollY < 0) {
+ scrollY = 0;
+ }
+ // displayPage will call updateScrollBars()
+ }
+ if ((pg = page - dec) < 1) {
+ pg = 1;
+ }
+ displayPage(pg, zoom, rotate, top, gTrue);
+ } else {
+ XBell(display, 0);
+ }
+}
+
+void XPDFCore::goForward() {
+ if (historyFLen == 0) {
+ XBell(display, 0);
+ return;
+ }
+ if (++historyCur == xpdfHistorySize) {
+ historyCur = 0;
+ }
+ --historyFLen;
+ ++historyBLen;
+ if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
+ if (loadFile(history[historyCur].fileName) != errNone) {
+ XBell(display, 0);
+ return;
+ }
+ }
+ displayPage(history[historyCur].page, zoom, rotate, gFalse, gFalse);
+}
+
+void XPDFCore::goBackward() {
+ if (historyBLen <= 1) {
+ XBell(display, 0);
+ return;
+ }
+ if (--historyCur < 0) {
+ historyCur = xpdfHistorySize - 1;
+ }
+ --historyBLen;
+ ++historyFLen;
+ if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
+ if (loadFile(history[historyCur].fileName) != errNone) {
+ XBell(display, 0);
+ return;
+ }
+ }
+ displayPage(history[historyCur].page, zoom, rotate, gFalse, gFalse);
+}
+
+void XPDFCore::scrollLeft(int nCols) {
+ scrollTo(scrollX - nCols * 16, scrollY);
+}
+
+void XPDFCore::scrollRight(int nCols) {
+ scrollTo(scrollX + nCols * 16, scrollY);
+}
+
+void XPDFCore::scrollUp(int nLines) {
+ scrollTo(scrollX, scrollY - nLines * 16);
+}
+
+void XPDFCore::scrollDown(int nLines) {
+ scrollTo(scrollX, scrollY + nLines * 16);
+}
+
+void XPDFCore::scrollPageUp() {
+ if (scrollY == 0) {
+ gotoPrevPage(1, gFalse, gTrue);
+ } else {
+ scrollTo(scrollX, scrollY - drawAreaHeight);
+ }
+}
+
+void XPDFCore::scrollPageDown() {
+ if (scrollY >= out->getPixmapHeight() - drawAreaHeight) {
+ gotoNextPage(1, gTrue);
+ } else {
+ scrollTo(scrollX, scrollY + drawAreaHeight);
+ }
+}
+
+void XPDFCore::scrollTo(int x, int y) {
+ GBool needRedraw;
+ int maxPos, pos;
+
+ needRedraw = gFalse;
+
+ maxPos = out ? out->getPixmapWidth() : 1;
+ if (maxPos < drawAreaWidth) {
+ maxPos = drawAreaWidth;
+ }
+ if (x < 0) {
+ pos = 0;
+ } else if (x > maxPos - drawAreaWidth) {
+ pos = maxPos - drawAreaWidth;
+ } else {
+ pos = x;
+ }
+ if (scrollX != pos) {
+ scrollX = pos;
+ XmScrollBarSetValues(hScrollBar, scrollX, drawAreaWidth, 16,
+ drawAreaWidth, False);
+ needRedraw = gTrue;
+ }
+
+ maxPos = out ? out->getPixmapHeight() : 1;
+ if (maxPos < drawAreaHeight) {
+ maxPos = drawAreaHeight;
+ }
+ if (y < 0) {
+ pos = 0;
+ } else if (y > maxPos - drawAreaHeight) {
+ pos = maxPos - drawAreaHeight;
+ } else {
+ pos = y;
+ }
+ if (scrollY != pos) {
+ scrollY = pos;
+ XmScrollBarSetValues(vScrollBar, scrollY, drawAreaHeight, 16,
+ drawAreaHeight, False);
+ needRedraw = gTrue;
+ }
+
+ if (needRedraw) {
+ redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
+ }
+}
+
+//------------------------------------------------------------------------
+// selection
+//------------------------------------------------------------------------
+
+void XPDFCore::setSelection(int newXMin, int newYMin,
+ int newXMax, int newYMax) {
+ Pixmap pixmap;
+ int x, y;
+ GBool needRedraw, needScroll;
+ GBool moveLeft, moveRight, moveTop, moveBottom;
+
+ pixmap = out->getPixmap();
+
+
+ // erase old selection on off-screen bitmap
+ needRedraw = gFalse;
+ if (selectXMin < selectXMax && selectYMin < selectYMax) {
+ XFillRectangle(display, pixmap,
+ selectGC, selectXMin, selectYMin,
+ selectXMax - selectXMin, selectYMax - selectYMin);
+ needRedraw = gTrue;
+ }
+
+ // draw new selection on off-screen bitmap
+ if (newXMin < newXMax && newYMin < newYMax) {
+ XFillRectangle(display, pixmap,
+ selectGC, newXMin, newYMin,
+ newXMax - newXMin, newYMax - newYMin);
+ needRedraw = gTrue;
+ }
+
+ // check which edges moved
+ moveLeft = newXMin != selectXMin;
+ moveTop = newYMin != selectYMin;
+ moveRight = newXMax != selectXMax;
+ moveBottom = newYMax != selectYMax;
+
+ // redraw currently visible part of bitmap
+ if (needRedraw) {
+ if (moveLeft) {
+ redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin,
+ (newYMin < selectYMin) ? newYMin : selectYMin,
+ (newXMin > selectXMin) ? newXMin : selectXMin,
+ (newYMax > selectYMax) ? newYMax : selectYMax);
+ }
+ if (moveRight) {
+ redrawRectangle((newXMax < selectXMax) ? newXMax : selectXMax,
+ (newYMin < selectYMin) ? newYMin : selectYMin,
+ (newXMax > selectXMax) ? newXMax : selectXMax,
+ (newYMax > selectYMax) ? newYMax : selectYMax);
+ }
+ if (moveTop) {
+ redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin,
+ (newYMin < selectYMin) ? newYMin : selectYMin,
+ (newXMax > selectXMax) ? newXMax : selectXMax,
+ (newYMin > selectYMin) ? newYMin : selectYMin);
+ }
+ if (moveBottom) {
+ redrawRectangle((newXMin < selectXMin) ? newXMin : selectXMin,
+ (newYMax < selectYMax) ? newYMax : selectYMax,
+ (newXMax > selectXMax) ? newXMax : selectXMax,
+ (newYMax > selectYMax) ? newYMax : selectYMax);
+ }
+ }
+
+ // switch to new selection coords
+ selectXMin = newXMin;
+ selectXMax = newXMax;
+ selectYMin = newYMin;
+ selectYMax = newYMax;
+
+ // scroll if necessary
+ if (fullScreen) {
+ return;
+ }
+ needScroll = gFalse;
+ x = scrollX;
+ y = scrollY;
+ if (moveLeft && selectXMin < x) {
+ x = selectXMin;
+ needScroll = gTrue;
+ } else if (moveRight && selectXMax >= x + drawAreaWidth) {
+ x = selectXMax - drawAreaWidth;
+ needScroll = gTrue;
+ } else if (moveLeft && selectXMin >= x + drawAreaWidth) {
+ x = selectXMin - drawAreaWidth;
+ needScroll = gTrue;
+ } else if (moveRight && selectXMax < x) {
+ x = selectXMax;
+ needScroll = gTrue;
+ }
+ if (moveTop && selectYMin < y) {
+ y = selectYMin;
+ needScroll = gTrue;
+ } else if (moveBottom && selectYMax >= y + drawAreaHeight) {
+ y = selectYMax - drawAreaHeight;
+ needScroll = gTrue;
+ } else if (moveTop && selectYMin >= y + drawAreaHeight) {
+ y = selectYMin - drawAreaHeight;
+ needScroll = gTrue;
+ } else if (moveBottom && selectYMax < y) {
+ y = selectYMax;
+ needScroll = gTrue;
+ }
+ if (needScroll) {
+ scrollTo(x, y);
+ }
+}
+
+void XPDFCore::moveSelection(int mx, int my) {
+ int xMin, yMin, xMax, yMax;
+
+ // clip mouse coords
+ if (mx < 0) {
+ mx = 0;
+ } else if (mx >= out->getPixmapWidth()) {
+ mx = out->getPixmapWidth() - 1;
+ }
+ if (my < 0) {
+ my = 0;
+ } else if (my >= out->getPixmapHeight()) {
+ my = out->getPixmapHeight() - 1;
+ }
+
+ // move appropriate edges of selection
+ if (lastDragLeft) {
+ if (mx < selectXMax) {
+ xMin = mx;
+ xMax = selectXMax;
+ } else {
+ xMin = selectXMax;
+ xMax = mx;
+ lastDragLeft = gFalse;
+ }
+ } else {
+ if (mx > selectXMin) {
+ xMin = selectXMin;
+ xMax = mx;
+ } else {
+ xMin = mx;
+ xMax = selectXMin;
+ lastDragLeft = gTrue;
+ }
+ }
+ if (lastDragTop) {
+ if (my < selectYMax) {
+ yMin = my;
+ yMax = selectYMax;
+ } else {
+ yMin = selectYMax;
+ yMax = my;
+ lastDragTop = gFalse;
+ }
+ } else {
+ if (my > selectYMin) {
+ yMin = selectYMin;
+ yMax = my;
+ } else {
+ yMin = my;
+ yMax = selectYMin;
+ lastDragTop = gTrue;
+ }
+ }
+
+ // redraw the selection
+ setSelection(xMin, yMin, xMax, yMax);
+}
+
+// X's copy-and-paste mechanism is brain damaged. Xt doesn't help
+// any, but doesn't make it too much worse, either. Motif, on the
+// other hand, adds significant complexity to the mess. So here we
+// blow off the Motif junk and stick to plain old Xt. The next two
+// functions (copySelection and convertSelectionCbk) implement the
+// magic needed to deal with Xt's mechanism. Note that this requires
+// global variables (currentSelection and currentSelectionOwner).
+
+void XPDFCore::copySelection() {
+ if (!doc->okToCopy()) {
+ return;
+ }
+ if (currentSelection) {
+ delete currentSelection;
+ }
+ //~ for multithreading: need a mutex here
+ currentSelection = out->getText(selectXMin, selectYMin,
+ selectXMax, selectYMax);
+ currentSelectionOwner = this;
+ XtOwnSelection(drawArea, XA_PRIMARY, XtLastTimestampProcessed(display),
+ &convertSelectionCbk, NULL, NULL);
+}
+
+Boolean XPDFCore::convertSelectionCbk(Widget widget, Atom *selection,
+ Atom *target, Atom *type,
+ XtPointer *value, unsigned long *length,
+ int *format) {
+ if (*target != XA_STRING) {
+ return False;
+ }
+ //~ for multithreading: need a mutex here
+ *value = XtNewString(currentSelection->getCString());
+ *length = currentSelection->getLength();
+ *type = XA_STRING;
+ *format = 8; // 8-bit elements
+ return True;
+}
+
+GBool XPDFCore::getSelection(int *xMin, int *yMin, int *xMax, int *yMax) {
+ if (selectXMin >= selectXMax || selectYMin >= selectYMax) {
+ return gFalse;
+ }
+ *xMin = selectXMin;
+ *yMin = selectYMin;
+ *xMax = selectXMax;
+ *yMax = selectYMax;
+ return gTrue;
+}
+
+GString *XPDFCore::extractText(int xMin, int yMin, int xMax, int yMax) {
+ if (!doc->okToCopy()) {
+ return NULL;
+ }
+ return out->getText(xMin, yMin, xMax, yMax);
+}
+
+GString *XPDFCore::extractText(int pageNum,
+ int xMin, int yMin, int xMax, int yMax) {
+ TextOutputDev *textOut;
+ GString *s;
+
+ if (!doc->okToCopy()) {
+ return NULL;
+ }
+ textOut = new TextOutputDev(NULL, gFalse, gFalse);
+ if (!textOut->isOk()) {
+ delete textOut;
+ return NULL;
+ }
+ doc->displayPage(textOut, pageNum, dpi, rotate, gFalse);
+ s = textOut->getText(xMin, yMin, xMax, yMax);
+ delete textOut;
+ return s;
+}
+
+//------------------------------------------------------------------------
+// hyperlinks
+//------------------------------------------------------------------------
+
+void XPDFCore::doLink(int mx, int my) {
+ double x, y;
+ LinkAction *action;
+
+ // look for a link
+ out->cvtDevToUser(mx, my, &x, &y);
+ if ((action = doc->findLink(x, y))) {
+ doAction(action);
+ }
+}
+
+void XPDFCore::doAction(LinkAction *action) {
+ LinkActionKind kind;
+ LinkDest *dest;
+ GString *namedDest;
+ char *s;
+ GString *fileName, *fileName2;
+ GString *cmd;
+ GString *actionName;
+ Object movieAnnot, obj1, obj2;
+ GString *msg;
+ int i;
+
+ switch (kind = action->getKind()) {
+
+ // GoTo / GoToR action
+ case actionGoTo:
+ case actionGoToR:
+ if (kind == actionGoTo) {
+ dest = NULL;
+ namedDest = NULL;
+ if ((dest = ((LinkGoTo *)action)->getDest())) {
+ dest = dest->copy();
+ } else if ((namedDest = ((LinkGoTo *)action)->getNamedDest())) {
+ namedDest = namedDest->copy();
+ }
+ } else {
+ dest = NULL;
+ namedDest = NULL;
+ if ((dest = ((LinkGoToR *)action)->getDest())) {
+ dest = dest->copy();
+ } else if ((namedDest = ((LinkGoToR *)action)->getNamedDest())) {
+ namedDest = namedDest->copy();
+ }
+ s = ((LinkGoToR *)action)->getFileName()->getCString();
+ //~ translate path name for VMS (deal with '/')
+ if (isAbsolutePath(s)) {
+ fileName = new GString(s);
+ } else {
+ fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s);
+ }
+ if (loadFile(fileName) != errNone) {
+ if (dest) {
+ delete dest;
+ }
+ if (namedDest) {
+ delete namedDest;
+ }
+ delete fileName;
+ return;
+ }
+ delete fileName;
+ }
+ if (namedDest) {
+ dest = doc->findDest(namedDest);
+ delete namedDest;
+ }
+ if (dest) {
+ displayDest(dest, zoom, rotate, gTrue);
+ delete dest;
+ } else {
+ if (kind == actionGoToR) {
+ displayPage(1, zoom, 0, gFalse, gTrue);
+ }
+ }
+ break;
+
+ // Launch action
+ case actionLaunch:
+ fileName = ((LinkLaunch *)action)->getFileName();
+ s = fileName->getCString();
+ if (!strcmp(s + fileName->getLength() - 4, ".pdf") ||
+ !strcmp(s + fileName->getLength() - 4, ".PDF")) {
+ //~ translate path name for VMS (deal with '/')
+ if (isAbsolutePath(s)) {
+ fileName = fileName->copy();
+ } else {
+ fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s);
+ }
+ if (loadFile(fileName) != errNone) {
+ delete fileName;
+ return;
+ }
+ delete fileName;
+ displayPage(1, zoom, rotate, gFalse, gTrue);
+ } else {
+ fileName = fileName->copy();
+ if (((LinkLaunch *)action)->getParams()) {
+ fileName->append(' ');
+ fileName->append(((LinkLaunch *)action)->getParams());
+ }
+#ifdef VMS
+ fileName->insert(0, "spawn/nowait ");
+#elif defined(__EMX__)
+ fileName->insert(0, "start /min /n ");
+#else
+ fileName->append(" &");
+#endif
+ msg = new GString("About to execute the command:\n");
+ msg->append(fileName);
+ if (doQuestionDialog("Launching external application", msg)) {
+ system(fileName->getCString());
+ }
+ delete fileName;
+ delete msg;
+ }
+ break;
+
+ // URI action
+ case actionURI:
+ if (!(cmd = globalParams->getURLCommand())) {
+ error(-1, "No urlCommand defined in config file");
+ break;
+ }
+ runCommand(cmd, ((LinkURI *)action)->getURI());
+ break;
+
+ // Named action
+ case actionNamed:
+ actionName = ((LinkNamed *)action)->getName();
+ if (!actionName->cmp("NextPage")) {
+ gotoNextPage(1, gTrue);
+ } else if (!actionName->cmp("PrevPage")) {
+ gotoPrevPage(1, gTrue, gFalse);
+ } else if (!actionName->cmp("FirstPage")) {
+ if (page != 1) {
+ displayPage(1, zoom, rotate, gTrue, gTrue);
+ }
+ } else if (!actionName->cmp("LastPage")) {
+ if (page != doc->getNumPages()) {
+ displayPage(doc->getNumPages(), zoom, rotate, gTrue, gTrue);
+ }
+ } else if (!actionName->cmp("GoBack")) {
+ goBackward();
+ } else if (!actionName->cmp("GoForward")) {
+ goForward();
+ } else if (!actionName->cmp("Quit")) {
+ if (actionCbk) {
+ (*actionCbk)(actionCbkData, "Quit");
+ }
+ } else {
+ error(-1, "Unknown named action: '%s'", actionName->getCString());
+ }
+ break;
+
+ // Movie action
+ case actionMovie:
+ if (!(cmd = globalParams->getMovieCommand())) {
+ error(-1, "No movieCommand defined in config file");
+ break;
+ }
+ if (((LinkMovie *)action)->hasAnnotRef()) {
+ doc->getXRef()->fetch(((LinkMovie *)action)->getAnnotRef()->num,
+ ((LinkMovie *)action)->getAnnotRef()->gen,
+ &movieAnnot);
+ } else {
+ doc->getCatalog()->getPage(page)->getAnnots(&obj1);
+ if (obj1.isArray()) {
+ for (i = 0; i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGet(i, &movieAnnot)->isDict()) {
+ if (movieAnnot.dictLookup("Subtype", &obj2)->isName("Movie")) {
+ obj2.free();
+ break;
+ }
+ obj2.free();
+ }
+ movieAnnot.free();
+ }
+ obj1.free();
+ }
+ }
+ if (movieAnnot.isDict()) {
+ if (movieAnnot.dictLookup("Movie", &obj1)->isDict()) {
+ if (obj1.dictLookup("F", &obj2)) {
+ if ((fileName = LinkAction::getFileSpecName(&obj2))) {
+ if (!isAbsolutePath(fileName->getCString())) {
+ fileName2 = appendToPath(
+ grabPath(doc->getFileName()->getCString()),
+ fileName->getCString());
+ delete fileName;
+ fileName = fileName2;
+ }
+ runCommand(cmd, fileName);
+ delete fileName;
+ }
+ obj2.free();
+ }
+ obj1.free();
+ }
+ }
+ movieAnnot.free();
+ break;
+
+ // unknown action type
+ case actionUnknown:
+ error(-1, "Unknown link action type: '%s'",
+ ((LinkUnknown *)action)->getAction()->getCString());
+ break;
+ }
+}
+
+// Run a command, given a <cmdFmt> string with one '%s' in it, and an
+// <arg> string to insert in place of the '%s'.
+void XPDFCore::runCommand(GString *cmdFmt, GString *arg) {
+ GString *cmd;
+ char *s;
+ int i;
+
+ if ((s = strstr(cmdFmt->getCString(), "%s"))) {
+ cmd = arg->copy();
+ // filter out any quote marks (' or ") to avoid a potential
+ // security hole
+ i = 0;
+ while (i < cmd->getLength()) {
+ if (cmd->getChar(i) == '"') {
+ cmd->del(i);
+ cmd->insert(i, "%22");
+ i += 3;
+ } else if (cmd->getChar(i) == '\'') {
+ cmd->del(i);
+ cmd->insert(i, "%27");
+ i += 3;
+ } else {
+ ++i;
+ }
+ }
+ cmd->insert(0, cmdFmt->getCString(),
+ s - cmdFmt->getCString());
+ cmd->append(s + 2);
+ } else {
+ cmd = cmdFmt->copy();
+ }
+#ifdef VMS
+ cmd->insert(0, "spawn/nowait ");
+#elif defined(__EMX__)
+ cmd->insert(0, "start /min /n ");
+#else
+ cmd->append(" &");
+#endif
+ system(cmd->getCString());
+ delete cmd;
+}
+
+
+//------------------------------------------------------------------------
+// find
+//------------------------------------------------------------------------
+
+void XPDFCore::find(char *s) {
+ Unicode *u;
+ TextOutputDev *textOut;
+ int xMin, yMin, xMax, yMax;
+ double xMin1, yMin1, xMax1, yMax1;
+ int pg;
+ GBool top;
+ int len, i;
+
+ // check for zero-length string
+ if (!s[0]) {
+ XBell(display, 0);
+ return;
+ }
+
+ // set cursor to watch
+ setCursor(busyCursor);
+
+ // convert to Unicode
+#if 1 //~ should do something more intelligent here
+ len = strlen(s);
+ u = (Unicode *)gmalloc(len * sizeof(Unicode));
+ for (i = 0; i < len; ++i) {
+ u[i] = (Unicode)(s[i] & 0xff);
+ }
+#endif
+
+ // search current page starting at current selection or top of page
+ xMin = yMin = xMax = yMax = 0;
+ if (selectXMin < selectXMax && selectYMin < selectYMax) {
+ xMin = selectXMax;
+ yMin = (selectYMin + selectYMax) / 2;
+ top = gFalse;
+ } else {
+ top = gTrue;
+ }
+ if (out->findText(u, len, top, gTrue, &xMin, &yMin, &xMax, &yMax)) {
+ goto found;
+ }
+
+ // search following pages
+ textOut = new TextOutputDev(NULL, gFalse, gFalse);
+ if (!textOut->isOk()) {
+ delete textOut;
+ goto done;
+ }
+ for (pg = page+1; pg <= doc->getNumPages(); ++pg) {
+ doc->displayPage(textOut, pg, 72, 0, gFalse);
+ if (textOut->findText(u, len, gTrue, gTrue,
+ &xMin1, &yMin1, &xMax1, &yMax1)) {
+ goto foundPage;
+ }
+ }
+
+ // search previous pages
+ for (pg = 1; pg < page; ++pg) {
+ doc->displayPage(textOut, pg, 72, 0, gFalse);
+ if (textOut->findText(u, len, gTrue, gTrue,
+ &xMin1, &yMin1, &xMax1, &yMax1)) {
+ goto foundPage;
+ }
+ }
+ delete textOut;
+
+ // search current page ending at current selection
+ if (selectXMin < selectXMax && selectYMin < selectYMax) {
+ xMax = selectXMin;
+ yMax = (selectYMin + selectYMax) / 2;
+ if (out->findText(u, len, gTrue, gFalse, &xMin, &yMin, &xMax, &yMax)) {
+ goto found;
+ }
+ }
+
+ // not found
+ XBell(display, 0);
+ goto done;
+
+ // found on a different page
+ foundPage:
+ delete textOut;
+ displayPage(pg, zoom, rotate, gTrue, gTrue);
+ if (!out->findText(u, len, gTrue, gTrue, &xMin, &yMin, &xMax, &yMax)) {
+ // this can happen if coalescing is bad
+ goto done;
+ }
+
+ // found: change the selection
+ found:
+ setSelection(xMin, yMin, xMax, yMax);
+#ifndef NO_TEXT_SELECT
+ copySelection();
+#endif
+
+ done:
+ gfree(u);
+
+ // reset cursors to normal
+ setCursor(None);
+}
+
+//------------------------------------------------------------------------
+// misc access
+//------------------------------------------------------------------------
+
+void XPDFCore::setBusyCursor(GBool busy) {
+ setCursor(busy ? busyCursor : None);
+}
+
+void XPDFCore::takeFocus() {
+ XmProcessTraversal(drawArea, XmTRAVERSE_CURRENT);
+}
+
+//------------------------------------------------------------------------
+// GUI code
+//------------------------------------------------------------------------
+
+void XPDFCore::initWindow() {
+ Arg args[20];
+ int n;
+
+ // create the cursors
+ busyCursor = XCreateFontCursor(display, XC_watch);
+ linkCursor = XCreateFontCursor(display, XC_hand2);
+ selectCursor = XCreateFontCursor(display, XC_cross);
+ currentCursor = 0;
+
+ // create the scrolled window and scrollbars
+ n = 0;
+ XtSetArg(args[n], XmNscrollingPolicy, XmAPPLICATION_DEFINED); ++n;
+ XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n;
+ scrolledWin = XmCreateScrolledWindow(parentWidget, "scroll", args, n);
+ XtManageChild(scrolledWin);
+ n = 0;
+ XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
+ XtSetArg(args[n], XmNminimum, 0); ++n;
+ XtSetArg(args[n], XmNmaximum, 1); ++n;
+ XtSetArg(args[n], XmNsliderSize, 1); ++n;
+ XtSetArg(args[n], XmNvalue, 0); ++n;
+ XtSetArg(args[n], XmNincrement, 1); ++n;
+ XtSetArg(args[n], XmNpageIncrement, 1); ++n;
+ hScrollBar = XmCreateScrollBar(scrolledWin, "hScrollBar", args, n);
+ XtManageChild(hScrollBar);
+ XtAddCallback(hScrollBar, XmNvalueChangedCallback,
+ &hScrollChangeCbk, (XtPointer)this);
+#ifndef DISABLE_SMOOTH_SCROLL
+ XtAddCallback(hScrollBar, XmNdragCallback,
+ &hScrollDragCbk, (XtPointer)this);
+#endif
+ n = 0;
+ XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n;
+ XtSetArg(args[n], XmNminimum, 0); ++n;
+ XtSetArg(args[n], XmNmaximum, 1); ++n;
+ XtSetArg(args[n], XmNsliderSize, 1); ++n;
+ XtSetArg(args[n], XmNvalue, 0); ++n;
+ XtSetArg(args[n], XmNincrement, 1); ++n;
+ XtSetArg(args[n], XmNpageIncrement, 1); ++n;
+ vScrollBar = XmCreateScrollBar(scrolledWin, "vScrollBar", args, n);
+ XtManageChild(vScrollBar);
+ XtAddCallback(vScrollBar, XmNvalueChangedCallback,
+ &vScrollChangeCbk, (XtPointer)this);
+#ifndef DISABLE_SMOOTH_SCROLL
+ XtAddCallback(vScrollBar, XmNdragCallback,
+ &vScrollDragCbk, (XtPointer)this);
+#endif
+
+ // create the drawing area
+ n = 0;
+ XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 0); ++n;
+ XtSetArg(args[n], XmNmarginHeight, 0); ++n;
+ if (fullScreen) {
+ XtSetArg(args[n], XmNshadowThickness, 0); ++n;
+ }
+ drawAreaFrame = XmCreateFrame(scrolledWin, "drawAreaFrame", args, n);
+ XtManageChild(drawAreaFrame);
+ n = 0;
+ XtSetArg(args[n], XmNresizePolicy, XmRESIZE_ANY); ++n;
+ XtSetArg(args[n], XmNbackground, paperColor); ++n;
+ XtSetArg(args[n], XmNwidth, 700); ++n;
+ XtSetArg(args[n], XmNheight, 500); ++n;
+ drawArea = XmCreateDrawingArea(drawAreaFrame, "drawArea", args, n);
+ XtManageChild(drawArea);
+ XtAddCallback(drawArea, XmNresizeCallback, &resizeCbk, (XtPointer)this);
+ XtAddCallback(drawArea, XmNexposeCallback, &redrawCbk, (XtPointer)this);
+ XtAddCallback(drawArea, XmNinputCallback, &inputCbk, (XtPointer)this);
+ resizeCbk(drawArea, this, NULL);
+
+ // set up mouse motion translations
+ XtOverrideTranslations(drawArea, XtParseTranslationTable(
+ "<Btn1Down>:DrawingAreaInput()\n"
+ "<Btn1Up>:DrawingAreaInput()\n"
+ "<Btn1Motion>:DrawingAreaInput()\n"
+ "<Motion>:DrawingAreaInput()"));
+
+ // can't create a GC until the window gets mapped
+ drawAreaGC = NULL;
+ selectGC = NULL;
+ highlightGC = NULL;
+}
+
+void XPDFCore::hScrollChangeCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFCore *core = (XPDFCore *)ptr;
+ XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
+
+ core->scrollTo(data->value, core->scrollY);
+}
+
+void XPDFCore::hScrollDragCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFCore *core = (XPDFCore *)ptr;
+ XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
+
+ core->scrollTo(data->value, core->scrollY);
+}
+
+void XPDFCore::vScrollChangeCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFCore *core = (XPDFCore *)ptr;
+ XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
+
+ core->scrollTo(core->scrollX, data->value);
+}
+
+void XPDFCore::vScrollDragCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFCore *core = (XPDFCore *)ptr;
+ XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
+
+ core->scrollTo(core->scrollX, data->value);
+}
+
+void XPDFCore::resizeCbk(Widget widget, XtPointer ptr, XtPointer callData) {
+ XPDFCore *core = (XPDFCore *)ptr;
+ Arg args[2];
+ int n;
+ Dimension w, h;
+
+ n = 0;
+ XtSetArg(args[n], XmNwidth, &w); ++n;
+ XtSetArg(args[n], XmNheight, &h); ++n;
+ XtGetValues(core->drawArea, args, n);
+ core->drawAreaWidth = (int)w;
+ core->drawAreaHeight = (int)h;
+ if (core->page >= 0 &&
+ (core->zoom == zoomPage || core->zoom == zoomWidth)) {
+ core->displayPage(core->page, core->zoom, core->rotate,
+ gFalse, gFalse);
+ } else {
+ core->updateScrollBars();
+ }
+}
+
+void XPDFCore::redrawCbk(Widget widget, XtPointer ptr, XtPointer callData) {
+ XPDFCore *core = (XPDFCore *)ptr;
+ XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData;
+ int x, y, w, h;
+
+ if (data->reason == XmCR_EXPOSE) {
+ x = core->scrollX + data->event->xexpose.x;
+ y = core->scrollY + data->event->xexpose.y;
+ w = data->event->xexpose.width;
+ h = data->event->xexpose.height;
+ } else {
+ x = core->scrollX;
+ y = core->scrollY;
+ w = core->drawAreaWidth;
+ h = core->drawAreaHeight;
+ }
+ core->redrawRectangle(x, y, w, h);
+}
+
+void XPDFCore::outputDevRedrawCbk(void *data) {
+ XPDFCore *core = (XPDFCore *)data;
+
+ core->redrawRectangle(core->scrollX, core->scrollY,
+ core->drawAreaWidth, core->drawAreaHeight);
+}
+
+void XPDFCore::inputCbk(Widget widget, XtPointer ptr, XtPointer callData) {
+ XPDFCore *core = (XPDFCore *)ptr;
+ XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData;
+ LinkAction *action;
+ int mx, my;
+ double x, y;
+ char *s;
+ KeySym key;
+ char buf[20];
+ int n;
+
+ switch (data->event->type) {
+ case ButtonPress:
+ if (data->event->xbutton.button == 1) {
+ core->takeFocus();
+ if (core->doc && core->doc->getNumPages() > 0) {
+ if (core->selectEnabled) {
+ mx = core->scrollX + data->event->xbutton.x;
+ my = core->scrollY + data->event->xbutton.y;
+ core->setSelection(mx, my, mx, my);
+ core->setCursor(core->selectCursor);
+ core->dragging = gTrue;
+ }
+ }
+ } else if (data->event->xbutton.button == 2) {
+ if (!core->fullScreen) {
+ core->panning = gTrue;
+ core->panMX = data->event->xbutton.x;
+ core->panMY = data->event->xbutton.y;
+ }
+ } else if (data->event->xbutton.button == 4) { // mouse wheel up
+ if (core->fullScreen) {
+ core->gotoPrevPage(1, gTrue, gFalse);
+ } else if (core->scrollY == 0) {
+ core->gotoPrevPage(1, gFalse, gTrue);
+ } else {
+ core->scrollUp(1);
+ }
+ } else if (data->event->xbutton.button == 5) { // mouse wheel down
+ if (core->fullScreen ||
+ core->scrollY >=
+ core->out->getPixmapHeight() - core->drawAreaHeight) {
+ core->gotoNextPage(1, gTrue);
+ } else {
+ core->scrollDown(1);
+ }
+ } else if (data->event->xbutton.button == 6) { // second mouse wheel right
+ if (!core->fullScreen) {
+ core->scrollRight(1);
+ }
+ } else if (data->event->xbutton.button == 7) { // second mouse wheel left
+ if (!core->fullScreen) {
+ core->scrollLeft(1);
+ }
+ } else {
+ if (*core->mouseCbk) {
+ (*core->mouseCbk)(core->mouseCbkData, data->event);
+ }
+ }
+ break;
+ case ButtonRelease:
+ if (data->event->xbutton.button == 1) {
+ if (core->doc && core->doc->getNumPages() > 0) {
+ mx = core->scrollX + data->event->xbutton.x;
+ my = core->scrollY + data->event->xbutton.y;
+ if (core->dragging) {
+ core->dragging = gFalse;
+ core->setCursor(None);
+ core->moveSelection(mx, my);
+#ifndef NO_TEXT_SELECT
+ if (core->selectXMin != core->selectXMax &&
+ core->selectYMin != core->selectYMax) {
+ if (core->doc->okToCopy()) {
+ core->copySelection();
+ } else {
+ error(-1, "Copying of text from this document is not allowed.");
+ }
+ }
+#endif
+ }
+ if (core->hyperlinksEnabled) {
+ if (core->selectXMin == core->selectXMax ||
+ core->selectYMin == core->selectYMax) {
+ core->doLink(mx, my);
+ }
+ }
+ }
+ } else if (data->event->xbutton.button == 2) {
+ core->panning = gFalse;
+ } else {
+ if (*core->mouseCbk) {
+ (*core->mouseCbk)(core->mouseCbkData, data->event);
+ }
+ }
+ break;
+ case MotionNotify:
+ if (core->doc && core->doc->getNumPages() > 0) {
+ mx = core->scrollX + data->event->xbutton.x;
+ my = core->scrollY + data->event->xbutton.y;
+ if (core->dragging) {
+ core->moveSelection(mx, my);
+ } else if (core->hyperlinksEnabled) {
+ core->out->cvtDevToUser(mx, my, &x, &y);
+ if ((action = core->doc->findLink(x, y))) {
+ core->setCursor(core->linkCursor);
+ if (action != core->linkAction) {
+ core->linkAction = action;
+ if (core->updateCbk) {
+ s = "";
+ switch (action->getKind()) {
+ case actionGoTo:
+ s = "[internal link]";
+ break;
+ case actionGoToR:
+ s = ((LinkGoToR *)action)->getFileName()->getCString();
+ break;
+ case actionLaunch:
+ s = ((LinkLaunch *)action)->getFileName()->getCString();
+ break;
+ case actionURI:
+ s = ((LinkURI *)action)->getURI()->getCString();
+ break;
+ case actionNamed:
+ s = ((LinkNamed *)action)->getName()->getCString();
+ break;
+ case actionMovie:
+ s = "[movie]";
+ break;
+ case actionUnknown:
+ s = "[unknown link]";
+ break;
+ }
+ (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, s);
+ }
+ }
+ } else {
+ core->setCursor(None);
+ if (core->linkAction) {
+ core->linkAction = NULL;
+ if (core->updateCbk) {
+ (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, "");
+ }
+ }
+ }
+ }
+ }
+ if (core->panning) {
+ core->scrollTo(core->scrollX - (data->event->xbutton.x - core->panMX),
+ core->scrollY - (data->event->xbutton.y - core->panMY));
+ core->panMX = data->event->xbutton.x;
+ core->panMY = data->event->xbutton.y;
+ }
+ break;
+ case KeyPress:
+ n = XLookupString(&data->event->xkey, buf, sizeof(buf) - 1,
+ &key, NULL);
+ core->keyPress(buf, key, data->event->xkey.state);
+ break;
+ }
+}
+
+void XPDFCore::keyPress(char *s, KeySym key, Guint modifiers) {
+ switch (key) {
+ case XK_Home:
+ case XK_KP_Home:
+ if (modifiers & ControlMask) {
+ displayPage(1, zoom, rotate, gTrue, gTrue);
+ } else if (!fullScreen) {
+ scrollTo(0, 0);
+ }
+ return;
+ case XK_End:
+ case XK_KP_End:
+ if (modifiers & ControlMask) {
+ displayPage(doc->getNumPages(), zoom, rotate, gTrue, gTrue);
+ } else if (!fullScreen) {
+ scrollTo(out->getPixmapWidth() - drawAreaWidth,
+ out->getPixmapHeight() - drawAreaHeight);
+ }
+ return;
+ case XK_Page_Up:
+ case XK_KP_Page_Up:
+ if (fullScreen) {
+ gotoPrevPage(1, gTrue, gFalse);
+ } else {
+ scrollPageUp();
+ }
+ return;
+ case XK_Page_Down:
+ case XK_KP_Page_Down:
+ if (fullScreen) {
+ gotoNextPage(1, gTrue);
+ } else {
+ scrollPageDown();
+ }
+ return;
+ case XK_Left:
+ case XK_KP_Left:
+ if (!fullScreen) {
+ scrollLeft();
+ }
+ return;
+ case XK_Right:
+ case XK_KP_Right:
+ if (!fullScreen) {
+ scrollRight();
+ }
+ return;
+ case XK_Up:
+ case XK_KP_Up:
+ if (!fullScreen) {
+ scrollUp();
+ }
+ return;
+ case XK_Down:
+ case XK_KP_Down:
+ if (!fullScreen) {
+ scrollDown();
+ }
+ return;
+ }
+
+ if (*keyPressCbk) {
+ (*keyPressCbk)(keyPressCbkData, s, key, modifiers);
+ }
+}
+
+void XPDFCore::redrawRectangle(int x, int y, int w, int h) {
+ XGCValues gcValues;
+ Window drawAreaWin;
+
+ // clip to window
+ if (x < scrollX) {
+ w -= scrollX - x;
+ x = scrollX;
+ }
+ if (x + w > scrollX + drawAreaWidth) {
+ w = scrollX + drawAreaWidth - x;
+ }
+ if (y < scrollY) {
+ h -= scrollY - y;
+ y = scrollY;
+ }
+ if (y + h > scrollY + drawAreaHeight) {
+ h = scrollY + drawAreaHeight - y;
+ }
+
+ // create a GC for the drawing area
+ drawAreaWin = XtWindow(drawArea);
+ if (!drawAreaGC) {
+ gcValues.foreground = paperColor;
+ drawAreaGC = XCreateGC(display, drawAreaWin, GCForeground, &gcValues);
+ }
+
+ // draw white background past the edges of the document
+ if (x + w > out->getPixmapWidth()) {
+ XFillRectangle(display, drawAreaWin, drawAreaGC,
+ out->getPixmapWidth() - scrollX, y - scrollY,
+ x + w - out->getPixmapWidth(), h);
+ w = out->getPixmapWidth() - x;
+ }
+ if (y + h > out->getPixmapHeight()) {
+ XFillRectangle(display, drawAreaWin, drawAreaGC,
+ x - scrollX, out->getPixmapHeight() - scrollY,
+ w, y + h - out->getPixmapHeight());
+ h = out->getPixmapHeight() - y;
+ }
+
+ // redraw (checking to see if pixmap has been allocated yet)
+ if (out->getPixmapWidth() > 0) {
+ XCopyArea(display, out->getPixmap(), drawAreaWin, drawAreaGC,
+ x, y, w, h, x - scrollX, y - scrollY);
+ }
+}
+
+void XPDFCore::updateScrollBars() {
+ Arg args[20];
+ int n;
+ int maxPos;
+
+ maxPos = out ? out->getPixmapWidth() : 1;
+ if (maxPos < drawAreaWidth) {
+ maxPos = drawAreaWidth;
+ }
+ if (scrollX > maxPos - drawAreaWidth) {
+ scrollX = maxPos - drawAreaWidth;
+ }
+ n = 0;
+ XtSetArg(args[n], XmNvalue, scrollX); ++n;
+ XtSetArg(args[n], XmNmaximum, maxPos); ++n;
+ XtSetArg(args[n], XmNsliderSize, drawAreaWidth); ++n;
+ XtSetArg(args[n], XmNincrement, 16); ++n;
+ XtSetArg(args[n], XmNpageIncrement, drawAreaWidth); ++n;
+ XtSetValues(hScrollBar, args, n);
+
+ maxPos = out ? out->getPixmapHeight() : 1;
+ if (maxPos < drawAreaHeight) {
+ maxPos = drawAreaHeight;
+ }
+ if (scrollY > maxPos - drawAreaHeight) {
+ scrollY = maxPos - drawAreaHeight;
+ }
+ n = 0;
+ XtSetArg(args[n], XmNvalue, scrollY); ++n;
+ XtSetArg(args[n], XmNmaximum, maxPos); ++n;
+ XtSetArg(args[n], XmNsliderSize, drawAreaHeight); ++n;
+ XtSetArg(args[n], XmNincrement, 16); ++n;
+ XtSetArg(args[n], XmNpageIncrement, drawAreaHeight); ++n;
+ XtSetValues(vScrollBar, args, n);
+}
+
+void XPDFCore::setCursor(Cursor cursor) {
+ Window topWin;
+
+ if (cursor == currentCursor) {
+ return;
+ }
+ if (!(topWin = XtWindow(shell))) {
+ return;
+ }
+ if (cursor == None) {
+ XUndefineCursor(display, topWin);
+ } else {
+ XDefineCursor(display, topWin, cursor);
+ }
+ XFlush(display);
+ currentCursor = cursor;
+}
+
+GBool XPDFCore::doQuestionDialog(char *title, GString *msg) {
+ return doDialog(XmDIALOG_QUESTION, gTrue, title, msg);
+}
+
+void XPDFCore::doInfoDialog(char *title, GString *msg) {
+ doDialog(XmDIALOG_INFORMATION, gFalse, title, msg);
+}
+
+void XPDFCore::doErrorDialog(char *title, GString *msg) {
+ doDialog(XmDIALOG_ERROR, gFalse, title, msg);
+}
+
+GBool XPDFCore::doDialog(int type, GBool hasCancel,
+ char *title, GString *msg) {
+ Widget dialog;
+ XtAppContext appContext;
+ Arg args[20];
+ int n;
+ XmString s1, s2;
+ XEvent event;
+
+ n = 0;
+ XtSetArg(args[n], XmNdialogType, type); ++n;
+ XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n;
+ s1 = XmStringCreateLocalized(title);
+ XtSetArg(args[n], XmNdialogTitle, s1); ++n;
+ s2 = XmStringCreateLocalized(msg->getCString());
+ XtSetArg(args[n], XmNmessageString, s2); ++n;
+ dialog = XmCreateMessageDialog(drawArea, "questionDialog", args, n);
+ XmStringFree(s1);
+ XmStringFree(s2);
+ XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
+ XtAddCallback(dialog, XmNokCallback,
+ &dialogOkCbk, (XtPointer)this);
+ if (hasCancel) {
+ XtAddCallback(dialog, XmNcancelCallback,
+ &dialogCancelCbk, (XtPointer)this);
+ } else {
+ XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
+ }
+
+ XtManageChild(dialog);
+
+ appContext = XtWidgetToApplicationContext(dialog);
+ dialogDone = 0;
+ do {
+ XtAppNextEvent(appContext, &event);
+ XtDispatchEvent(&event);
+ } while (!dialogDone);
+
+ XtUnmanageChild(dialog);
+ XtDestroyWidget(dialog);
+
+ return dialogDone > 0;
+}
+
+void XPDFCore::dialogOkCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFCore *core = (XPDFCore *)ptr;
+
+ core->dialogDone = 1;
+}
+
+void XPDFCore::dialogCancelCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFCore *core = (XPDFCore *)ptr;
+
+ core->dialogDone = -1;
+}
diff --git a/pdf/xpdf/XPDFCore.h b/pdf/xpdf/XPDFCore.h
new file mode 100644
index 0000000..348486f
--- /dev/null
+++ b/pdf/xpdf/XPDFCore.h
@@ -0,0 +1,296 @@
+//========================================================================
+//
+// XPDFCore.h
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef XPDFCORE_H
+#define XPDFCORE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#define Object XtObject
+#include <Xm/XmAll.h>
+#undef Object
+#include <aconf.h>
+#include "gtypes.h"
+#include "gfile.h" // for time_t
+
+class GString;
+class GList;
+class PDFDoc;
+class LinkAction;
+class LinkDest;
+class XPixmapOutputDev;
+
+//------------------------------------------------------------------------
+// zoom factor
+//------------------------------------------------------------------------
+
+#define minZoom -5
+#define maxZoom 5
+#define zoomPage 100
+#define zoomWidth 101
+#define defZoom 1
+
+//------------------------------------------------------------------------
+// XPDFHistory
+//------------------------------------------------------------------------
+
+struct XPDFHistory {
+ GString *fileName;
+ int page;
+};
+
+#define xpdfHistorySize 50
+
+//------------------------------------------------------------------------
+// XPDFRegion
+//------------------------------------------------------------------------
+
+struct XPDFRegion {
+ int page;
+ double xMin, yMin, xMax, yMax;
+ Gulong color;
+ Gulong selectColor;
+};
+
+//------------------------------------------------------------------------
+// callbacks
+//------------------------------------------------------------------------
+
+typedef void (*XPDFUpdateCbk)(void *data, GString *fileName,
+ int pageNum, int numPages, char *linkLabel);
+
+typedef void (*XPDFActionCbk)(void *data, char *action);
+
+typedef void (*XPDFKeyPressCbk)(void *data, char *s, KeySym key,
+ Guint modifiers);
+
+typedef void (*XPDFMouseCbk)(void *data, XEvent *event);
+
+typedef GString *(*XPDFReqPasswordCbk)(void *data, GBool again);
+
+//------------------------------------------------------------------------
+// XPDFCore
+//------------------------------------------------------------------------
+
+class XPDFCore {
+public:
+
+ // Create viewer core inside <parentWidgetA>.
+ XPDFCore(Widget shellA, Widget parentWidgetA,
+ Gulong paperColorA, GBool fullScreenA, GBool reverseVideo,
+ GBool installCmap, int rgbCubeSize);
+
+ ~XPDFCore();
+
+ //----- loadFile / displayPage / displayDest
+
+ // Load a new file. Returns pdfOk or error code.
+ int loadFile(GString *fileName, GString *ownerPassword = NULL,
+ GString *userPassword = NULL);
+
+ // Resize the window to fit page <pg> of the current document.
+ void resizeToPage(int pg);
+
+ // Clear out the current document, if any.
+ void clear();
+
+ // Display (or redisplay) the specified page. If <scrollToTop> is
+ // set, the window is vertically scrolled to the top; otherwise, no
+ // scrolling is done. If <addToHist> is set, this page change is
+ // added to the history list.
+ void displayPage(int pageA, int zoomA, int rotateA,
+ GBool scrollToTop, GBool addToHist);
+
+ // Display a link destination.
+ void displayDest(LinkDest *dest, int zoomA, int rotateA,
+ GBool addToHist);
+
+ //----- page/position changes
+
+ void gotoNextPage(int inc, GBool top);
+ void gotoPrevPage(int dec, GBool top, GBool bottom);
+ void goForward();
+ void goBackward();
+ void scrollLeft(int nCols = 1);
+ void scrollRight(int nCols = 1);
+ void scrollUp(int nLines = 1);
+ void scrollDown(int nLines = 1);
+ void scrollPageUp();
+ void scrollPageDown();
+ void scrollTo(int x, int y);
+
+ //----- selection
+
+ void setSelection(int newXMin, int newYMin, int newXMax, int newYMax);
+ void moveSelection(int mx, int my);
+ void copySelection();
+ GBool getSelection(int *xMin, int *yMin, int *xMax, int *yMax);
+ GString *extractText(int xMin, int yMin, int xMax, int yMax);
+ GString *extractText(int pageNum, int xMin, int yMin, int xMax, int yMax);
+
+ //----- hyperlinks
+
+ void doAction(LinkAction *action);
+
+
+ //----- find
+
+ void find(char *s);
+
+ //----- simple modal dialogs
+
+ GBool doQuestionDialog(char *title, GString *msg);
+ void doInfoDialog(char *title, GString *msg);
+ void doErrorDialog(char *title, GString *msg);
+
+ //----- misc access
+
+ Widget getWidget() { return scrolledWin; }
+ Widget getDrawAreaWidget() { return drawArea; }
+ PDFDoc *getDoc() { return doc; }
+ XPixmapOutputDev *getOutputDev() { return out; }
+ int getPageNum() { return page; }
+ int getZoom() { return zoom; }
+ double getZoomDPI() { return dpi; }
+ int getRotate() { return rotate; }
+ GBool canGoBack() { return historyBLen > 1; }
+ GBool canGoForward() { return historyFLen > 0; }
+ int getScrollX() { return scrollX; }
+ int getScrollY() { return scrollY; }
+ int getDrawAreaWidth() { return drawAreaWidth; }
+ int getDrawAreaHeight() { return drawAreaHeight; }
+ void setBusyCursor(GBool busy);
+ void takeFocus();
+ void enableHyperlinks(GBool on) { hyperlinksEnabled = on; }
+ void enableSelect(GBool on) { selectEnabled = on; }
+ void setUpdateCbk(XPDFUpdateCbk cbk, void *data)
+ { updateCbk = cbk; updateCbkData = data; }
+ void setActionCbk(XPDFActionCbk cbk, void *data)
+ { actionCbk = cbk; actionCbkData = data; }
+ void setKeyPressCbk(XPDFKeyPressCbk cbk, void *data)
+ { keyPressCbk = cbk; keyPressCbkData = data; }
+ void setMouseCbk(XPDFMouseCbk cbk, void *data)
+ { mouseCbk = cbk; mouseCbkData = data; }
+ void setReqPasswordCbk(XPDFReqPasswordCbk cbk, void *data)
+ { reqPasswordCbk = cbk; reqPasswordCbkData = data; }
+
+private:
+
+ //----- hyperlinks
+ void doLink(int mx, int my);
+ void runCommand(GString *cmdFmt, GString *arg);
+
+ //----- selection
+ static Boolean convertSelectionCbk(Widget widget, Atom *selection,
+ Atom *target, Atom *type,
+ XtPointer *value, unsigned long *length,
+ int *format);
+
+
+ //----- GUI code
+ void initWindow();
+ static void hScrollChangeCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void hScrollDragCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void vScrollChangeCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void vScrollDragCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void resizeCbk(Widget widget, XtPointer ptr, XtPointer callData);
+ static void redrawCbk(Widget widget, XtPointer ptr, XtPointer callData);
+ static void outputDevRedrawCbk(void *data);
+ static void inputCbk(Widget widget, XtPointer ptr, XtPointer callData);
+ void keyPress(char *s, KeySym key, Guint modifiers);
+ void redrawRectangle(int x, int y, int w, int h);
+ void updateScrollBars();
+ void setCursor(Cursor cursor);
+ GBool doDialog(int type, GBool hasCancel,
+ char *title, GString *msg);
+ static void dialogOkCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void dialogCancelCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+
+ Gulong paperColor;
+ GBool fullScreen;
+
+ Display *display;
+ int screenNum;
+ Visual *visual;
+ Colormap colormap;
+ Widget shell; // top-level shell containing the widget
+ Widget parentWidget; // parent widget (not created by XPDFCore)
+ Widget scrolledWin;
+ Widget hScrollBar;
+ Widget vScrollBar;
+ Widget drawAreaFrame;
+ Widget drawArea;
+ Cursor busyCursor, linkCursor, selectCursor;
+ Cursor currentCursor;
+ GC drawAreaGC; // GC for blitting into drawArea
+ GC selectGC;
+ GC highlightGC;
+
+ int drawAreaWidth, drawAreaHeight;
+ int scrollX, scrollY; // current upper-left corner
+
+ int selectXMin, selectYMin, // coordinates of current selection:
+ selectXMax, selectYMax; // (xMin==xMax || yMin==yMax) means there
+ // is no selection
+ GBool dragging; // set while selection is being dragged
+ GBool lastDragLeft; // last dragged selection edge was left/right
+ GBool lastDragTop; // last dragged selection edge was top/bottom
+ static GString *currentSelection; // selected text
+ static XPDFCore *currentSelectionOwner;
+
+ GBool panning;
+ int panMX, panMY;
+
+ XPDFHistory // page history queue
+ history[xpdfHistorySize];
+ int historyCur; // currently displayed page
+ int historyBLen; // number of valid entries backward from
+ // current entry
+ int historyFLen; // number of valid entries forward from
+ // current entry
+
+ PDFDoc *doc; // current PDF file
+ int page; // current page number
+ int zoom; // current zoom level
+ double dpi; // current zoom level, in DPI
+ int rotate; // current page rotation
+ time_t modTime; // last modification time of PDF file
+
+ LinkAction *linkAction; // mouse cursor is over this link
+
+
+ XPDFUpdateCbk updateCbk;
+ void *updateCbkData;
+ XPDFActionCbk actionCbk;
+ void *actionCbkData;
+ XPDFKeyPressCbk keyPressCbk;
+ void *keyPressCbkData;
+ XPDFMouseCbk mouseCbk;
+ void *mouseCbkData;
+ XPDFReqPasswordCbk reqPasswordCbk;
+ void *reqPasswordCbkData;
+
+ GBool hyperlinksEnabled;
+ GBool selectEnabled;
+
+ XPixmapOutputDev *out;
+
+ int dialogDone;
+};
+
+#endif
diff --git a/pdf/xpdf/XPDFTree.cc b/pdf/xpdf/XPDFTree.cc
new file mode 100644
index 0000000..46e5466
--- /dev/null
+++ b/pdf/xpdf/XPDFTree.cc
@@ -0,0 +1,929 @@
+//========================================================================
+//
+// XPDFTree.cc
+//
+//========================================================================
+
+#include <stdlib.h>
+#include "gmem.h"
+#include "XPDFTreeP.h"
+
+//------------------------------------------------------------------------
+
+#define xpdfTreeIndent 16
+
+//------------------------------------------------------------------------
+
+struct _XPDFTreeEntry {
+ Widget widget;
+ XPDFTreeEntry *children;
+ XPDFTreeEntry *next;
+};
+
+//------------------------------------------------------------------------
+
+static void classPartInitialize(WidgetClass widgetClass);
+static void initialize(Widget requestWidget, Widget newWidget,
+ ArgList args, Cardinal *numArgs);
+static void destroy(Widget widget);
+static void destroySubtree(XPDFTreeEntry *e);
+static void resize(Widget widget);
+static void redisplay(Widget widget, XEvent *event, Region region);
+static void redisplaySubtree(XPDFTreeWidget w, XPDFTreeEntry *e,
+ XEvent *event, Region region);
+static void drawExpandedIcon(XPDFTreeWidget w, Position x, Position y);
+static void drawCollapsedIcon(XPDFTreeWidget w, Position x, Position y);
+static Boolean setValues(Widget oldWidget, Widget requestWidget,
+ Widget newWidget, ArgList args, Cardinal *numArgs);
+static void setValuesAlmost(Widget oldWidget, Widget newWidget,
+ XtWidgetGeometry *request,
+ XtWidgetGeometry *reply);
+static XtGeometryResult queryGeometry(Widget widget,
+ XtWidgetGeometry *request,
+ XtWidgetGeometry *reply);
+static XtGeometryResult geometryManager(Widget widget,
+ XtWidgetGeometry *request,
+ XtWidgetGeometry *reply);
+static void changeManaged(Widget widget);
+static void initConstraint(Widget requestWidget, Widget newWidget,
+ ArgList args, Cardinal *numArgs);
+static void destroyConstraint(Widget widget);
+static void deleteSubtree(Widget widget);
+static Boolean constraintSetValues(Widget oldWidget, Widget requestWidget,
+ Widget newWidget,
+ ArgList args, Cardinal *numArgs);
+static void insertChildOnList(XPDFTreeEntry *e, XPDFTreeEntry **listHead);
+static void deleteChildFromList(XPDFTreeEntry *e, XPDFTreeEntry **listHead);
+static void createGC(Widget widget);
+static void destroyGC(Widget widget);
+static void layout(Widget widget, Widget instigator);
+static int layoutSubtree(XPDFTreeWidget w, Widget instigator,
+ XPDFTreeEntry *e, Position x, Position y,
+ Boolean visible);
+static void calcSize(Widget widget, Widget instigator,
+ Dimension *totalWidth,
+ Dimension *totalHeight);
+static void calcSubtreeSize(XPDFTreeWidget w, Widget instigator,
+ XPDFTreeEntry *e,
+ Dimension *width, Dimension *height);
+static Boolean needRelayout(Widget oldWidget, Widget newWidget);
+static void click(Widget widget, XEvent *event,
+ String *params, Cardinal *numParams);
+static Boolean findPosition(XPDFTreeWidget w, int x, int y,
+ XPDFTreeEntry **e, Boolean *onExpandIcon);
+static Boolean findPositionInSubtree(XPDFTreeWidget w, int x, int y,
+ XPDFTreeEntry **e,
+ Boolean *onExpandIcon);
+
+//------------------------------------------------------------------------
+
+static XtResource resources[] = {
+ { XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
+ sizeof(Dimension), XtOffsetOf(XPDFTreeRec, tree.marginWidth),
+ XmRImmediate, (XtPointer)0 },
+ { XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
+ sizeof(Dimension), XtOffsetOf(XPDFTreeRec, tree.marginHeight),
+ XmRImmediate, (XtPointer)0 },
+ { XPDFNselectionCallback, XmCCallback, XmRCallback,
+ sizeof(XtCallbackList), XtOffsetOf(XPDFTreeRec, tree.selectCallback),
+ XmRImmediate, (XtPointer)NULL }
+};
+
+static XmSyntheticResource synResources[] = {
+ { XmNmarginWidth, sizeof(Dimension),
+ XtOffsetOf(XPDFTreeRec, tree.marginWidth),
+#if XmVERSION > 1
+ XmeFromHorizontalPixels, XmeToHorizontalPixels
+#else
+ _XmFromHorizontalPixels, _XmToHorizontalPixels
+#endif
+ },
+ { XmNmarginHeight, sizeof(Dimension),
+ XtOffsetOf(XPDFTreeRec, tree.marginHeight),
+#if XmVERSION > 1
+ XmeFromVerticalPixels, XmeToVerticalPixels
+#else
+ _XmFromVerticalPixels, _XmToVerticalPixels
+#endif
+ }
+};
+
+static XtResource constraints[] = {
+ { XPDFNentryParent, XPDFCentryParent, XmRWidget,
+ sizeof(Widget), XtOffsetOf(XPDFTreeConstraintRec, tree.entryParent),
+ XmRImmediate, (XtPointer)NULL },
+ { XPDFNentryExpanded, XPDFCentryExpanded, XmRBoolean,
+ sizeof(Boolean), XtOffsetOf(XPDFTreeConstraintRec, tree.entryExpanded),
+ XmRImmediate, (XtPointer)False },
+ { XPDFNentryPosition, XPDFCentryPosition, XmRInt,
+ sizeof(int), XtOffsetOf(XPDFTreeConstraintRec, tree.entryPosition),
+ XmRImmediate, (XtPointer)0 }
+};
+
+static char defaultTranslations[] =
+ "<Btn1Down>: XPDFTreeClick()";
+
+static XtActionsRec actions[] = {
+ { "XPDFTreeClick", click }
+};
+
+externaldef(xpdftreeclassrec) XPDFTreeClassRec xpdfTreeClassRec = {
+ { // Core
+ (WidgetClass)&xmManagerClassRec, // superclass
+ "XPDFTree", // class_name
+ sizeof(XPDFTreeRec), // widget_size
+ NULL, // class_initialize
+ &classPartInitialize, // class_part_initialize
+ FALSE, // class_inited
+ &initialize, // initialize
+ NULL, // initialize_hook
+ XtInheritRealize, // realize
+ actions, // actions
+ XtNumber(actions), // num_actions
+ resources, // resources
+ XtNumber(resources), // num_resources
+ NULLQUARK, // xrm_class
+ TRUE, // compress_motion
+ XtExposeCompressMaximal, // compress_exposure
+ TRUE, // compress_enterleave
+ FALSE, // visible_interest
+ &destroy, // destroy
+ &resize, // resize
+ &redisplay, // expose
+ &setValues, // set_values
+ NULL, // set_values_hook
+ &setValuesAlmost, // set_values_almost
+ NULL, // get_values_hook
+ NULL, // accept_focus
+ XtVersion, // version
+ NULL, // callback_private
+ defaultTranslations, // tm_table
+ &queryGeometry, // query_geometry
+ NULL, // display_accelerator
+ NULL // extension
+ },
+ { // Composite
+ &geometryManager, // geometry_manager
+ &changeManaged, // change_managed
+ XtInheritInsertChild, // insert_child
+ XtInheritDeleteChild, // delete_child
+ NULL // extension
+ },
+ { // Constraint
+ constraints, // constraint_resources
+ XtNumber(constraints), // constraint_num_resources
+ sizeof(XPDFTreeConstraintRec), // constraint_size
+ &initConstraint, // constraint_initialize
+ &destroyConstraint, // constraint_destroy
+ &constraintSetValues, // constraint_set_values
+ NULL // extension
+ },
+ { // XmManager
+ XtInheritTranslations, // translations
+#if XmVERSION > 1
+ synResources, // syn_resources
+ XtNumber(synResources), // num_syn_resources
+#else
+ NULL, // syn_resources
+ 0, // num_syn_resources
+#endif
+ NULL, // syn_constraint_resources
+ 0, // num_syn_constraint_res's
+ XmInheritParentProcess, // parent_process
+ NULL // extension
+ },
+ { // XPDFTree
+ &createGC, // createGC
+ &destroyGC, // destroyGC
+ &layout, // layout
+ &calcSize, // calcSize
+ &needRelayout, // needRelayout
+ NULL // extension
+ }
+};
+
+externaldef(xpdftreewidgetclass) WidgetClass xpdfTreeWidgetClass =
+ (WidgetClass)&xpdfTreeClassRec;
+
+//------------------------------------------------------------------------
+
+static void classPartInitialize(WidgetClass widgetCls) {
+ XPDFTreeWidgetClass wc = (XPDFTreeWidgetClass)widgetCls;
+ XPDFTreeWidgetClass sc = (XPDFTreeWidgetClass)wc->coreClass.superclass;
+
+ // method inheritance
+ if (wc->treeClass.createGC == XPDFInheritCreateGC) {
+ wc->treeClass.createGC = sc->treeClass.createGC;
+ }
+ if (wc->treeClass.destroyGC == XPDFInheritDestroyGC) {
+ wc->treeClass.destroyGC = sc->treeClass.destroyGC;
+ }
+ if (wc->treeClass.layout == XPDFInheritLayout) {
+ wc->treeClass.layout = sc->treeClass.layout;
+ }
+ if (wc->treeClass.calcSize == XPDFInheritCalcSize) {
+ wc->treeClass.calcSize = sc->treeClass.calcSize;
+ }
+ if (wc->treeClass.needRelayout == XPDFInheritNeedRelayout) {
+ wc->treeClass.needRelayout = sc->treeClass.needRelayout;
+ }
+}
+
+static void initialize(Widget requestWidget, Widget newWidget,
+ ArgList args, Cardinal *numArgs) {
+ XPDFTreeWidget nw = (XPDFTreeWidget)newWidget;
+ XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(newWidget);
+
+ nw->tree.root = NULL;
+ nw->tree.redrawY = -1;
+ if (cls->treeClass.createGC) {
+ (*cls->treeClass.createGC)(newWidget);
+ } else {
+ createGC(newWidget);
+ }
+}
+
+static void destroy(Widget widget) {
+ XPDFTreeWidget w = (XPDFTreeWidget)widget;
+ XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
+
+ if (w->tree.root) {
+ destroySubtree(w->tree.root);
+ w->tree.root = NULL;
+ }
+ if (cls->treeClass.destroyGC) {
+ (*cls->treeClass.destroyGC)(widget);
+ } else {
+ destroyGC(widget);
+ }
+}
+
+static void destroySubtree(XPDFTreeEntry *e) {
+ if (e->children) {
+ destroySubtree(e->children);
+ }
+ if (e->next) {
+ destroySubtree(e->next);
+ }
+}
+
+static void resize(Widget widget) {
+ XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
+
+ if (cls->treeClass.layout) {
+ (*cls->treeClass.layout)(widget, NULL);
+ } else {
+ layout(widget, NULL);
+ }
+}
+
+static void redisplay(Widget widget, XEvent *event, Region region) {
+ XPDFTreeWidget w = (XPDFTreeWidget)widget;
+ XPDFTreeEntry *e;
+
+ if (w->tree.redrawY >= 0) {
+ XClearArea(XtDisplay((Widget)w), XtWindow((Widget)w),
+ 0, w->tree.redrawY, w->core.width, w->core.height, False);
+ w->tree.redrawY = -1;
+ }
+ for (e = w->tree.root; e; e = e->next) {
+ redisplaySubtree(w, e, event, region);
+ }
+}
+
+static void redisplaySubtree(XPDFTreeWidget w, XPDFTreeEntry *e,
+ XEvent *event, Region region) {
+ XPDFTreeConstraint c;
+ Position x, y, y2;
+ XPDFTreeEntry *child;
+
+ (*XtClass(e->widget)->core_class.expose)(e->widget, event, region);
+ c = XPDFTreeCPart(e->widget);
+ x = e->widget->core.x;
+ y = e->widget->core.y + e->widget->core.height / 2;
+ if (e->children) {
+ if (c->entryExpanded) {
+ drawExpandedIcon(w, x - 8, y);
+ y2 = y; // make gcc happy
+ for (child = e->children; child; child = child->next) {
+ y2 = child->widget->core.y + child->widget->core.height / 2;
+ XDrawLine(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.dottedGC,
+ x - 8, y2, x + 6, y2);
+ redisplaySubtree(w, child, event, region);
+ }
+ XDrawLine(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.dottedGC,
+ x - 8, y + 2, x - 8, y2);
+ } else {
+ drawCollapsedIcon(w, x - 8, y);
+ }
+ }
+}
+
+static void drawExpandedIcon(XPDFTreeWidget w, Position x, Position y) {
+ XPoint pts[4];
+
+ pts[0].x = x - 4; pts[0].y = y - 2;
+ pts[1].x = x + 4; pts[1].y = y - 2;
+ pts[2].x = x; pts[2].y = y + 2;
+ pts[3].x = x - 4; pts[3].y = y - 2;
+ XDrawLines(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.plainGC,
+ pts, 4, CoordModeOrigin);
+}
+
+static void drawCollapsedIcon(XPDFTreeWidget w, Position x, Position y) {
+ XPoint pts[4];
+
+ pts[0].x = x - 2; pts[0].y = y - 4;
+ pts[1].x = x - 2; pts[1].y = y + 4;
+ pts[2].x = x + 2; pts[2].y = y;
+ pts[3].x = x - 2; pts[3].y = y - 4;
+ XDrawLines(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.plainGC,
+ pts, 4, CoordModeOrigin);
+}
+
+static Boolean setValues(Widget oldWidget, Widget requestWidget,
+ Widget newWidget, ArgList args, Cardinal *numArgs) {
+ XPDFTreeWidget ow = (XPDFTreeWidget)oldWidget;
+ XPDFTreeWidget nw = (XPDFTreeWidget)newWidget;
+ XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(nw);
+ Boolean relayout, redisp;
+
+ // check to see if layout-affecting resources have changed
+ if (cls->treeClass.needRelayout) {
+ relayout = (*cls->treeClass.needRelayout)((Widget)ow, (Widget)nw);
+ } else {
+ relayout = needRelayout((Widget)ow, (Widget)nw);
+ }
+ redisp = False;
+ if (relayout) {
+
+ // calculate a new ideal size (reset the widget size first so
+ // calcSize will compute a new one)
+ if (nw->core.width == ow->core.width) {
+ nw->core.width = 0;
+ }
+ if (nw->core.height == ow->core.height) {
+ nw->core.height = 0;
+ }
+ if (cls->treeClass.calcSize) {
+ (*cls->treeClass.calcSize)((Widget)nw, NULL,
+ &nw->core.width, &nw->core.height);
+ } else {
+ calcSize((Widget)nw, NULL, &nw->core.width, &nw->core.height);
+ }
+
+ // if resources have changed but size hasn't, layout manually
+ // (because Xt just looks at the size)
+ if (nw->core.width == ow->core.width &&
+ nw->core.height == ow->core.height) {
+ if (cls->treeClass.layout) {
+ (*cls->treeClass.layout)((Widget)nw, NULL);
+ } else {
+ layout((Widget)nw, NULL);
+ }
+ redisp = True;
+ }
+ }
+
+ return redisp;
+}
+
+static void setValuesAlmost(Widget oldWidget, Widget newWidget,
+ XtWidgetGeometry *request,
+ XtWidgetGeometry *reply) {
+ XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(newWidget);
+
+ // our parent rejected a geometry request, so accept the compromise
+ // and relayout
+ if (!reply->request_mode) {
+ if (cls->treeClass.layout) {
+ (*cls->treeClass.layout)(newWidget, NULL);
+ } else {
+ layout(newWidget, NULL);
+ }
+ }
+ *request = *reply;
+}
+
+static XtGeometryResult queryGeometry(Widget widget,
+ XtWidgetGeometry *request,
+ XtWidgetGeometry *reply) {
+ XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
+
+ if (!XtIsRealized(widget)) {
+ reply->width = XtWidth(widget);
+ reply->height = XtHeight(widget);
+ } else {
+ reply->width = 0;
+ reply->height = 0;
+ }
+ if (cls->treeClass.calcSize) {
+ (*cls->treeClass.calcSize)(widget, NULL, &reply->width, &reply->height);
+ } else {
+ calcSize(widget, NULL, &reply->width, &reply->height);
+ }
+#if XmVERSION > 1
+ return XmeReplyToQueryGeometry(widget, request, reply);
+#else
+ if ((request->request_mode & CWWidth) &&
+ (request->request_mode & CWHeight) &&
+ request->width == reply->width &&
+ request->height == reply->height) {
+ return XtGeometryYes;
+ }
+ if (reply->width == XtWidth(widget) &&
+ reply->height == XtHeight(widget)) {
+ return XtGeometryNo;
+ }
+ reply->request_mode = CWWidth | CWHeight;
+ return XtGeometryAlmost;
+#endif
+}
+
+static XtGeometryResult geometryManager(Widget widget,
+ XtWidgetGeometry *request,
+ XtWidgetGeometry *reply) {
+ XPDFTreeWidget w = (XPDFTreeWidget)XtParent(widget);
+ XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(w);
+ Dimension curWidth, curHeight, curBW;
+ XtWidgetGeometry parentReq;
+ XtGeometryResult result;
+
+ // deny any requests for a new position
+ if ((request->request_mode & CWX) || (request->request_mode & CWY)) {
+ return XtGeometryNo;
+ }
+
+ // save the current geometry
+ curWidth = w->core.width;
+ curHeight = w->core.height;
+ curBW = w->core.border_width;
+
+ // make the requested changes
+ if (request->request_mode & CWWidth) {
+ w->core.width = request->width;
+ }
+ if (request->request_mode & CWHeight) {
+ w->core.height = request->height;
+ }
+ if (request->request_mode & CWBorderWidth) {
+ w->core.border_width = request->border_width;
+ }
+
+ // calculate the new ideal size
+ parentReq.width = 0;
+ parentReq.height = 0;
+ if (cls->treeClass.calcSize) {
+ (*cls->treeClass.calcSize)((Widget)w, widget,
+ &parentReq.width, &reply->height);
+ } else {
+ calcSize((Widget)w, widget, &parentReq.width, &reply->height);
+ }
+
+ // send geometry request to our parent
+ parentReq.request_mode = CWWidth | CWHeight;
+ if (request->request_mode & XtCWQueryOnly) {
+ parentReq.request_mode |= XtCWQueryOnly;
+ }
+ result = XtMakeGeometryRequest((Widget)w, &parentReq, NULL);
+ if (result == XtGeometryAlmost) {
+ result = XtGeometryNo;
+ }
+
+ if (result == XtGeometryNo || (request->request_mode & XtCWQueryOnly)) {
+ // restore the original geometry
+ w->core.width = curWidth;
+ w->core.height = curHeight;
+ w->core.border_width = curBW;
+ } else {
+ if (cls->treeClass.layout) {
+ (*cls->treeClass.layout)((Widget)w, widget);
+ } else {
+ layout((Widget)w, widget);
+ }
+ }
+
+ return result;
+}
+
+static void changeManaged(Widget widget) {
+ Dimension width, height;
+ XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
+
+ // compute the ideal size
+ if (!XtIsRealized(widget)) {
+ width = XtWidth(widget);
+ height = XtHeight(widget);
+ } else {
+ width = 0;
+ height = 0;
+ }
+ if (cls->treeClass.calcSize) {
+ (*cls->treeClass.calcSize)(widget, NULL, &width, &height);
+ } else {
+ calcSize(widget, NULL, &width, &height);
+ }
+
+ // make resize request to parent -- keep asking until we get a yes
+ // or no
+ while (XtMakeResizeRequest(widget, width, height, &width, &height)
+ == XtGeometryAlmost) ;
+
+ // relayout
+ if (cls->treeClass.layout) {
+ (*cls->treeClass.layout)(widget, NULL);
+ } else {
+ layout(widget, NULL);
+ }
+
+#if XmVERSION > 1
+ // update keyboard traversal
+ XmeNavigChangeManaged(widget);
+#else
+ _XmNavigChangeManaged(widget);
+#endif
+}
+
+static void initConstraint(Widget requestWidget, Widget newWidget,
+ ArgList args, Cardinal *numArgs) {
+ XPDFTreeWidget w = (XPDFTreeWidget)XtParent(newWidget);
+ XPDFTreeConstraint c;
+
+ c = XPDFTreeCPart(newWidget);
+ c->e = (XPDFTreeEntry *)gmalloc(sizeof(XPDFTreeEntry));
+ c->e->widget = newWidget;
+ c->e->children = NULL;
+ c->e->next = NULL;
+ if (c->entryParent) {
+ insertChildOnList(c->e, &XPDFTreeCPart(c->entryParent)->e->children);
+ } else {
+ insertChildOnList(c->e, &w->tree.root);
+ }
+}
+
+static void destroyConstraint(Widget widget) {
+ deleteSubtree(widget);
+}
+
+static void deleteSubtree(Widget widget) {
+ XPDFTreeWidget w = (XPDFTreeWidget)XtParent(widget);
+ XPDFTreeConstraint c;
+
+ c = XPDFTreeCPart(widget);
+ if (!c->e) {
+ return;
+ }
+ while (c->e->children) {
+ deleteSubtree(c->e->children->widget);
+ }
+ if (c->entryParent) {
+ deleteChildFromList(c->e, &XPDFTreeCPart(c->entryParent)->e->children);
+ } else {
+ deleteChildFromList(c->e, &w->tree.root);
+ }
+ gfree(c->e);
+ c->e = NULL;
+}
+
+static Boolean constraintSetValues(Widget oldWidget, Widget requestWidget,
+ Widget newWidget,
+ ArgList args, Cardinal *numArgs) {
+ XPDFTreeWidget w = (XPDFTreeWidget)XtParent(newWidget);
+ XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass((Widget)w);
+ XPDFTreeConstraint oc, nc;
+ Boolean relayout;
+ Dimension width, height;
+
+ if (!XtIsManaged(newWidget)) {
+ return False;
+ }
+ oc = XPDFTreeCPart(oldWidget);
+ nc = XPDFTreeCPart(newWidget);
+ relayout = False;
+ if (nc->entryParent != oc->entryParent ||
+ nc->entryPosition != oc->entryPosition) {
+ if (oc->entryParent) {
+ deleteChildFromList(oc->e, &XPDFTreeCPart(oc->entryParent)->e->children);
+ } else {
+ deleteChildFromList(oc->e, &w->tree.root);
+ }
+ if (nc->entryParent) {
+ insertChildOnList(nc->e, &XPDFTreeCPart(nc->entryParent)->e->children);
+ } else {
+ insertChildOnList(nc->e, &w->tree.root);
+ }
+ relayout = True;
+ } else if (nc->entryExpanded != oc->entryExpanded) {
+ relayout = True;
+ }
+
+ if (relayout) {
+
+ // calculate a new ideal size (reset the widget size first so
+ // calcSize will compute a new one)
+ width = 0;
+ height = 0;
+ if (cls->treeClass.calcSize) {
+ (*cls->treeClass.calcSize)((Widget)w, NULL, &width, &height);
+ } else {
+ calcSize((Widget)w, NULL, &width, &height);
+ }
+
+ // make resize request to parent -- keep asking until we get a yes
+ // or no
+ while (XtMakeResizeRequest((Widget)w, width, height, &width, &height)
+ == XtGeometryAlmost) ;
+
+ // relayout the widget
+ if (cls->treeClass.layout) {
+ (*cls->treeClass.layout)((Widget)w, NULL);
+ } else {
+ layout((Widget)w, NULL);
+ }
+ }
+
+ return relayout;
+}
+
+static void insertChildOnList(XPDFTreeEntry *e, XPDFTreeEntry **listHead) {
+ int pos;
+ XPDFTreeEntry *e2;
+
+ pos = XPDFTreeCPart(e->widget)->entryPosition;
+ if (!*listHead || pos < XPDFTreeCPart((*listHead)->widget)->entryPosition) {
+ e->next = *listHead;
+ *listHead = e;
+ } else {
+ for (e2 = *listHead;
+ e2->next && pos >= XPDFTreeCPart(e2->next->widget)->entryPosition;
+ e2 = e2->next) ;
+ e->next = e2->next;
+ e2->next = e;
+ }
+}
+
+static void deleteChildFromList(XPDFTreeEntry *e, XPDFTreeEntry **listHead) {
+ XPDFTreeEntry **p;
+
+ for (p = listHead; *p; p = &(*p)->next) {
+ if (*p == e) {
+ *p = e->next;
+ e->next = NULL;
+ return;
+ }
+ }
+}
+
+static void createGC(Widget widget) {
+ XPDFTreeWidget w = (XPDFTreeWidget)widget;
+ XGCValues gcValues;
+
+ gcValues.foreground = w->manager.foreground;
+ gcValues.line_width = 0;
+ gcValues.line_style = LineSolid;
+ w->tree.plainGC = XtGetGC(widget,
+ GCForeground | GCLineWidth | GCLineStyle,
+ &gcValues);
+
+ gcValues.line_style = LineOnOffDash;
+ gcValues.dashes = 1;
+ gcValues.dash_offset = 0;
+ w->tree.dottedGC = XtGetGC(widget,
+ GCForeground | GCLineWidth | GCLineStyle |
+ GCDashList | GCDashOffset,
+ &gcValues);
+}
+
+static void destroyGC(Widget widget) {
+ XPDFTreeWidget w = (XPDFTreeWidget)widget;
+
+ XtReleaseGC(widget, w->tree.plainGC);
+ XtReleaseGC(widget, w->tree.dottedGC);
+}
+
+static void layout(Widget widget, Widget instigator) {
+ XPDFTreeWidget w = (XPDFTreeWidget)widget;
+ XPDFTreeEntry *e;
+ Position x, y;
+
+ x = w->tree.marginWidth + xpdfTreeIndent;
+ y = w->tree.marginHeight;
+ for (e = w->tree.root; e; e = e->next) {
+ y = layoutSubtree(w, instigator, e, x, y, True);
+ }
+}
+
+static int layoutSubtree(XPDFTreeWidget w, Widget instigator,
+ XPDFTreeEntry *e, Position x, Position y,
+ Boolean visible) {
+ Widget ew;
+ XPDFTreeEntry *child;
+ XPDFTreeConstraint c;
+
+ ew = e->widget;
+ if (!XtIsManaged(ew)) {
+ return y;
+ }
+ c = XPDFTreeCPart(ew);
+
+ // place this entry
+ if (ew) {
+ if (visible) {
+ if (ew == instigator) {
+ ew->core.x = x;
+ ew->core.y = y;
+ } else {
+#if XmVERSION > 1
+ XmeConfigureObject(ew, x, y, ew->core.width, ew->core.height,
+ ew->core.border_width);
+#else
+ _XmConfigureObject(ew, x, y, ew->core.width, ew->core.height,
+ ew->core.border_width);
+#endif
+ }
+ y += ew->core.height + 2 * ew->core.border_width;
+ }
+ }
+
+ // place this entry's children
+ x += xpdfTreeIndent;
+ for (child = e->children; child; child = child->next) {
+ y = layoutSubtree(w, instigator, child, x, y,
+ visible && (!c || c->entryExpanded));
+ }
+
+ return y;
+}
+
+static void calcSize(Widget widget, Widget instigator,
+ Dimension *totalWidth,
+ Dimension *totalHeight) {
+ XPDFTreeWidget w = (XPDFTreeWidget)widget;
+ XPDFTreeEntry *e;
+ Dimension w1, h1, w2, h2;
+
+ w1 = h1 = 0;
+ for (e = w->tree.root; e; e = e->next) {
+ calcSubtreeSize(w, instigator, e, &w2, &h2);
+ if (w2 > w1) {
+ w1 = w2;
+ }
+ h1 += h2;
+ }
+ w1 += xpdfTreeIndent + 2 * w->tree.marginWidth;
+ h1 += 2 * w->tree.marginHeight;
+ if (h1 == 0) {
+ h1 = 1;
+ }
+ if (!*totalWidth) {
+ *totalWidth = w1;
+ }
+ if (!*totalHeight) {
+ *totalHeight = h1;
+ }
+}
+
+static void calcSubtreeSize(XPDFTreeWidget w, Widget instigator,
+ XPDFTreeEntry *e,
+ Dimension *width, Dimension *height) {
+ Widget ew;
+ XPDFTreeEntry *child;
+ XPDFTreeConstraint c;
+ XtWidgetGeometry geom;
+ Dimension w1, h1, w2, h2;
+
+ ew = e->widget;
+ if (!XtIsManaged(ew)) {
+ *width = *height = 0;
+ return;
+ }
+ c = XPDFTreeCPart(ew);
+
+ // get size of this entry
+ if (ew) {
+ if (!XtIsManaged(ew)) {
+ *width = *height = 0;
+ return;
+ }
+ if (ew == instigator) {
+ w1 = ew->core.width;
+ h1 = ew->core.height;
+ } else {
+ XtQueryGeometry(ew, NULL, &geom);
+ w1 = (geom.request_mode & CWWidth) ? geom.width : ew->core.width;
+ h1 = (geom.request_mode & CWHeight) ? geom.height : ew->core.height;
+ }
+ h1 += 2 * ew->core.border_width;
+ } else {
+ // root of tree
+ w1 = 0;
+ h1 = 0;
+ }
+
+ // if this entry is expanded, get size of all of its children
+ if (c->entryExpanded) {
+ for (child = e->children; child; child = child->next) {
+ calcSubtreeSize(w, instigator, child, &w2, &h2);
+ w2 += xpdfTreeIndent;
+ if (w2 > w1) {
+ w1 = w2;
+ }
+ h1 += h2;
+ }
+ }
+
+ *width = w1;
+ *height = h1;
+}
+
+static Boolean needRelayout(Widget oldWidget, Widget newWidget) {
+ XPDFTreeWidget ow = (XPDFTreeWidget)oldWidget;
+ XPDFTreeWidget nw = (XPDFTreeWidget)newWidget;
+
+ if (nw->tree.marginWidth != ow->tree.marginWidth ||
+ nw->tree.marginHeight != ow->tree.marginHeight) {
+ return True;
+ }
+ return False;
+}
+
+static void click(Widget widget, XEvent *event,
+ String *params, Cardinal *numParams) {
+ XPDFTreeWidget w = (XPDFTreeWidget)widget;
+ XButtonPressedEvent *bpe;
+ XPDFTreeEntry *e;
+ Boolean onExpandIcon;
+ XPDFTreeConstraint c;
+ XPDFTreeSelectCallbackStruct cbs;
+
+ if (event->type != ButtonPress) {
+ return;
+ }
+ bpe = (XButtonPressedEvent *)event;
+ if (findPosition(w, bpe->x, bpe->y, &e, &onExpandIcon)) {
+ if (onExpandIcon) {
+ c = XPDFTreeCPart(e->widget);
+ w->tree.redrawY = e->widget->core.y;
+ XtVaSetValues(e->widget, XPDFNentryExpanded, !c->entryExpanded, NULL);
+ } else {
+ XmProcessTraversal(e->widget, XmTRAVERSE_CURRENT);
+ XtCallActionProc(widget, "ManagerGadgetActivate", event, NULL, 0);
+ cbs.reason = XmCR_ACTIVATE;
+ cbs.event = event;
+ cbs.selectedItem = e->widget;
+ XtCallCallbackList(widget, w->tree.selectCallback, &cbs);
+ }
+ }
+}
+
+static Boolean findPosition(XPDFTreeWidget w, int x, int y,
+ XPDFTreeEntry **e, Boolean *onExpandIcon) {
+ XPDFTreeEntry *e2;
+
+ for (e2 = w->tree.root; e2; e2 = e2->next) {
+ *e = e2;
+ if (findPositionInSubtree(w, x, y, e, onExpandIcon)) {
+ return True;
+ }
+ }
+ return False;
+}
+
+// If (x,y) falls on either an expand/collapse icon or a label gadget,
+// set *<e> and *<onExpandIcon> and return true.
+static Boolean findPositionInSubtree(XPDFTreeWidget w, int x, int y,
+ XPDFTreeEntry **e,
+ Boolean *onExpandIcon) {
+ Widget child;
+ XPDFTreeConstraint c;
+ XPDFTreeEntry *e2;
+ int y1;
+
+ child = (*e)->widget;
+ y1 = child->core.y + child->core.height / 2;
+ if (x >= child->core.x && x < child->core.x + child->core.width &&
+ y >= child->core.y && y < child->core.y + child->core.height) {
+ *onExpandIcon = False;
+ return True;
+ } else if (x >= child->core.x - 16 && x < child->core.x - 4 &&
+ y >= y1 - 6 && y < y1 + 6 &&
+ (*e)->children) {
+ *onExpandIcon = True;
+ return True;
+ }
+ c = XPDFTreeCPart(child);
+ if (!c || c->entryExpanded) {
+ for (e2 = (*e)->children; e2; e2 = e2->next) {
+ *e = e2;
+ if (findPositionInSubtree(w, x, y, e, onExpandIcon)) {
+ return True;
+ }
+ }
+ }
+ return False;
+}
+
+Widget XPDFCreateTree(Widget parent, char *name,
+ ArgList argList, Cardinal numArgs) {
+ return XtCreateWidget(name, xpdfTreeWidgetClass, parent, argList, numArgs);
+}
diff --git a/pdf/xpdf/XPDFTree.h b/pdf/xpdf/XPDFTree.h
new file mode 100644
index 0000000..d569f49
--- /dev/null
+++ b/pdf/xpdf/XPDFTree.h
@@ -0,0 +1,43 @@
+//========================================================================
+//
+// XPDFTree.h
+//
+//========================================================================
+
+#ifndef XPDFTREE_H
+#define XPDFTREE_H
+
+#include <Xm/Xm.h>
+
+extern "C" {
+
+externalref WidgetClass xpdfTreeWidgetClass;
+
+typedef struct _XPDFTreeClassRec *XPDFTreeWidgetClass;
+typedef struct _XPDFTreeRec *XPDFTreeWidget;
+
+#ifndef XPDFIsTree
+#define XPDFIsTree(w) XtIsSubclass(w, xpdfTreeWidgetClass)
+#endif
+
+#define XPDFNentryParent "entryParent"
+#define XPDFNentryExpanded "entryExpanded"
+#define XPDFNentryPosition "entryPosition"
+#define XPDFNselectionCallback "selectionCallback"
+
+#define XPDFCentryParent "EntryParent"
+#define XPDFCentryExpanded "EntryExpanded"
+#define XPDFCentryPosition "EntryPosition"
+
+typedef struct {
+ int reason;
+ XEvent *event;
+ Widget selectedItem;
+} XPDFTreeSelectCallbackStruct;
+
+extern Widget XPDFCreateTree(Widget parent, char *name,
+ ArgList argList, Cardinal argCount);
+
+} // extern "C"
+
+#endif
diff --git a/pdf/xpdf/XPDFTreeP.h b/pdf/xpdf/XPDFTreeP.h
new file mode 100644
index 0000000..16ab137
--- /dev/null
+++ b/pdf/xpdf/XPDFTreeP.h
@@ -0,0 +1,85 @@
+//========================================================================
+//
+// XPDFTreeP.h
+//
+//========================================================================
+
+#ifndef XPDFTREEP_H
+#define XPDFTREEP_H
+
+#include <Xm/ManagerP.h>
+#include "XPDFTree.h"
+
+extern "C" {
+
+typedef void (*XPDFLayoutProc)(Widget widget, Widget instigator);
+typedef void (*XPDFCalcSizeProc)(Widget widget, Widget instigator,
+ Dimension *totalWidth,
+ Dimension *totalHeight);
+typedef Boolean (*XPDFNeedRelayoutProc)(Widget oldWidget, Widget newWidget);
+
+#define XPDFInheritCreateGC ((XtWidgetProc)_XtInherit)
+#define XPDFInheritDestroyGC ((XtWidgetProc)_XtInherit)
+#define XPDFInheritLayout ((XPDFLayoutProc)_XtInherit)
+#define XPDFInheritCalcSize ((XPDFCalcSizeProc)_XtInherit)
+#define XPDFInheritNeedRelayout ((XPDFNeedRelayoutProc)_XtInherit)
+
+typedef struct {
+ XtWidgetProc createGC;
+ XtWidgetProc destroyGC;
+ XPDFLayoutProc layout;
+ XPDFCalcSizeProc calcSize;
+ XPDFNeedRelayoutProc needRelayout;
+ XtPointer extension;
+} XPDFTreeClassPart;
+
+typedef struct _XPDFTreeClassRec {
+ CoreClassPart coreClass;
+ CompositeClassPart compositeClass;
+ ConstraintClassPart constraintClass;
+ XmManagerClassPart managerClass;
+ XPDFTreeClassPart treeClass;
+} XPDFTreeClassRec;
+
+externalref XPDFTreeClassRec xpdfTreeClassRec;
+
+typedef struct _XPDFTreeEntry XPDFTreeEntry;
+
+typedef struct {
+ Dimension marginWidth;
+ Dimension marginHeight;
+ XtCallbackList selectCallback;
+ GC plainGC;
+ GC dottedGC;
+ XPDFTreeEntry *root;
+ int redrawY;
+} XPDFTreePart;
+
+typedef struct _XPDFTreeRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ XmManagerPart manager;
+ XPDFTreePart tree;
+} XPDFTreeRec;
+
+#define XPDFTreeIndex (XmManagerIndex + 1)
+
+typedef struct _XPDFTreeConstraintPart {
+ Widget entryParent;
+ Boolean entryExpanded;
+ int entryPosition;
+ XPDFTreeEntry *e;
+} XPDFTreeConstraintPart, *XPDFTreeConstraint;
+
+typedef struct _XPDFTreeConstraintRec {
+ XmManagerConstraintPart manager;
+ XPDFTreeConstraintPart tree;
+} XPDFTreeConstraintRec, *XPDFTreeConstraintPtr;
+
+#define XPDFTreeCPart(w) \
+ (&((XPDFTreeConstraintPtr)(w)->core.constraints)->tree)
+
+} // extern "C"
+
+#endif
diff --git a/pdf/xpdf/XPDFViewer.cc b/pdf/xpdf/XPDFViewer.cc
new file mode 100644
index 0000000..a8c8f8f
--- /dev/null
+++ b/pdf/xpdf/XPDFViewer.cc
@@ -0,0 +1,2318 @@
+//========================================================================
+//
+// XPDFViewer.cc
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <X11/cursorfont.h>
+#ifdef HAVE_X11_XPM_H
+#include <X11/xpm.h>
+#endif
+#include "gmem.h"
+#include "gfile.h"
+#include "GString.h"
+#include "GList.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "PDFDoc.h"
+#include "ErrorCodes.h"
+#include "Outline.h"
+#include "UnicodeMap.h"
+#ifndef DISABLE_OUTLINE
+#define Object XtObject
+#include "XPDFTree.h"
+#undef Object
+#endif
+#include "XPDFApp.h"
+#include "XPDFViewer.h"
+#include "XPixmapOutputDev.h"
+#include "PSOutputDev.h"
+#include "config.h"
+
+// these macro defns conflict with xpdf's Object class
+#ifdef LESSTIF_VERSION
+#undef XtDisplay
+#undef XtScreen
+#undef XtWindow
+#undef XtParent
+#undef XtIsRealized
+#endif
+
+#if XmVERSION <= 1
+#define XmSET True
+#define XmUNSET False
+#endif
+
+//------------------------------------------------------------------------
+// GUI includes
+//------------------------------------------------------------------------
+
+#include "xpdfIcon.xpm"
+#include "leftArrow.xbm"
+#include "leftArrowDis.xbm"
+#include "dblLeftArrow.xbm"
+#include "dblLeftArrowDis.xbm"
+#include "rightArrow.xbm"
+#include "rightArrowDis.xbm"
+#include "dblRightArrow.xbm"
+#include "dblRightArrowDis.xbm"
+#include "backArrow.xbm"
+#include "backArrowDis.xbm"
+#include "forwardArrow.xbm"
+#include "forwardArrowDis.xbm"
+#include "find.xbm"
+#include "findDis.xbm"
+#include "print.xbm"
+#include "printDis.xbm"
+#include "about.xbm"
+#include "about-text.h"
+
+//------------------------------------------------------------------------
+
+XPDFViewer::XPDFViewer(XPDFApp *appA, GString *fileName,
+ int pageA, GString *destName,
+ GString *ownerPassword, GString *userPassword) {
+ LinkDest *dest;
+ int pg, z;
+ GString *dir;
+
+ app = appA;
+ win = NULL;
+ core = NULL;
+ password = NULL;
+ ok = gFalse;
+#ifndef DISABLE_OUTLINE
+ outlineLabels = NULL;
+ outlineLabelsLength = outlineLabelsSize = 0;
+#endif
+
+ // do Motif-specific initialization and create the window;
+ // this also creates the core object
+ initWindow();
+ initAboutDialog();
+ initOpenDialog();
+ initFindDialog();
+ initSaveAsDialog();
+ initPrintDialog();
+ initPasswordDialog();
+
+ dest = NULL; // make gcc happy
+ pg = pageA; // make gcc happy
+
+ if (fileName) {
+ if (loadFile(fileName, ownerPassword, userPassword)) {
+ getPageAndDest(pageA, destName, &pg, &dest);
+ if (pg > 0) {
+ core->resizeToPage(pg);
+ }
+ dir = makePathAbsolute(grabPath(fileName->getCString()));
+ setOpenDialogDir(dir->getCString());
+ setSaveAsDialogDir(dir->getCString());
+ delete dir;
+ } else {
+ return;
+ }
+ }
+
+ // map the window -- we do this after calling resizeToPage to avoid
+ // an annoying on-screen resize
+ mapWindow();
+
+ // display the first page
+ z = app->getFullScreen() ? zoomPage : core->getZoom();
+ if (dest) {
+ displayDest(dest, z, core->getRotate(), gTrue);
+ delete dest;
+ } else {
+ displayPage(pg, z, core->getRotate(), gTrue, gTrue);
+ }
+
+ ok = gTrue;
+}
+
+XPDFViewer::~XPDFViewer() {
+ delete core;
+ XmFontListFree(aboutBigFont);
+ XmFontListFree(aboutVersionFont);
+ XmFontListFree(aboutFixedFont);
+ closeWindow();
+#ifndef DISABLE_OUTLINE
+ if (outlineLabels) {
+ gfree(outlineLabels);
+ }
+#endif
+ if (password) {
+ delete password;
+ }
+}
+
+void XPDFViewer::open(GString *fileName, int pageA, GString *destName) {
+ LinkDest *dest;
+ int pg, z;
+
+ if (!core->getDoc() || fileName->cmp(core->getDoc()->getFileName())) {
+ if (!loadFile(fileName, NULL, NULL)) {
+ return;
+ }
+ }
+ getPageAndDest(pageA, destName, &pg, &dest);
+ z = app->getFullScreen() ? zoomPage : core->getZoom();
+ if (dest) {
+ displayDest(dest, z, core->getRotate(), gTrue);
+ delete dest;
+ } else {
+ displayPage(pg, z, core->getRotate(), gTrue, gTrue);
+ }
+}
+
+void XPDFViewer::clear() {
+ char *title;
+ XmString s;
+
+ core->clear();
+
+ // set up title, number-of-pages display
+ title = app->getTitle() ? app->getTitle()->getCString()
+ : (char *)xpdfAppName;
+ XtVaSetValues(win, XmNtitle, title, XmNiconName, title, NULL);
+ s = XmStringCreateLocalized("");
+ XtVaSetValues(pageNumText, XmNlabelString, s, NULL);
+ XmStringFree(s);
+ s = XmStringCreateLocalized(" of 0");
+ XtVaSetValues(pageCountLabel, XmNlabelString, s, NULL);
+ XmStringFree(s);
+
+ // disable buttons
+ XtVaSetValues(prevTenPageBtn, XmNsensitive, False, NULL);
+ XtVaSetValues(prevPageBtn, XmNsensitive, False, NULL);
+ XtVaSetValues(nextTenPageBtn, XmNsensitive, False, NULL);
+ XtVaSetValues(nextPageBtn, XmNsensitive, False, NULL);
+}
+
+//------------------------------------------------------------------------
+// load / display
+//------------------------------------------------------------------------
+
+GBool XPDFViewer::loadFile(GString *fileName, GString *ownerPassword,
+ GString *userPassword) {
+ return core->loadFile(fileName, ownerPassword, userPassword) == errNone;
+}
+
+void XPDFViewer::reloadFile() {
+ int pg;
+
+ if (!core->getDoc()) {
+ return;
+ }
+ pg = core->getPageNum();
+ loadFile(core->getDoc()->getFileName());
+ if (pg > core->getDoc()->getNumPages()) {
+ pg = core->getDoc()->getNumPages();
+ }
+ displayPage(pg, core->getZoom(), core->getRotate(), gFalse, gFalse);
+}
+
+void XPDFViewer::displayPage(int pageA, int zoomA, int rotateA,
+ GBool scrollToTop, GBool addToHist) {
+ core->displayPage(pageA, zoomA, rotateA, scrollToTop, addToHist);
+}
+
+void XPDFViewer::displayDest(LinkDest *dest, int zoomA, int rotateA,
+ GBool addToHist) {
+ core->displayDest(dest, zoomA, rotateA, addToHist);
+}
+
+void XPDFViewer::getPageAndDest(int pageA, GString *destName,
+ int *pageOut, LinkDest **destOut) {
+ Ref pageRef;
+
+ // find the page number for a named destination
+ *pageOut = pageA;
+ *destOut = NULL;
+ if (destName && (*destOut = core->getDoc()->findDest(destName))) {
+ if ((*destOut)->isPageRef()) {
+ pageRef = (*destOut)->getPageRef();
+ *pageOut = core->getDoc()->findPage(pageRef.num, pageRef.gen);
+ } else {
+ *pageOut = (*destOut)->getPageNum();
+ }
+ }
+
+ if (*pageOut <= 0) {
+ *pageOut = 1;
+ }
+ if (*pageOut > core->getDoc()->getNumPages()) {
+ *pageOut = core->getDoc()->getNumPages();
+ }
+}
+
+//------------------------------------------------------------------------
+// password dialog
+//------------------------------------------------------------------------
+
+GString *XPDFViewer::reqPasswordCbk(void *data, GBool again) {
+ XPDFViewer *viewer = (XPDFViewer *)data;
+
+ viewer->getPassword(again);
+ return viewer->password;
+}
+
+//------------------------------------------------------------------------
+// actions
+//------------------------------------------------------------------------
+
+void XPDFViewer::actionCbk(void *data, char *action) {
+ XPDFViewer *viewer = (XPDFViewer *)data;
+
+ if (!strcmp(action, "Quit")) {
+ viewer->app->quit();
+ }
+}
+
+//------------------------------------------------------------------------
+// keyboard/mouse input
+//------------------------------------------------------------------------
+
+void XPDFViewer::keyPressCbk(void *data, char *s, KeySym key,
+ Guint modifiers) {
+ XPDFViewer *viewer = (XPDFViewer *)data;
+ int z;
+
+ if (s[0]) {
+ switch (s[0]) {
+ case 'O':
+ case 'o':
+ viewer->mapOpenDialog(gFalse);
+ break;
+ case 'R':
+ case 'r':
+ viewer->reloadFile();
+ break;
+ case 'F':
+ case 'f':
+ case '\006': // ctrl-F
+ if (viewer->core->getDoc()) {
+ XtManageChild(viewer->findDialog);
+ }
+ break;
+ case '\007': // ctrl-G
+ if (viewer->core->getDoc()) {
+ XPDFViewer::findFindCbk(None, viewer, NULL);
+ }
+ break;
+ case '\020': // ctrl-P
+ if (viewer->core->getDoc()) {
+ XtManageChild(viewer->printDialog);
+ }
+ break;
+ case 'N':
+ case 'n':
+ viewer->core->gotoNextPage(1, !(modifiers & Mod5Mask));
+ break;
+ case 'P':
+ case 'p':
+ viewer->core->gotoPrevPage(1, !(modifiers & Mod5Mask), gFalse);
+ break;
+ case ' ':
+ if (viewer->app->getFullScreen()) {
+ viewer->core->gotoNextPage(1, gTrue);
+ } else {
+ viewer->core->scrollPageDown();
+ }
+ break;
+ case '\b': // bs
+ case '\177': // del
+ if (viewer->app->getFullScreen()) {
+ viewer->core->gotoPrevPage(1, gTrue, gFalse);
+ } else {
+ viewer->core->scrollPageUp();
+ }
+ break;
+ case 'v':
+ viewer->core->goForward();
+ break;
+ case 'b':
+ viewer->core->goBackward();
+ break;
+ case 'g':
+ if (!viewer->app->getFullScreen()) {
+ XmTextFieldSetSelection(
+ viewer->pageNumText, 0,
+ strlen(XmTextFieldGetString(viewer->pageNumText)),
+ XtLastTimestampProcessed(viewer->display));
+ XmProcessTraversal(viewer->pageNumText, XmTRAVERSE_CURRENT);
+ }
+ break;
+ case 'h': // vi-style left
+ if (!viewer->app->getFullScreen() && viewer->app->getViKeys()) {
+ viewer->core->scrollLeft();
+ }
+ break;
+ case 'l': // vi-style right
+ if (!viewer->app->getFullScreen() && viewer->app->getViKeys()) {
+ viewer->core->scrollRight();
+ }
+ break;
+ case 'k': // vi-style up
+ if (!viewer->app->getFullScreen() && viewer->app->getViKeys()) {
+ viewer->core->scrollUp();
+ }
+ break;
+ case 'j': // vi-style down
+ if (!viewer->app->getFullScreen() && viewer->app->getViKeys()) {
+ viewer->core->scrollDown();
+ }
+ break;
+ case '0':
+ if (!viewer->app->getFullScreen() &&
+ viewer->core->getZoom() != defZoom) {
+ XtVaSetValues(viewer->zoomMenu,
+ XmNmenuHistory, viewer->getZoomMenuBtn(defZoom),
+ NULL);
+ viewer->displayPage(viewer->core->getPageNum(), defZoom,
+ viewer->core->getRotate(), gTrue, gFalse);
+ }
+ break;
+ case '+':
+ if (!viewer->app->getFullScreen() &&
+ viewer->core->getZoom() >= minZoom &&
+ viewer->core->getZoom() < maxZoom) {
+ z = viewer->core->getZoom() + 1;
+ XtVaSetValues(viewer->zoomMenu,
+ XmNmenuHistory, viewer->getZoomMenuBtn(z),
+ NULL);
+ viewer->displayPage(viewer->core->getPageNum(), z,
+ viewer->core->getRotate(), gTrue, gFalse);
+ }
+ break;
+ case '-':
+ if (!viewer->app->getFullScreen() &&
+ viewer->core->getZoom() > minZoom &&
+ viewer->core->getZoom() <= maxZoom) {
+ z = viewer->core->getZoom() - 1;
+ XtVaSetValues(viewer->zoomMenu,
+ XmNmenuHistory, viewer->getZoomMenuBtn(z),
+ NULL);
+ viewer->displayPage(viewer->core->getPageNum(), z,
+ viewer->core->getRotate(), gTrue, gFalse);
+ }
+ break;
+ case 'z':
+ if (!viewer->app->getFullScreen() &&
+ viewer->core->getZoom() != zoomPage) {
+ XtVaSetValues(viewer->zoomMenu,
+ XmNmenuHistory, viewer->getZoomMenuBtn(zoomPage),
+ NULL);
+ viewer->displayPage(viewer->core->getPageNum(), zoomPage,
+ viewer->core->getRotate(), gTrue, gFalse);
+ }
+ break;
+ case 'w':
+ if (!viewer->app->getFullScreen() &&
+ viewer->core->getZoom() != zoomWidth) {
+ XtVaSetValues(viewer->zoomMenu,
+ XmNmenuHistory, viewer->getZoomMenuBtn(zoomWidth),
+ NULL);
+ viewer->displayPage(viewer->core->getPageNum(), zoomWidth,
+ viewer->core->getRotate(), gTrue, gFalse);
+ }
+ break;
+ case '\014': // ^L
+ viewer->displayPage(viewer->core->getPageNum(), viewer->core->getZoom(),
+ viewer->core->getRotate(), gFalse, gFalse);
+ break;
+ case '\027': // ^W
+ viewer->app->close(viewer, gFalse);
+ break;
+ case '?':
+ XtManageChild(viewer->aboutDialog);
+ break;
+ case 'Q':
+ case 'q':
+ viewer->app->quit();
+ break;
+ }
+ }
+}
+
+void XPDFViewer::mouseCbk(void *data, XEvent *event) {
+ XPDFViewer *viewer = (XPDFViewer *)data;
+
+ if (event->type == ButtonPress && event->xbutton.button == 3) {
+ XmMenuPosition(viewer->popupMenu, &event->xbutton);
+ XtManageChild(viewer->popupMenu);
+ }
+}
+
+//------------------------------------------------------------------------
+// GUI code: main window
+//------------------------------------------------------------------------
+
+void XPDFViewer::initWindow() {
+ Widget btn, label, menuPane, lastBtn;
+#ifndef DISABLE_OUTLINE
+ Widget clipWin;
+#endif
+ Colormap colormap;
+ XColor xcol;
+ Arg args[20];
+ int n;
+ char *title;
+ XmString s, s2, emptyString;
+ char buf[16];
+ int i;
+
+ display = XtDisplay(app->getAppShell());
+ screenNum = XScreenNumberOfScreen(XtScreen(app->getAppShell()));
+
+ // private colormap
+ if (app->getInstallCmap()) {
+ XtVaGetValues(app->getAppShell(), XmNcolormap, &colormap, NULL);
+ // ensure that BlackPixel and WhitePixel are reserved in the
+ // new colormap
+ xcol.red = xcol.green = xcol.blue = 0;
+ XAllocColor(display, colormap, &xcol);
+ xcol.red = xcol.green = xcol.blue = 65535;
+ XAllocColor(display, colormap, &xcol);
+ colormap = XCopyColormapAndFree(display, colormap);
+ }
+
+ // top-level window
+ n = 0;
+ title = app->getTitle() ? app->getTitle()->getCString()
+ : (char *)xpdfAppName;
+ XtSetArg(args[n], XmNtitle, title); ++n;
+ XtSetArg(args[n], XmNiconName, title); ++n;
+ XtSetArg(args[n], XmNminWidth, 100); ++n;
+ XtSetArg(args[n], XmNminHeight, 100); ++n;
+ XtSetArg(args[n], XmNbaseWidth, 0); ++n;
+ XtSetArg(args[n], XmNbaseHeight, 0); ++n;
+ XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); ++n;
+ if (app->getFullScreen()) {
+ XtSetArg(args[n], XmNmwmDecorations, 0); ++n;
+ XtSetArg(args[n], XmNgeometry, "+0+0"); ++n;
+ } else if (app->getGeometry()) {
+ XtSetArg(args[n], XmNgeometry, app->getGeometry()->getCString()); ++n;
+ }
+ win = XtCreatePopupShell("win", topLevelShellWidgetClass,
+ app->getAppShell(), args, n);
+ if (app->getInstallCmap()) {
+ XtVaSetValues(win, XmNcolormap, colormap, NULL);
+ }
+ XmAddWMProtocolCallback(win, XInternAtom(display, "WM_DELETE_WINDOW", False),
+ &closeMsgCbk, this);
+
+ // form
+ n = 0;
+ form = XmCreateForm(win, "form", args, n);
+ XtManageChild(form);
+
+ // toolbar
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ toolBar = XmCreateForm(form, "toolBar", args, n);
+ XtManageChild(toolBar);
+
+ // create an empty string -- this is used for buttons that will get
+ // pixmaps later
+ emptyString = XmStringCreateLocalized("");
+
+ // page movement buttons
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 6); ++n;
+ XtSetArg(args[n], XmNsensitive, False); ++n;
+ XtSetArg(args[n], XmNlabelString, emptyString); ++n;
+ backBtn = XmCreatePushButton(toolBar, "back", args, n);
+ XtManageChild(backBtn);
+ XtAddCallback(backBtn, XmNactivateCallback,
+ &backCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, backBtn); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 6); ++n;
+ XtSetArg(args[n], XmNsensitive, False); ++n;
+ XtSetArg(args[n], XmNlabelString, emptyString); ++n;
+ prevTenPageBtn = XmCreatePushButton(toolBar, "prevTenPage", args, n);
+ XtManageChild(prevTenPageBtn);
+ XtAddCallback(prevTenPageBtn, XmNactivateCallback,
+ &prevTenPageCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, prevTenPageBtn); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 6); ++n;
+ XtSetArg(args[n], XmNsensitive, False); ++n;
+ XtSetArg(args[n], XmNlabelString, emptyString); ++n;
+ prevPageBtn = XmCreatePushButton(toolBar, "prevPage", args, n);
+ XtManageChild(prevPageBtn);
+ XtAddCallback(prevPageBtn, XmNactivateCallback,
+ &prevPageCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, prevPageBtn); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 6); ++n;
+ XtSetArg(args[n], XmNsensitive, False); ++n;
+ XtSetArg(args[n], XmNlabelString, emptyString); ++n;
+ nextPageBtn = XmCreatePushButton(toolBar, "nextPage", args, n);
+ XtManageChild(nextPageBtn);
+ XtAddCallback(nextPageBtn, XmNactivateCallback,
+ &nextPageCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, nextPageBtn); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 6); ++n;
+ XtSetArg(args[n], XmNsensitive, False); ++n;
+ XtSetArg(args[n], XmNlabelString, emptyString); ++n;
+ nextTenPageBtn = XmCreatePushButton(toolBar, "nextTenPage", args, n);
+ XtManageChild(nextTenPageBtn);
+ XtAddCallback(nextTenPageBtn, XmNactivateCallback,
+ &nextTenPageCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, nextTenPageBtn); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 6); ++n;
+ XtSetArg(args[n], XmNsensitive, False); ++n;
+ XtSetArg(args[n], XmNlabelString, emptyString); ++n;
+ forwardBtn = XmCreatePushButton(toolBar, "forward", args, n);
+ XtManageChild(forwardBtn);
+ XtAddCallback(forwardBtn, XmNactivateCallback,
+ &forwardCbk, (XtPointer)this);
+
+ // page number display
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, forwardBtn); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ s = XmStringCreateLocalized("Page ");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ label = XmCreateLabel(toolBar, "pageLabel", args, n);
+ XmStringFree(s);
+ XtManageChild(label);
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, label); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 3); ++n;
+ XtSetArg(args[n], XmNmarginHeight, 3); ++n;
+ XtSetArg(args[n], XmNcolumns, 5); ++n;
+ pageNumText = XmCreateTextField(toolBar, "pageNum", args, n);
+ XtManageChild(pageNumText);
+ XtAddCallback(pageNumText, XmNactivateCallback,
+ &pageNumCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, pageNumText); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ s = XmStringCreateLocalized(" of 00000");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); ++n;
+ XtSetArg(args[n], XmNrecomputeSize, False); ++n;
+ pageCountLabel = XmCreateLabel(toolBar, "pageCountLabel", args, n);
+ XmStringFree(s);
+ XtManageChild(pageCountLabel);
+ s = XmStringCreateLocalized(" of 0");
+ XtVaSetValues(pageCountLabel, XmNlabelString, s, NULL);
+ XmStringFree(s);
+
+ // zoom menu
+ n = 0;
+ menuPane = XmCreatePulldownMenu(toolBar, "zoomMenuPane", args, n);
+ for (i = minZoom; i <= maxZoom; ++i) {
+ n = 0;
+ sprintf(buf, "%s%d", i > 0 ? "+" : "", i);
+ s = XmStringCreateLocalized(buf);
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNuserData, (XtPointer)i); ++n;
+ sprintf(buf, "zoom%s%d", i < 0 ? "M" : "", i < 0 ? -i : i);
+ btn = XmCreatePushButton(menuPane, buf, args, n);
+ XmStringFree(s);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &zoomMenuCbk, (XtPointer)this);
+ zoomMenuBtns[i - minZoom] = btn;
+ }
+ n = 0;
+ s = XmStringCreateLocalized("fit page");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNuserData, (XtPointer)zoomPage); ++n;
+ btn = XmCreatePushButton(menuPane, "zoomPage", args, n);
+ XmStringFree(s);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &zoomMenuCbk, (XtPointer)this);
+ zoomMenuBtns[maxZoom - minZoom + 1] = btn;
+ n = 0;
+ s = XmStringCreateLocalized("fit width");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNuserData, (XtPointer)zoomWidth); ++n;
+ btn = XmCreatePushButton(menuPane, "zoomWidth", args, n);
+ XmStringFree(s);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &zoomMenuCbk, (XtPointer)this);
+ zoomMenuBtns[maxZoom - minZoom + 2] = btn;
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, pageCountLabel); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 0); ++n;
+ XtSetArg(args[n], XmNmarginHeight, 0); ++n;
+ XtSetArg(args[n], XmNsubMenuId, menuPane); ++n;
+ zoomMenu = XmCreateOptionMenu(toolBar, "zoomMenu", args, n);
+ XtManageChild(zoomMenu);
+
+ // find/print/about buttons
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, zoomMenu); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 6); ++n;
+ XtSetArg(args[n], XmNlabelString, emptyString); ++n;
+ findBtn = XmCreatePushButton(toolBar, "find", args, n);
+ XtManageChild(findBtn);
+ XtAddCallback(findBtn, XmNactivateCallback,
+ &findCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, findBtn); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 6); ++n;
+ XtSetArg(args[n], XmNlabelString, emptyString); ++n;
+ printBtn = XmCreatePushButton(toolBar, "print", args, n);
+ XtManageChild(printBtn);
+ XtAddCallback(printBtn, XmNactivateCallback,
+ &printCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, printBtn); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 6); ++n;
+ XtSetArg(args[n], XmNlabelString, emptyString); ++n;
+ aboutBtn = XmCreatePushButton(toolBar, "about", args, n);
+ XtManageChild(aboutBtn);
+ XtAddCallback(aboutBtn, XmNactivateCallback,
+ &aboutCbk, (XtPointer)this);
+ lastBtn = aboutBtn;
+
+ // quit button
+ n = 0;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 6); ++n;
+ s = XmStringCreateLocalized("Quit");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ quitBtn = XmCreatePushButton(toolBar, "quit", args, n);
+ XmStringFree(s);
+ XtManageChild(quitBtn);
+ XtAddCallback(quitBtn, XmNactivateCallback,
+ &quitCbk, (XtPointer)this);
+
+ // link label
+ n = 0;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNleftWidget, lastBtn); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightWidget, btn); ++n;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ s = XmStringCreateLocalized("");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNrecomputeSize, True); ++n;
+ XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); ++n;
+ linkLabel = XmCreateLabel(toolBar, "linkLabel", args, n);
+ XmStringFree(s);
+ XtManageChild(linkLabel);
+
+#ifndef DISABLE_OUTLINE
+ if (app->getFullScreen()) {
+#endif
+
+ // core
+ core = new XPDFCore(win, form, app->getPaperColor(),
+ app->getFullScreen(), app->getReverseVideo(),
+ app->getInstallCmap(), app->getRGBCubeSize());
+ core->setUpdateCbk(&updateCbk, this);
+ core->setActionCbk(&actionCbk, this);
+ core->setKeyPressCbk(&keyPressCbk, this);
+ core->setMouseCbk(&mouseCbk, this);
+ core->setReqPasswordCbk(&reqPasswordCbk, this);
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNbottomWidget, toolBar); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetValues(core->getWidget(), args, n);
+
+#ifndef DISABLE_OUTLINE
+ } else {
+
+ // paned window
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNbottomWidget, toolBar); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
+ panedWin = XmCreatePanedWindow(form, "panedWin", args, n);
+ XtManageChild(panedWin);
+
+ // scrolled window for outline container
+ n = 0;
+ XtSetArg(args[n], XmNpositionIndex, 0); ++n;
+ XtSetArg(args[n], XmNallowResize, True); ++n;
+ XtSetArg(args[n], XmNpaneMinimum, 1); ++n;
+ XtSetArg(args[n], XmNpaneMaximum, 10000); ++n;
+ XtSetArg(args[n], XmNwidth, 1); ++n;
+ XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); ++n;
+ outlineScroll = XmCreateScrolledWindow(panedWin, "outlineScroll", args, n);
+ XtManageChild(outlineScroll);
+ XtVaGetValues(outlineScroll, XmNclipWindow, &clipWin, NULL);
+ XtVaSetValues(clipWin, XmNbackground, app->getPaperColor(), NULL);
+
+ // outline tree
+ n = 0;
+ XtSetArg(args[n], XmNbackground, app->getPaperColor()); ++n;
+ outlineTree = XPDFCreateTree(outlineScroll, "outlineTree", args, n);
+ XtManageChild(outlineTree);
+ XtAddCallback(outlineTree, XPDFNselectionCallback, &outlineSelectCbk,
+ (XtPointer)this);
+
+ // core
+ core = new XPDFCore(win, panedWin, app->getPaperColor(),
+ app->getFullScreen(), app->getReverseVideo(),
+ app->getInstallCmap(), app->getRGBCubeSize());
+ core->setUpdateCbk(&updateCbk, this);
+ core->setActionCbk(&actionCbk, this);
+ core->setKeyPressCbk(&keyPressCbk, this);
+ core->setMouseCbk(&mouseCbk, this);
+ core->setReqPasswordCbk(&reqPasswordCbk, this);
+ n = 0;
+ XtSetArg(args[n], XmNpositionIndex, 1); ++n;
+ XtSetArg(args[n], XmNallowResize, True); ++n;
+ XtSetArg(args[n], XmNpaneMinimum, 1); ++n;
+ XtSetArg(args[n], XmNpaneMaximum, 10000); ++n;
+ XtSetValues(core->getWidget(), args, n);
+ }
+#endif
+
+ // set the zoom menu to match the initial zoom setting
+ XtVaSetValues(zoomMenu, XmNmenuHistory,
+ getZoomMenuBtn(core->getZoom()), NULL);
+
+ // set traversal order
+ XtVaSetValues(core->getDrawAreaWidget(),
+ XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL);
+ XtVaSetValues(backBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(prevTenPageBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(prevPageBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(nextPageBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(nextTenPageBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(forwardBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(pageNumText, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(zoomMenu, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(findBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(printBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(aboutBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+ XtVaSetValues(quitBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP,
+ NULL);
+
+ // popup menu
+ n = 0;
+ XtSetArg(args[n], XmNmenuPost, "<Btn3Down>"); ++n;
+ popupMenu = XmCreatePopupMenu(core->getDrawAreaWidget(), "popupMenu",
+ args, n);
+ n = 0;
+ s = XmStringCreateLocalized("Open...");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ s2 = XmStringCreateLocalized("O");
+ XtSetArg(args[n], XmNacceleratorText, s2); ++n;
+ btn = XmCreatePushButton(popupMenu, "open", args, n);
+ XmStringFree(s);
+ XmStringFree(s2);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &openCbk, (XtPointer)this);
+ n = 0;
+ s = XmStringCreateLocalized("Open in new window...");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ btn = XmCreatePushButton(popupMenu, "openInNewWindow", args, n);
+ XmStringFree(s);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &openInNewWindowCbk, (XtPointer)this);
+ n = 0;
+ s = XmStringCreateLocalized("Reload");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ s2 = XmStringCreateLocalized("R");
+ XtSetArg(args[n], XmNacceleratorText, s2); ++n;
+ btn = XmCreatePushButton(popupMenu, "reload", args, n);
+ XmStringFree(s);
+ XmStringFree(s2);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &reloadCbk, (XtPointer)this);
+ n = 0;
+ s = XmStringCreateLocalized("Save as...");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ btn = XmCreatePushButton(popupMenu, "saveAs", args, n);
+ XmStringFree(s);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &saveAsCbk, (XtPointer)this);
+ n = 0;
+ btn = XmCreateSeparator(popupMenu, "sep1", args, n);
+ XtManageChild(btn);
+ n = 0;
+ s = XmStringCreateLocalized("Rotate counterclockwise");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ btn = XmCreatePushButton(popupMenu, "rotateCCW", args, n);
+ XmStringFree(s);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &rotateCCWCbk, (XtPointer)this);
+ n = 0;
+ s = XmStringCreateLocalized("Rotate clockwise");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ btn = XmCreatePushButton(popupMenu, "rotateCW", args, n);
+ XmStringFree(s);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &rotateCWCbk, (XtPointer)this);
+ n = 0;
+ btn = XmCreateSeparator(popupMenu, "sep2", args, n);
+ XtManageChild(btn);
+ n = 0;
+ s = XmStringCreateLocalized("Close");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ s2 = XmStringCreateLocalized("Ctrl+W");
+ XtSetArg(args[n], XmNacceleratorText, s2); ++n;
+ btn = XmCreatePushButton(popupMenu, "close", args, n);
+ XmStringFree(s);
+ XmStringFree(s2);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &closeCbk, (XtPointer)this);
+ n = 0;
+ s = XmStringCreateLocalized("Quit");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ s2 = XmStringCreateLocalized("Q");
+ XtSetArg(args[n], XmNacceleratorText, s2); ++n;
+ btn = XmCreatePushButton(popupMenu, "quit", args, n);
+ XmStringFree(s);
+ XmStringFree(s2);
+ XtManageChild(btn);
+ XtAddCallback(btn, XmNactivateCallback,
+ &quitCbk, (XtPointer)this);
+
+ XmStringFree(emptyString);
+}
+
+void XPDFViewer::mapWindow() {
+#ifdef HAVE_X11_XPM_H
+ Pixmap iconPixmap;
+#endif
+ int depth;
+ Pixel bg, arm;
+
+ // show the window
+ XtPopup(win, XtGrabNone);
+ core->takeFocus();
+
+ // create the icon
+#ifdef HAVE_X11_XPM_H
+ if (XpmCreatePixmapFromData(display, XtWindow(win), xpdfIcon,
+ &iconPixmap, NULL, NULL) == XpmSuccess) {
+ XtVaSetValues(win, XmNiconPixmap, iconPixmap, NULL);
+ }
+#endif
+
+ // set button bitmaps (must be done after the window is mapped)
+ XtVaGetValues(backBtn, XmNdepth, &depth,
+ XmNbackground, &bg, XmNarmColor, &arm, NULL);
+ XtVaSetValues(backBtn, XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)backArrow_bits,
+ backArrow_width,
+ backArrow_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ XmNarmPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)backArrow_bits,
+ backArrow_width,
+ backArrow_height,
+ BlackPixel(display, screenNum),
+ arm, depth),
+ XmNlabelInsensitivePixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)backArrowDis_bits,
+ backArrowDis_width,
+ backArrowDis_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ NULL);
+ XtVaSetValues(prevTenPageBtn, XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)dblLeftArrow_bits,
+ dblLeftArrow_width,
+ dblLeftArrow_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ XmNarmPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)dblLeftArrow_bits,
+ dblLeftArrow_width,
+ dblLeftArrow_height,
+ BlackPixel(display, screenNum),
+ arm, depth),
+ XmNlabelInsensitivePixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)dblLeftArrowDis_bits,
+ dblLeftArrowDis_width,
+ dblLeftArrowDis_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ NULL);
+ XtVaSetValues(prevPageBtn, XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)leftArrow_bits,
+ leftArrow_width,
+ leftArrow_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ XmNarmPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)leftArrow_bits,
+ leftArrow_width,
+ leftArrow_height,
+ BlackPixel(display, screenNum),
+ arm, depth),
+ XmNlabelInsensitivePixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)leftArrowDis_bits,
+ leftArrowDis_width,
+ leftArrowDis_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ NULL);
+ XtVaSetValues(nextPageBtn, XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)rightArrow_bits,
+ rightArrow_width,
+ rightArrow_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ XmNarmPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)rightArrow_bits,
+ rightArrow_width,
+ rightArrow_height,
+ BlackPixel(display, screenNum),
+ arm, depth),
+ XmNlabelInsensitivePixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)rightArrowDis_bits,
+ rightArrowDis_width,
+ rightArrowDis_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ NULL);
+ XtVaSetValues(nextTenPageBtn, XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)dblRightArrow_bits,
+ dblRightArrow_width,
+ dblRightArrow_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ XmNarmPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)dblRightArrow_bits,
+ dblRightArrow_width,
+ dblRightArrow_height,
+ BlackPixel(display, screenNum),
+ arm, depth),
+ XmNlabelInsensitivePixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)dblRightArrowDis_bits,
+ dblRightArrowDis_width,
+ dblRightArrowDis_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ NULL);
+ XtVaSetValues(forwardBtn, XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)forwardArrow_bits,
+ forwardArrow_width,
+ forwardArrow_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ XmNarmPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)forwardArrow_bits,
+ forwardArrow_width,
+ forwardArrow_height,
+ BlackPixel(display, screenNum),
+ arm, depth),
+ XmNlabelInsensitivePixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)forwardArrowDis_bits,
+ forwardArrowDis_width,
+ forwardArrowDis_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ NULL);
+ XtVaSetValues(findBtn, XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)find_bits,
+ find_width,
+ find_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ XmNarmPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)find_bits,
+ find_width,
+ find_height,
+ BlackPixel(display, screenNum),
+ arm, depth),
+ XmNlabelInsensitivePixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)findDis_bits,
+ findDis_width,
+ findDis_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ NULL);
+ XtVaSetValues(printBtn, XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)print_bits,
+ print_width,
+ print_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ XmNarmPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)print_bits,
+ print_width,
+ print_height,
+ BlackPixel(display, screenNum),
+ arm, depth),
+ XmNlabelInsensitivePixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)printDis_bits,
+ printDis_width,
+ printDis_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ NULL);
+ XtVaSetValues(aboutBtn, XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)about_bits,
+ about_width,
+ about_height,
+ BlackPixel(display, screenNum),
+ bg, depth),
+ XmNarmPixmap,
+ XCreatePixmapFromBitmapData(display, XtWindow(toolBar),
+ (char *)about_bits,
+ about_width,
+ about_height,
+ BlackPixel(display, screenNum),
+ arm, depth),
+ NULL);
+}
+
+void XPDFViewer::closeWindow() {
+ XtPopdown(win);
+ XtDestroyWidget(win);
+}
+
+Widget XPDFViewer::getZoomMenuBtn(int z) {
+ if (z >= minZoom && z <= maxZoom) {
+ return zoomMenuBtns[z - minZoom];
+ }
+ if (z == zoomPage) {
+ return zoomMenuBtns[maxZoom - minZoom + 1];
+ }
+ if (z == zoomWidth) {
+ return zoomMenuBtns[maxZoom - minZoom + 2];
+ }
+ return zoomMenuBtns[0];
+}
+
+void XPDFViewer::prevPageCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->core->gotoPrevPage(1, gTrue, gFalse);
+ viewer->core->takeFocus();
+}
+
+void XPDFViewer::prevTenPageCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->core->gotoPrevPage(10, gTrue, gFalse);
+ viewer->core->takeFocus();
+}
+
+void XPDFViewer::nextPageCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->core->gotoNextPage(1, gTrue);
+ viewer->core->takeFocus();
+}
+
+void XPDFViewer::nextTenPageCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->core->gotoNextPage(10, gTrue);
+ viewer->core->takeFocus();
+}
+
+void XPDFViewer::backCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->core->goBackward();
+ viewer->core->takeFocus();
+}
+
+void XPDFViewer::forwardCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->core->goForward();
+ viewer->core->takeFocus();
+}
+
+void XPDFViewer::zoomMenuCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ XtPointer userData;
+
+ XtVaGetValues(widget, XmNuserData, &userData, NULL);
+ if ((int)userData != viewer->core->getZoom()) {
+ viewer->displayPage(viewer->core->getPageNum(), (int)userData,
+ viewer->core->getRotate(), gTrue, gFalse);
+ }
+ viewer->core->takeFocus();
+}
+
+void XPDFViewer::findCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ if (!viewer->core->getDoc()) {
+ return;
+ }
+ XtManageChild(viewer->findDialog);
+}
+
+void XPDFViewer::printCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ if (!viewer->core->getDoc()) {
+ return;
+ }
+ XtManageChild(viewer->printDialog);
+}
+
+void XPDFViewer::aboutCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ XtManageChild(viewer->aboutDialog);
+}
+
+void XPDFViewer::quitCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->app->quit();
+}
+
+void XPDFViewer::openCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->mapOpenDialog(gFalse);
+}
+
+void XPDFViewer::openInNewWindowCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->mapOpenDialog(gTrue);
+}
+
+void XPDFViewer::reloadCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->reloadFile();
+}
+
+void XPDFViewer::saveAsCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ if (!viewer->core->getDoc()) {
+ return;
+ }
+ viewer->mapSaveAsDialog();
+}
+
+void XPDFViewer::rotateCCWCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ int r;
+
+ r = viewer->core->getRotate();
+ r = (r == 0) ? 270 : r - 90;
+ viewer->displayPage(viewer->core->getPageNum(), viewer->core->getZoom(),
+ r, gTrue, gFalse);
+}
+
+void XPDFViewer::rotateCWCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ int r;
+
+ r = viewer->core->getRotate();
+ r = (r == 270) ? 0 : r + 90;
+ viewer->displayPage(viewer->core->getPageNum(), viewer->core->getZoom(),
+ r, gTrue, gFalse);
+}
+
+void XPDFViewer::closeCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->app->close(viewer, gFalse);
+}
+
+void XPDFViewer::closeMsgCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->app->close(viewer, gTrue);
+}
+
+void XPDFViewer::pageNumCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ char *s, *p;
+ int pg;
+ char buf[20];
+
+ if (!viewer->core->getDoc()) {
+ goto err;
+ }
+ s = XmTextFieldGetString(viewer->pageNumText);
+ for (p = s; *p; ++p) {
+ if (!isdigit(*p)) {
+ goto err;
+ }
+ }
+ pg = atoi(s);
+ if (pg < 1 || pg > viewer->core->getDoc()->getNumPages()) {
+ goto err;
+ }
+ viewer->displayPage(pg, viewer->core->getZoom(),
+ viewer->core->getRotate(), gFalse, gTrue);
+ viewer->core->takeFocus();
+ return;
+
+ err:
+ XBell(viewer->display, 0);
+ sprintf(buf, "%d", viewer->core->getPageNum());
+ XmTextFieldSetString(viewer->pageNumText, buf);
+}
+
+void XPDFViewer::updateCbk(void *data, GString *fileName,
+ int pageNum, int numPages, char *linkLabel) {
+ XPDFViewer *viewer = (XPDFViewer *)data;
+ GString *title;
+ char buf[20];
+ XmString s;
+
+ if (fileName) {
+ if (!(title = viewer->app->getTitle())) {
+ title = (new GString(xpdfAppName))->append(": ")->append(fileName);
+ }
+ XtVaSetValues(viewer->win, XmNtitle, title->getCString(),
+ XmNiconName, title->getCString(), NULL);
+ if (!viewer->app->getTitle()) {
+ delete title;
+ }
+#ifndef DISABLE_OUTLINE
+ if (!viewer->app->getFullScreen()) {
+ viewer->setupOutline();
+ }
+#endif
+ viewer->setupPrintDialog();
+ }
+
+ if (pageNum >= 0) {
+ s = XmStringCreateLocalized("");
+ XtVaSetValues(viewer->linkLabel, XmNlabelString, s, NULL);
+ XmStringFree(s);
+ sprintf(buf, "%d", pageNum);
+ XmTextFieldSetString(viewer->pageNumText, buf);
+ XtVaSetValues(viewer->prevTenPageBtn, XmNsensitive,
+ pageNum > 1, NULL);
+ XtVaSetValues(viewer->prevPageBtn, XmNsensitive,
+ pageNum > 1, NULL);
+ XtVaSetValues(viewer->nextTenPageBtn, XmNsensitive,
+ pageNum < viewer->core->getDoc()->getNumPages(), NULL);
+ XtVaSetValues(viewer->nextPageBtn, XmNsensitive,
+ pageNum < viewer->core->getDoc()->getNumPages(), NULL);
+ XtVaSetValues(viewer->backBtn, XmNsensitive,
+ viewer->core->canGoBack(), NULL);
+ XtVaSetValues(viewer->forwardBtn, XmNsensitive,
+ viewer->core->canGoForward(), NULL);
+ }
+
+ if (numPages >= 0) {
+ sprintf(buf, " of %d", numPages);
+ s = XmStringCreateLocalized(buf);
+ XtVaSetValues(viewer->pageCountLabel, XmNlabelString, s, NULL);
+ XmStringFree(s);
+ }
+
+ if (linkLabel) {
+ s = XmStringCreateLocalized(linkLabel);
+ XtVaSetValues(viewer->linkLabel, XmNlabelString, s, NULL);
+ XmStringFree(s);
+ }
+}
+
+
+//------------------------------------------------------------------------
+// GUI code: outline
+//------------------------------------------------------------------------
+
+#ifndef DISABLE_OUTLINE
+
+void XPDFViewer::setupOutline() {
+ GList *items;
+ UnicodeMap *uMap;
+ GString *enc;
+ int i;
+
+ // unmanage and destroy the old labels
+ if (outlineLabels) {
+ XtUnmanageChildren(outlineLabels, outlineLabelsLength);
+ for (i = 0; i < outlineLabelsLength; ++i) {
+ XtDestroyWidget(outlineLabels[i]);
+ }
+ gfree(outlineLabels);
+ outlineLabels = NULL;
+ outlineLabelsLength = outlineLabelsSize = 0;
+ }
+
+ // create the new labels
+ items = core->getDoc()->getOutline()->getItems();
+ if (items && items->getLength() > 0) {
+ enc = new GString("Latin1");
+ uMap = globalParams->getUnicodeMap(enc);
+ delete enc;
+ setupOutlineItems(items, NULL, uMap);
+ uMap->decRefCnt();
+ }
+
+ // manage the new labels
+ XtManageChildren(outlineLabels, outlineLabelsLength);
+}
+
+void XPDFViewer::setupOutlineItems(GList *items, Widget parent,
+ UnicodeMap *uMap) {
+ OutlineItem *item;
+ GList *kids;
+ Widget label;
+ Arg args[20];
+ GString *title;
+ char buf[8];
+ XmString s;
+ int i, j, n;
+
+ for (i = 0; i < items->getLength(); ++i) {
+ item = (OutlineItem *)items->get(i);
+ title = new GString();
+ for (j = 0; j < item->getTitleLength(); ++j) {
+ n = uMap->mapUnicode(item->getTitle()[j], buf, sizeof(buf));
+ title->append(buf, n);
+ }
+ n = 0;
+ XtSetArg(args[n], XPDFNentryPosition, i); ++n;
+ if (parent) {
+ XtSetArg(args[n], XPDFNentryParent, parent); ++n;
+ }
+ XtSetArg(args[n], XPDFNentryExpanded, item->isOpen()); ++n;
+ s = XmStringCreateLocalized(title->getCString());
+ delete title;
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNuserData, item); ++n;
+ XtSetArg(args[n], XmNmarginWidth, 0); ++n;
+ XtSetArg(args[n], XmNmarginHeight, 2); ++n;
+ XtSetArg(args[n], XmNshadowThickness, 0); ++n;
+ XtSetArg(args[n], XmNforeground,
+ app->getReverseVideo() ? WhitePixel(display, screenNum)
+ : BlackPixel(display, screenNum)); ++n;
+ XtSetArg(args[n], XmNbackground, app->getPaperColor()); ++n;
+ label = XmCreateLabelGadget(outlineTree, "label", args, n);
+ XmStringFree(s);
+ if (outlineLabelsLength == outlineLabelsSize) {
+ outlineLabelsSize += 64;
+ outlineLabels = (Widget *)grealloc(outlineLabels,
+ outlineLabelsSize * sizeof(Widget *));
+ }
+ outlineLabels[outlineLabelsLength++] = label;
+ item->open();
+ if ((kids = item->getKids())) {
+ setupOutlineItems(kids, label, uMap);
+ }
+ }
+}
+
+void XPDFViewer::outlineSelectCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ XPDFTreeSelectCallbackStruct *data =
+ (XPDFTreeSelectCallbackStruct *)callData;
+ OutlineItem *item;
+
+ XtVaGetValues(data->selectedItem, XmNuserData, &item, NULL);
+ if (item) {
+ viewer->core->doAction(item->getAction());
+ }
+ viewer->core->takeFocus();
+}
+
+#endif // !DISABLE_OUTLINE
+
+//------------------------------------------------------------------------
+// GUI code: "about" dialog
+//------------------------------------------------------------------------
+
+void XPDFViewer::initAboutDialog() {
+ Widget scrolledWin, col, label, sep, closeBtn;
+ Arg args[20];
+ int n, i;
+ XmString s;
+ char buf[20];
+
+ //----- dialog
+ n = 0;
+ s = XmStringCreateLocalized(xpdfAppName ": About");
+ XtSetArg(args[n], XmNdialogTitle, s); ++n;
+ XtSetArg(args[n], XmNwidth, 450); ++n;
+ XtSetArg(args[n], XmNheight, 300); ++n;
+ aboutDialog = XmCreateFormDialog(win, "aboutDialog", args, n);
+ XmStringFree(s);
+
+ //----- "close" button
+ n = 0;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightOffset, 4); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomOffset, 4); ++n;
+ closeBtn = XmCreatePushButton(aboutDialog, "Close", args, n);
+ XtManageChild(closeBtn);
+ n = 0;
+ XtSetArg(args[n], XmNdefaultButton, closeBtn); ++n;
+ XtSetArg(args[n], XmNcancelButton, closeBtn); ++n;
+ XtSetValues(aboutDialog, args, n);
+
+ //----- scrolled window and RowColumn
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNbottomWidget, closeBtn); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); ++n;
+ scrolledWin = XmCreateScrolledWindow(aboutDialog, "scrolledWin", args, n);
+ XtManageChild(scrolledWin);
+ n = 0;
+ XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n;
+ XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); ++n;
+ col = XmCreateRowColumn(scrolledWin, "col", args, n);
+ XtManageChild(col);
+
+ //----- fonts
+ aboutBigFont = XmFontListAppendEntry(NULL,
+ XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT,
+ XLoadQueryFont(display,
+ "-*-times-bold-i-normal--20-*-*-*-*-*-iso8859-1")));
+ aboutVersionFont = XmFontListAppendEntry(NULL,
+ XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT,
+ XLoadQueryFont(display,
+ "-*-times-medium-r-normal--16-*-*-*-*-*-iso8859-1")));
+ aboutFixedFont = XmFontListAppendEntry(NULL,
+ XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT,
+ XLoadQueryFont(display,
+ "-*-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1")));
+
+ //----- heading
+ n = 0;
+ s = XmStringCreateLocalized("Xpdf");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNfontList, aboutBigFont); ++n;
+ label = XmCreateLabel(col, "h0", args, n);
+ XmStringFree(s);
+ XtManageChild(label);
+ n = 0;
+ s = XmStringCreateLocalized("Version " xpdfVersion);
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNfontList, aboutVersionFont); ++n;
+ label = XmCreateLabel(col, "h1", args, n);
+ XmStringFree(s);
+ XtManageChild(label);
+ n = 0;
+ s = XmStringCreateLocalized(xpdfCopyright);
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNfontList, aboutVersionFont); ++n;
+ label = XmCreateLabel(col, "h2", args, n);
+ XmStringFree(s);
+ XtManageChild(label);
+ n = 0;
+ s = XmStringCreateLocalized(" ");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNfontList, aboutVersionFont); ++n;
+ label = XmCreateLabel(col, "h3", args, n);
+ XmStringFree(s);
+ XtManageChild(label);
+ n = 0;
+ XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
+ sep = XmCreateSeparator(col, "sep", args, n);
+ XtManageChild(sep);
+ n = 0;
+ s = XmStringCreateLocalized(" ");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNfontList, aboutVersionFont); ++n;
+ label = XmCreateLabel(col, "h4", args, n);
+ XmStringFree(s);
+ XtManageChild(label);
+ n = 0;
+
+ //----- text
+ for (i = 0; aboutWinText[i]; ++i) {
+ n = 0;
+ s = XmStringCreateLocalized(aboutWinText[i]);
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ XtSetArg(args[n], XmNfontList, aboutFixedFont); ++n;
+ sprintf(buf, "t%d", i);
+ label = XmCreateLabel(col, buf, args, n);
+ XtManageChild(label);
+ XmStringFree(s);
+ }
+}
+
+//------------------------------------------------------------------------
+// GUI code: "open" dialog
+//------------------------------------------------------------------------
+
+void XPDFViewer::initOpenDialog() {
+ Arg args[20];
+ int n;
+ XmString s1, s2, s3;
+
+ n = 0;
+ s1 = XmStringCreateLocalized("Open");
+ XtSetArg(args[n], XmNokLabelString, s1); ++n;
+ s2 = XmStringCreateLocalized("*.[Pp][Dd][Ff]");
+ XtSetArg(args[n], XmNpattern, s2); ++n;
+ s3 = XmStringCreateLocalized(xpdfAppName ": Open");
+ XtSetArg(args[n], XmNdialogTitle, s3); ++n;
+ XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n;
+ XtSetArg(args[n], XmNautoUnmanage, True); ++n;
+ openDialog = XmCreateFileSelectionDialog(win, "openDialog", args, n);
+ XmStringFree(s1);
+ XmStringFree(s2);
+ XmStringFree(s3);
+ XtUnmanageChild(XmFileSelectionBoxGetChild(openDialog,
+ XmDIALOG_HELP_BUTTON));
+ XtAddCallback(openDialog, XmNokCallback,
+ &openOkCbk, (XtPointer)this);
+}
+
+void XPDFViewer::setOpenDialogDir(char *dir) {
+ XmString s;
+
+ s = XmStringCreateLocalized(dir);
+ XtVaSetValues(openDialog, XmNdirectory, s, NULL);
+ XmStringFree(s);
+}
+
+void XPDFViewer::mapOpenDialog(GBool openInNewWindowA) {
+ openInNewWindow = openInNewWindowA;
+ XmFileSelectionDoSearch(openDialog, NULL);
+ XtManageChild(openDialog);
+}
+
+void XPDFViewer::openOkCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ XmFileSelectionBoxCallbackStruct *data =
+ (XmFileSelectionBoxCallbackStruct *)callData;
+ char *fileName;
+ XmStringContext context;
+ XmStringCharSet charSet;
+ XmStringDirection dir;
+ Boolean sep;
+ GString *fileNameStr;
+
+ XmStringInitContext(&context, data->value);
+ if (XmStringGetNextSegment(context, &fileName, &charSet, &dir, &sep)) {
+ fileNameStr = new GString(fileName);
+ if (viewer->openInNewWindow) {
+ viewer->app->open(fileNameStr);
+ } else {
+ if (viewer->loadFile(fileNameStr)) {
+ viewer->displayPage(1, viewer->core->getZoom(),
+ viewer->core->getRotate(), gTrue, gTrue);
+ }
+ }
+ delete fileNameStr;
+ XtFree(charSet);
+ XtFree(fileName);
+ }
+ XmStringFreeContext(context);
+}
+
+//------------------------------------------------------------------------
+// GUI code: "find" dialog
+//------------------------------------------------------------------------
+
+void XPDFViewer::initFindDialog() {
+ Widget row1, label, okBtn, closeBtn;
+ Arg args[20];
+ int n;
+ XmString s;
+
+ //----- dialog
+ n = 0;
+ s = XmStringCreateLocalized(xpdfAppName ": Find");
+ XtSetArg(args[n], XmNdialogTitle, s); ++n;
+ XtSetArg(args[n], XmNnavigationType, XmNONE); ++n;
+ XtSetArg(args[n], XmNautoUnmanage, False); ++n;
+ findDialog = XmCreateFormDialog(win, "findDialog", args, n);
+ XmStringFree(s);
+
+ //----- top row: search string entry
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNtopOffset, 4); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
+ XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); ++n;
+ row1 = XmCreateRowColumn(findDialog, "row1", args, n);
+ XtManageChild(row1);
+ n = 0;
+ s = XmStringCreateLocalized("Find text: ");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ label = XmCreateLabel(row1, "label", args, n);
+ XmStringFree(s);
+ XtManageChild(label);
+ n = 0;
+ XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n;
+ findText = XmCreateTextField(row1, "text", args, n);
+ XtManageChild(findText);
+
+ //----- "find" and "close" buttons
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, row1); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 4); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomOffset, 4); ++n;
+ XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n;
+ okBtn = XmCreatePushButton(findDialog, "Find", args, n);
+ XtManageChild(okBtn);
+ XtAddCallback(okBtn, XmNactivateCallback,
+ &findFindCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, row1); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightOffset, 4); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomOffset, 4); ++n;
+ XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n;
+ closeBtn = XmCreatePushButton(findDialog, "Close", args, n);
+ XtManageChild(closeBtn);
+ XtAddCallback(closeBtn, XmNactivateCallback,
+ &findCloseCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNdefaultButton, okBtn); ++n;
+ XtSetArg(args[n], XmNcancelButton, closeBtn); ++n;
+ XtSetArg(args[n], XmNinitialFocus, findText); ++n;
+ XtSetValues(findDialog, args, n);
+}
+
+void XPDFViewer::findFindCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->core->find(XmTextFieldGetString(viewer->findText));
+}
+
+void XPDFViewer::findCloseCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ XtUnmanageChild(viewer->findDialog);
+}
+
+//------------------------------------------------------------------------
+// GUI code: "save as" dialog
+//------------------------------------------------------------------------
+
+void XPDFViewer::initSaveAsDialog() {
+ Arg args[20];
+ int n;
+ XmString s1, s2, s3;
+
+ n = 0;
+ s1 = XmStringCreateLocalized("Save");
+ XtSetArg(args[n], XmNokLabelString, s1); ++n;
+ s2 = XmStringCreateLocalized("*.[Pp][Dd][Ff]");
+ XtSetArg(args[n], XmNpattern, s2); ++n;
+ s3 = XmStringCreateLocalized(xpdfAppName ": Save as");
+ XtSetArg(args[n], XmNdialogTitle, s3); ++n;
+ XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n;
+ XtSetArg(args[n], XmNautoUnmanage, True); ++n;
+ saveAsDialog = XmCreateFileSelectionDialog(win, "saveAsDialog", args, n);
+ XmStringFree(s1);
+ XmStringFree(s2);
+ XmStringFree(s3);
+ XtUnmanageChild(XmFileSelectionBoxGetChild(saveAsDialog,
+ XmDIALOG_HELP_BUTTON));
+ XtAddCallback(saveAsDialog, XmNokCallback,
+ &saveAsOkCbk, (XtPointer)this);
+}
+
+void XPDFViewer::setSaveAsDialogDir(char *dir) {
+ XmString s;
+
+ s = XmStringCreateLocalized(dir);
+ XtVaSetValues(saveAsDialog, XmNdirectory, s, NULL);
+ XmStringFree(s);
+}
+
+void XPDFViewer::mapSaveAsDialog() {
+ XmFileSelectionDoSearch(saveAsDialog, NULL);
+ XtManageChild(saveAsDialog);
+}
+
+void XPDFViewer::saveAsOkCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ XmFileSelectionBoxCallbackStruct *data =
+ (XmFileSelectionBoxCallbackStruct *)callData;
+ char *fileName;
+ GString *fileNameStr;
+ XmStringContext context;
+ XmStringCharSet charSet;
+ XmStringDirection dir;
+ Boolean sep;
+
+ XmStringInitContext(&context, data->value);
+ if (XmStringGetNextSegment(context, &fileName, &charSet, &dir, &sep)) {
+ fileNameStr = new GString(fileName);
+ viewer->core->getDoc()->saveAs(fileNameStr);
+ delete fileNameStr;
+ XtFree(charSet);
+ XtFree(fileName);
+ }
+ XmStringFreeContext(context);
+}
+
+//------------------------------------------------------------------------
+// GUI code: "print" dialog
+//------------------------------------------------------------------------
+
+void XPDFViewer::initPrintDialog() {
+ Widget sep1, sep2, row, label1, label2, okBtn, cancelBtn;
+ Arg args[20];
+ int n;
+ XmString s;
+
+ //----- dialog
+ n = 0;
+ s = XmStringCreateLocalized(xpdfAppName ": Print");
+ XtSetArg(args[n], XmNdialogTitle, s); ++n;
+ XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n;
+ printDialog = XmCreateFormDialog(win, "printDialog", args, n);
+ XmStringFree(s);
+
+ //----- "print with command"
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNtopOffset, 4); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); ++n;
+ XtSetArg(args[n], XmNset, XmSET); ++n;
+ s = XmStringCreateLocalized("Print with command:");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ printWithCmdBtn = XmCreateToggleButton(printDialog, "printWithCmd", args, n);
+ XmStringFree(s);
+ XtManageChild(printWithCmdBtn);
+ XtAddCallback(printWithCmdBtn, XmNvalueChangedCallback,
+ &printWithCmdBtnCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, printWithCmdBtn); ++n;
+ XtSetArg(args[n], XmNtopOffset, 2); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 16); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightOffset, 4); ++n;
+ XtSetArg(args[n], XmNcolumns, 40); ++n;
+ printCmdText = XmCreateTextField(printDialog, "printCmd", args, n);
+ XtManageChild(printCmdText);
+
+ //----- "print with command"
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, printCmdText); ++n;
+ XtSetArg(args[n], XmNtopOffset, 4); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); ++n;
+ XtSetArg(args[n], XmNset, XmUNSET); ++n;
+ s = XmStringCreateLocalized("Print to file:");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ printToFileBtn = XmCreateToggleButton(printDialog, "printToFile", args, n);
+ XmStringFree(s);
+ XtManageChild(printToFileBtn);
+ XtAddCallback(printToFileBtn, XmNvalueChangedCallback,
+ &printToFileBtnCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, printToFileBtn); ++n;
+ XtSetArg(args[n], XmNtopOffset, 2); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 16); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightOffset, 4); ++n;
+ XtSetArg(args[n], XmNcolumns, 40); ++n;
+ XtSetArg(args[n], XmNsensitive, False); ++n;
+ printFileText = XmCreateTextField(printDialog, "printFile", args, n);
+ XtManageChild(printFileText);
+
+ //----- separator
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, printFileText); ++n;
+ XtSetArg(args[n], XmNtopOffset, 8); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 8); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightOffset, 8); ++n;
+ XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
+ sep1 = XmCreateSeparator(printDialog, "sep1", args, n);
+ XtManageChild(sep1);
+
+ //----- page range
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, sep1); ++n;
+ XtSetArg(args[n], XmNtopOffset, 8); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 4); ++n;
+ XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
+ XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); ++n;
+ row = XmCreateRowColumn(printDialog, "row", args, n);
+ XtManageChild(row);
+ n = 0;
+ s = XmStringCreateLocalized("Pages:");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ label1 = XmCreateLabel(row, "label1", args, n);
+ XmStringFree(s);
+ XtManageChild(label1);
+ n = 0;
+ XtSetArg(args[n], XmNcolumns, 5); ++n;
+ printFirstPage = XmCreateTextField(row, "printFirstPage", args, n);
+ XtManageChild(printFirstPage);
+ n = 0;
+ s = XmStringCreateLocalized("to");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ label2 = XmCreateLabel(row, "label2", args, n);
+ XmStringFree(s);
+ XtManageChild(label2);
+ n = 0;
+ XtSetArg(args[n], XmNcolumns, 5); ++n;
+ printLastPage = XmCreateTextField(row, "printLastPage", args, n);
+ XtManageChild(printLastPage);
+
+ //----- separator
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, row); ++n;
+ XtSetArg(args[n], XmNtopOffset, 8); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 8); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightOffset, 8); ++n;
+ XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
+ sep2 = XmCreateSeparator(printDialog, "sep2", args, n);
+ XtManageChild(sep2);
+
+ //----- "print" and "cancel" buttons
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, sep2); ++n;
+ XtSetArg(args[n], XmNtopOffset, 8); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 4); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomOffset, 4); ++n;
+ okBtn = XmCreatePushButton(printDialog, "Print", args, n);
+ XtManageChild(okBtn);
+ XtAddCallback(okBtn, XmNactivateCallback,
+ &printPrintCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, sep2); ++n;
+ XtSetArg(args[n], XmNtopOffset, 8); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightOffset, 4); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomOffset, 4); ++n;
+ cancelBtn = XmCreatePushButton(printDialog, "Cancel", args, n);
+ XtManageChild(cancelBtn);
+ n = 0;
+ XtSetArg(args[n], XmNdefaultButton, okBtn); ++n;
+ XtSetArg(args[n], XmNcancelButton, cancelBtn); ++n;
+ XtSetValues(printDialog, args, n);
+}
+
+void XPDFViewer::setupPrintDialog() {
+ PDFDoc *doc;
+ char buf[20];
+ GString *pdfFileName, *psFileName;
+ char *p;
+
+ doc = core->getDoc();
+
+ psFileName = globalParams->getPSFile();
+ if (psFileName && psFileName->getChar(0) != '|') {
+ XmTextFieldSetString(printFileText, psFileName->getCString());
+ } else {
+ pdfFileName = doc->getFileName();
+ p = pdfFileName->getCString() + pdfFileName->getLength() - 4;
+ if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")) {
+ psFileName = new GString(pdfFileName->getCString(),
+ pdfFileName->getLength() - 4);
+ } else {
+ psFileName = pdfFileName->copy();
+ }
+ psFileName->append(".ps");
+ XmTextFieldSetString(printFileText, psFileName->getCString());
+ delete psFileName;
+ }
+
+ psFileName = globalParams->getPSFile();
+ if (psFileName && psFileName->getChar(0) == '|') {
+ XmTextFieldSetString(printCmdText,
+ psFileName->getCString() + 1);
+ }
+
+ sprintf(buf, "%d", doc->getNumPages());
+ XmTextFieldSetString(printFirstPage, "1");
+ XmTextFieldSetString(printLastPage, buf);
+}
+
+void XPDFViewer::printWithCmdBtnCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ XmToggleButtonCallbackStruct *data =
+ (XmToggleButtonCallbackStruct *)callData;
+
+ if (data->set != XmSET) {
+ XmToggleButtonSetState(viewer->printWithCmdBtn, True, False);
+ }
+ XmToggleButtonSetState(viewer->printToFileBtn, False, False);
+ XtVaSetValues(viewer->printCmdText, XmNsensitive, True, NULL);
+ XtVaSetValues(viewer->printFileText, XmNsensitive, False, NULL);
+}
+
+void XPDFViewer::printToFileBtnCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ XmToggleButtonCallbackStruct *data =
+ (XmToggleButtonCallbackStruct *)callData;
+
+ if (data->set != XmSET) {
+ XmToggleButtonSetState(viewer->printToFileBtn, True, False);
+ }
+ XmToggleButtonSetState(viewer->printWithCmdBtn, False, False);
+ XtVaSetValues(viewer->printFileText, XmNsensitive, True, NULL);
+ XtVaSetValues(viewer->printCmdText, XmNsensitive, False, NULL);
+}
+
+void XPDFViewer::printPrintCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ unsigned char withCmd;
+ GString *psFileName;
+ int firstPage, lastPage;
+ PDFDoc *doc;
+ PSOutputDev *psOut;
+
+ doc = viewer->core->getDoc();
+ if (!doc->okToPrint()) {
+ error(-1, "Printing this document is not allowed.");
+ return;
+ }
+
+ viewer->core->setBusyCursor(gTrue);
+
+ XtVaGetValues(viewer->printWithCmdBtn, XmNset, &withCmd, NULL);
+ if (withCmd) {
+ psFileName = new GString(XmTextFieldGetString(viewer->printCmdText));
+ psFileName->insert(0, '|');
+ } else {
+ psFileName = new GString(XmTextFieldGetString(viewer->printFileText));
+ }
+
+ firstPage = atoi(XmTextFieldGetString(viewer->printFirstPage));
+ lastPage = atoi(XmTextFieldGetString(viewer->printLastPage));
+ if (firstPage < 1) {
+ firstPage = 1;
+ } else if (firstPage > doc->getNumPages()) {
+ firstPage = doc->getNumPages();
+ }
+ if (lastPage < firstPage) {
+ lastPage = firstPage;
+ } else if (lastPage > doc->getNumPages()) {
+ lastPage = doc->getNumPages();
+ }
+
+ psOut = new PSOutputDev(psFileName->getCString(), doc->getXRef(),
+ doc->getCatalog(), firstPage, lastPage,
+ psModePS);
+ if (psOut->isOk()) {
+ doc->displayPages(psOut, firstPage, lastPage, 72, 0, gFalse);
+ }
+ delete psOut;
+ delete psFileName;
+
+ viewer->core->setBusyCursor(gFalse);
+}
+
+//------------------------------------------------------------------------
+// GUI code: password dialog
+//------------------------------------------------------------------------
+
+void XPDFViewer::initPasswordDialog() {
+ Widget row, label, okBtn, cancelBtn;
+ Arg args[20];
+ int n;
+ XmString s;
+
+ //----- dialog
+ n = 0;
+ s = XmStringCreateLocalized(xpdfAppName ": Password");
+ XtSetArg(args[n], XmNdialogTitle, s); ++n;
+ XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n;
+ passwordDialog = XmCreateFormDialog(win, "passwordDialog", args, n);
+ XmStringFree(s);
+
+ //----- message
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNtopOffset, 4); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 4); ++n;
+ s = XmStringCreateLocalized(" ");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ passwordMsg = XmCreateLabel(passwordDialog, "msg", args, n);
+ XmStringFree(s);
+ XtManageChild(passwordMsg);
+
+ //----- label and password entry
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, passwordMsg); ++n;
+ XtSetArg(args[n], XmNtopOffset, 4); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 4); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 4); ++n;
+ XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
+ XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); ++n;
+ row = XmCreateRowColumn(passwordDialog, "row", args, n);
+ XtManageChild(row);
+ n = 0;
+ s = XmStringCreateLocalized("Password: ");
+ XtSetArg(args[n], XmNlabelString, s); ++n;
+ label = XmCreateLabel(row, "label", args, n);
+ XmStringFree(s);
+ XtManageChild(label);
+ n = 0;
+ XtSetArg(args[n], XmNcolumns, 16); ++n;
+ passwordText = XmCreateTextField(row, "text", args, n);
+ XtManageChild(passwordText);
+ XtAddCallback(passwordText, XmNmodifyVerifyCallback,
+ &passwordTextVerifyCbk, this);
+
+ //----- "Ok" and "Cancel" buttons
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, row); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 4); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomOffset, 4); ++n;
+ XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n;
+ okBtn = XmCreatePushButton(passwordDialog, "Ok", args, n);
+ XtManageChild(okBtn);
+ XtAddCallback(okBtn, XmNactivateCallback,
+ &passwordOkCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNtopWidget, row); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNrightOffset, 4); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNbottomOffset, 4); ++n;
+ XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n;
+ cancelBtn = XmCreatePushButton(passwordDialog, "Cancel", args, n);
+ XtManageChild(cancelBtn);
+ XtAddCallback(cancelBtn, XmNactivateCallback,
+ &passwordCancelCbk, (XtPointer)this);
+ n = 0;
+ XtSetArg(args[n], XmNdefaultButton, okBtn); ++n;
+ XtSetArg(args[n], XmNcancelButton, cancelBtn); ++n;
+ XtSetArg(args[n], XmNinitialFocus, passwordText); ++n;
+ XtSetValues(passwordDialog, args, n);
+}
+
+void XPDFViewer::passwordTextVerifyCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+ XmTextVerifyCallbackStruct *data =
+ (XmTextVerifyCallbackStruct *)callData;
+ int i, n;
+
+ i = (int)data->startPos;
+ n = (int)data->endPos - i;
+ if (i > viewer->password->getLength()) {
+ i = viewer->password->getLength();
+ }
+ if (i + n > viewer->password->getLength()) {
+ n = viewer->password->getLength() - i;
+ }
+ viewer->password->del(i, n);
+ viewer->password->insert(i, data->text->ptr, data->text->length);
+
+ for (i = 0; i < data->text->length; ++i) {
+ data->text->ptr[i] = '*';
+ }
+ data->doit = True;
+}
+
+void XPDFViewer::passwordOkCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->passwordDone = 1;
+}
+
+void XPDFViewer::passwordCancelCbk(Widget widget, XtPointer ptr,
+ XtPointer callData) {
+ XPDFViewer *viewer = (XPDFViewer *)ptr;
+
+ viewer->passwordDone = -1;
+}
+
+void XPDFViewer::getPassword(GBool again) {
+ XmString s;
+ XEvent event;
+
+ if (password) {
+ delete password;
+ }
+ password = new GString();
+
+ XmTextFieldSetString(passwordText, "");
+ s = XmStringCreateLocalized(
+ again ? (char *)"Incorrect password. Please try again."
+ : (char *)"This document requires a password.");
+ XtVaSetValues(passwordMsg, XmNlabelString, s, NULL);
+ XmStringFree(s);
+ XtManageChild(passwordDialog);
+ passwordDone = 0;
+ do {
+ XtAppNextEvent(app->getAppContext(), &event);
+ XtDispatchEvent(&event);
+ } while (!passwordDone);
+
+ if (passwordDone < 0) {
+ delete password;
+ password = NULL;
+ }
+}
diff --git a/pdf/xpdf/XPDFViewer.h b/pdf/xpdf/XPDFViewer.h
new file mode 100644
index 0000000..77875c4
--- /dev/null
+++ b/pdf/xpdf/XPDFViewer.h
@@ -0,0 +1,236 @@
+//========================================================================
+//
+// XPDFViewer.h
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef XPDFVIEWER_H
+#define XPDFVIEWER_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#define Object XtObject
+#include <Xm/XmAll.h>
+#undef Object
+#include "gtypes.h"
+#include "XPDFCore.h"
+
+#if XmVERSION <= 1
+#define DISABLE_OUTLINE
+#endif
+
+class GString;
+class GList;
+class UnicodeMap;
+class LinkDest;
+class XPDFApp;
+
+//------------------------------------------------------------------------
+// XPDFViewer
+//------------------------------------------------------------------------
+
+class XPDFViewer {
+public:
+
+ XPDFViewer(XPDFApp *appA, GString *fileName,
+ int pageA, GString *destName,
+ GString *ownerPassword, GString *userPassword);
+ GBool isOk() { return ok; }
+ ~XPDFViewer();
+
+ void open(GString *fileName, int pageA, GString *destName);
+ void clear();
+
+ Widget getWindow() { return win; }
+
+private:
+
+ //----- load / display
+ GBool loadFile(GString *fileName, GString *ownerPassword = NULL,
+ GString *userPassword = NULL);
+ void reloadFile();
+ void displayPage(int pageA, int zoomA, int rotateA,
+ GBool scrollToTop, GBool addToHist);
+ void displayDest(LinkDest *dest, int zoomA, int rotateA,
+ GBool addToHist);
+ void getPageAndDest(int pageA, GString *destName,
+ int *pageOut, LinkDest **destOut);
+
+ //----- password dialog
+ static GString *reqPasswordCbk(void *data, GBool again);
+
+ //----- actions
+ static void actionCbk(void *data, char *action);
+
+ //----- keyboard/mouse input
+ static void keyPressCbk(void *data, char *s, KeySym key,
+ Guint modifiers);
+ static void mouseCbk(void *data, XEvent *event);
+
+ //----- GUI code: main window
+ void initWindow();
+ void mapWindow();
+ void closeWindow();
+ Widget getZoomMenuBtn(int z);
+ static void prevPageCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void prevTenPageCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void nextPageCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void nextTenPageCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void backCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void forwardCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void zoomMenuCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void findCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void printCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void aboutCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void quitCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void openCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void openInNewWindowCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void reloadCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void saveAsCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void rotateCCWCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void rotateCWCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void closeCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void closeMsgCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void pageNumCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void updateCbk(void *data, GString *fileName,
+ int pageNum, int numPages, char *linkLabel);
+
+ //----- GUI code: outline
+#ifndef DISABLE_OUTLINE
+ void setupOutline();
+ void setupOutlineItems(GList *items, Widget parent, UnicodeMap *uMap);
+ static void outlineSelectCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+#endif
+
+ //----- GUI code: "about" dialog
+ void initAboutDialog();
+
+ //----- GUI code: "open" dialog
+ void initOpenDialog();
+ void setOpenDialogDir(char *dir);
+ void mapOpenDialog(GBool openInNewWindowA);
+ static void openOkCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+
+ //----- GUI code: "find" dialog
+ void initFindDialog();
+ static void findFindCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void findCloseCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+
+ //----- GUI code: "save as" dialog
+ void initSaveAsDialog();
+ void setSaveAsDialogDir(char *dir);
+ void mapSaveAsDialog();
+ static void saveAsOkCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+
+ //----- GUI code: "print" dialog
+ void initPrintDialog();
+ void setupPrintDialog();
+ static void printWithCmdBtnCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void printToFileBtnCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void printPrintCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+
+ //----- GUI code: password dialog
+ void initPasswordDialog();
+ static void passwordTextVerifyCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void passwordOkCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ static void passwordCancelCbk(Widget widget, XtPointer ptr,
+ XtPointer callData);
+ void getPassword(GBool again);
+
+ XPDFApp *app;
+ GBool ok;
+
+ Display *display;
+ int screenNum;
+ Widget win; // top-level window
+ Widget form;
+ Widget panedWin;
+#ifndef DISABLE_OUTLINE
+ Widget outlineScroll;
+ Widget outlineTree;
+ Widget *outlineLabels;
+ int outlineLabelsLength;
+ int outlineLabelsSize;
+#endif
+ XPDFCore *core;
+ Widget toolBar;
+ Widget backBtn;
+ Widget prevTenPageBtn;
+ Widget prevPageBtn;
+ Widget nextPageBtn;
+ Widget nextTenPageBtn;
+ Widget forwardBtn;
+ Widget pageNumText;
+ Widget pageCountLabel;
+ Widget zoomMenu;
+ Widget zoomMenuBtns[maxZoom - minZoom + 1 + 2];
+ Widget findBtn;
+ Widget printBtn;
+ Widget aboutBtn;
+ Widget linkLabel;
+ Widget quitBtn;
+ Widget popupMenu;
+
+ Widget aboutDialog;
+ XmFontList aboutBigFont, aboutVersionFont, aboutFixedFont;
+
+ Widget openDialog;
+ GBool openInNewWindow;
+
+ Widget findDialog;
+ Widget findText;
+
+ Widget saveAsDialog;
+
+ Widget printDialog;
+ Widget printWithCmdBtn;
+ Widget printToFileBtn;
+ Widget printCmdText;
+ Widget printFileText;
+ Widget printFirstPage;
+ Widget printLastPage;
+
+ Widget passwordDialog;
+ Widget passwordMsg;
+ Widget passwordText;
+ int passwordDone;
+ GString *password;
+};
+
+#endif
diff --git a/pdf/xpdf/XPixmapOutputDev.cc b/pdf/xpdf/XPixmapOutputDev.cc
new file mode 100644
index 0000000..ecd1498
--- /dev/null
+++ b/pdf/xpdf/XPixmapOutputDev.cc
@@ -0,0 +1,84 @@
+//========================================================================
+//
+// XPixmapOutputDev.cc
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "Object.h"
+#include "GfxState.h"
+#include "XPixmapOutputDev.h"
+
+//------------------------------------------------------------------------
+
+#define xoutRound(x) ((int)(x + 0.5))
+
+//------------------------------------------------------------------------
+
+XPixmapOutputDev::XPixmapOutputDev(Display *displayA, int screenNumA,
+ Visual *visualA, Colormap colormapA,
+ GBool reverseVideoA, Gulong paperColorA,
+ GBool installCmapA, int rgbCubeSizeA,
+ GBool incrementalUpdateA,
+ void (*redrawCbkA)(void *data),
+ void *redrawCbkDataA):
+ XOutputDev(displayA, screenNumA, visualA, colormapA,
+ reverseVideoA, paperColorA, installCmapA, rgbCubeSizeA)
+{
+ incrementalUpdate = incrementalUpdateA;
+ redrawCbk = redrawCbkA;
+ redrawCbkData = redrawCbkDataA;
+}
+
+XPixmapOutputDev::~XPixmapOutputDev() {
+ if (getPixmapWidth() > 0) {
+ XFreePixmap(getDisplay(), getPixmap());
+ }
+}
+
+void XPixmapOutputDev::clear() {
+ startDoc(NULL);
+ startPage(0, NULL);
+}
+
+void XPixmapOutputDev::startPage(int pageNum, GfxState *state) {
+ int oldPixmapW, oldPixmapH, newPixmapW, newPixmapH;
+
+ // resize the off-screen pixmap (if needed)
+ oldPixmapW = getPixmapWidth();
+ oldPixmapH = getPixmapHeight();
+ newPixmapW = xoutRound(state ? state->getPageWidth() : 1);
+ newPixmapH = xoutRound(state ? state->getPageHeight() : 1);
+ if (oldPixmapW == 0 ||
+ newPixmapW != oldPixmapW || newPixmapH != oldPixmapH) {
+ if (oldPixmapW > 0) {
+ XFreePixmap(getDisplay(), getPixmap());
+ }
+ setPixmap(XCreatePixmap(getDisplay(), win, newPixmapW, newPixmapH,
+ getDepth()),
+ newPixmapW, newPixmapH);
+ }
+
+ XOutputDev::startPage(pageNum, state);
+}
+
+void XPixmapOutputDev::endPage() {
+ if (!incrementalUpdate) {
+ (*redrawCbk)(redrawCbkData);
+ }
+ XOutputDev::endPage();
+}
+
+void XPixmapOutputDev::dump() {
+ if (incrementalUpdate) {
+ (*redrawCbk)(redrawCbkData);
+ }
+ XOutputDev::dump();
+}
diff --git a/pdf/xpdf/XPixmapOutputDev.h b/pdf/xpdf/XPixmapOutputDev.h
new file mode 100644
index 0000000..1dba8af
--- /dev/null
+++ b/pdf/xpdf/XPixmapOutputDev.h
@@ -0,0 +1,63 @@
+//========================================================================
+//
+// XPixmapOutputDev.h
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef XPIXMAPOUTPUTDEV_H
+#define XPIXMAPOUTPUTDEV_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <X11/Xlib.h>
+#include "XOutputDev.h"
+
+//------------------------------------------------------------------------
+
+class XPixmapOutputDev: public XOutputDev {
+public:
+
+ XPixmapOutputDev(Display *displayA, int screenNumA,
+ Visual *visualA, Colormap colormapA,
+ GBool reverseVideoA, Gulong paperColorA,
+ GBool installCmapA, int rgbCubeSizeA,
+ GBool incrementalUpdateA,
+ void (*redrawCbkA)(void *data),
+ void *redrawCbkDataA);
+
+ ~XPixmapOutputDev();
+
+ //----- initialization and control
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state);
+
+ // End a page.
+ virtual void endPage();
+
+ // Dump page contents to display.
+ virtual void dump();
+
+ //----- special access
+
+ // Set the window - this is used only to create a compatible pixmap.
+ void setWindow(Window winA) { win = winA; }
+
+ // Clear out the document (used when displaying an empty window).
+ void clear();
+
+private:
+
+ GBool incrementalUpdate; // incrementally update the display?
+ void (*redrawCbk)(void *data);
+ void *redrawCbkData;
+ Window win;
+};
+
+#endif
diff --git a/pdf/xpdf/about-text.h b/pdf/xpdf/about-text.h
new file mode 100644
index 0000000..e84c1ef
--- /dev/null
+++ b/pdf/xpdf/about-text.h
@@ -0,0 +1,47 @@
+//========================================================================
+//
+// about-text.h
+//
+// Copyright 2002 Glyph & Cog, LLC
+//
+//========================================================================
+
+static char *aboutWinText[] = {
+ "http://www.foolabs.com/xpdf/",
+ "derekn@foolabs.com",
+ " ",
+ "Licensed under the GNU General Public License (GPL).",
+ "See the 'COPYING' file for details.",
+ " ",
+ "Supports PDF version " supportedPDFVersionStr ".",
+ " ",
+ "The PDF data structures, operators, and specification",
+ "are copyright 1985-2001 Adobe Systems Inc.",
+ " ",
+ "Mouse bindings:",
+ " button 1: select text / follow link",
+ " button 2: pan window",
+ " button 3: menu",
+ " ",
+ "Key bindings:",
+ " o = open file",
+ " r = reload",
+ " f / ctrl-F = find text",
+ " ctrl-G = find next"
+ " ctrl-P = print",
+ " n = next page",
+ " p = previous page",
+ " <PgDn> = <space> = scroll down",
+ " <PgUp> = <backspace> = <delete> = scroll up",
+ " v = forward (history path)",
+ " b = backward (history path)",
+ " 0 / + / - = zoom zero / in / out",
+ " z / w = zoom page / page width",
+ " ctrl-L = redraw",
+ " q = quit",
+ " <home> / <end> = top / bottom of page",
+ " <arrows> = scroll",
+ " ",
+ "For more information, please read the xpdf(1) man page.",
+ NULL
+};
diff --git a/pdf/xpdf/backArrowDis.xbm b/pdf/xpdf/backArrowDis.xbm
new file mode 100644
index 0000000..7529639
--- /dev/null
+++ b/pdf/xpdf/backArrowDis.xbm
@@ -0,0 +1,6 @@
+#define backArrowDis_width 16
+#define backArrowDis_height 15
+static unsigned char backArrowDis_bits[] = {
+ 0x80, 0x00, 0x40, 0x00, 0xa0, 0x00, 0x50, 0x00, 0xa8, 0x00, 0x54, 0x44,
+ 0xaa, 0x88, 0x55, 0x44, 0xaa, 0x88, 0x54, 0x44, 0xa8, 0x88, 0x50, 0x00,
+ 0xa0, 0x00, 0x40, 0x00, 0x80, 0x00};
diff --git a/pdf/xpdf/dblLeftArrowDis.xbm b/pdf/xpdf/dblLeftArrowDis.xbm
new file mode 100644
index 0000000..3fb78d8
--- /dev/null
+++ b/pdf/xpdf/dblLeftArrowDis.xbm
@@ -0,0 +1,6 @@
+#define dblLeftArrowDis_width 16
+#define dblLeftArrowDis_height 15
+static unsigned char dblLeftArrowDis_bits[] = {
+ 0x80, 0x80, 0x40, 0x40, 0xa0, 0xa0, 0x50, 0x50, 0xa8, 0xa8, 0x54, 0x54,
+ 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x54, 0x54, 0xa8, 0xa8, 0x50, 0x50,
+ 0xa0, 0xa0, 0x40, 0x40, 0x80, 0x80};
diff --git a/pdf/xpdf/dblRightArrowDis.xbm b/pdf/xpdf/dblRightArrowDis.xbm
new file mode 100644
index 0000000..a6c1e37
--- /dev/null
+++ b/pdf/xpdf/dblRightArrowDis.xbm
@@ -0,0 +1,6 @@
+#define dblRightArrowDis_width 16
+#define dblRightArrowDis_height 15
+static unsigned char dblRightArrowDis_bits[] = {
+ 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x0a, 0x0a, 0x15, 0x15, 0x2a, 0x2a,
+ 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0x2a, 0x2a, 0x15, 0x15, 0x0a, 0x0a,
+ 0x05, 0x05, 0x02, 0x02, 0x01, 0x01};
diff --git a/pdf/xpdf/findDis.xbm b/pdf/xpdf/findDis.xbm
new file mode 100644
index 0000000..cf666f2
--- /dev/null
+++ b/pdf/xpdf/findDis.xbm
@@ -0,0 +1,6 @@
+#define findDis_width 15
+#define findDis_height 15
+static unsigned char findDis_bits[] = {
+ 0x10, 0x04, 0x28, 0x0a, 0x04, 0x10, 0xaa, 0x2a, 0x55, 0x55, 0x20, 0x02,
+ 0x41, 0x41, 0x20, 0x02, 0x41, 0x41, 0xa0, 0x02, 0x01, 0x40, 0x20, 0x02,
+ 0x01, 0x40, 0x20, 0x02, 0x15, 0x54};
diff --git a/pdf/xpdf/forwardArrowDis.xbm b/pdf/xpdf/forwardArrowDis.xbm
new file mode 100644
index 0000000..58d0cc0
--- /dev/null
+++ b/pdf/xpdf/forwardArrowDis.xbm
@@ -0,0 +1,6 @@
+#define forwardArrowDis_width 16
+#define forwardArrowDis_height 15
+static unsigned char forwardArrowDis_bits[] = {
+ 0x00, 0x01, 0x00, 0x02, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x15, 0x22, 0x2a,
+ 0x11, 0x55, 0x22, 0xaa, 0x11, 0x55, 0x22, 0x2a, 0x00, 0x15, 0x00, 0x0a,
+ 0x00, 0x05, 0x00, 0x02, 0x00, 0x01};
diff --git a/pdf/xpdf/leftArrowDis.xbm b/pdf/xpdf/leftArrowDis.xbm
new file mode 100644
index 0000000..953092a
--- /dev/null
+++ b/pdf/xpdf/leftArrowDis.xbm
@@ -0,0 +1,5 @@
+#define leftArrowDis_width 8
+#define leftArrowDis_height 15
+static unsigned char leftArrowDis_bits[] = {
+ 0x80, 0x40, 0xa0, 0x50, 0xa8, 0x54, 0xaa, 0x55, 0xaa, 0x54, 0xa8, 0x50,
+ 0xa0, 0x40, 0x80};
diff --git a/pdf/xpdf/print.xbm b/pdf/xpdf/print.xbm
new file mode 100644
index 0000000..209eb43
--- /dev/null
+++ b/pdf/xpdf/print.xbm
@@ -0,0 +1,6 @@
+#define print_width 15
+#define print_height 15
+static unsigned char print_bits[] = {
+ 0xf0, 0x7f, 0x10, 0x40, 0x10, 0x40, 0xc8, 0x23, 0x08, 0x20, 0x68, 0x23,
+ 0x04, 0x10, 0x34, 0x10, 0x04, 0x10, 0xff, 0x7f, 0x55, 0x55, 0xab, 0x6a,
+ 0x55, 0x55, 0xab, 0x6a, 0xfe, 0x3f};
diff --git a/pdf/xpdf/printDis.xbm b/pdf/xpdf/printDis.xbm
new file mode 100644
index 0000000..19e962d
--- /dev/null
+++ b/pdf/xpdf/printDis.xbm
@@ -0,0 +1,6 @@
+#define printDis_width 15
+#define printDis_height 15
+static unsigned char printDis_bits[] = {
+ 0xa0, 0x2a, 0x10, 0x40, 0x00, 0x00, 0x40, 0x01, 0x08, 0x20, 0x40, 0x01,
+ 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x01, 0x40,
+ 0x00, 0x00, 0x01, 0x40, 0xaa, 0x2a};
diff --git a/pdf/xpdf/rightArrowDis.xbm b/pdf/xpdf/rightArrowDis.xbm
new file mode 100644
index 0000000..1216c47
--- /dev/null
+++ b/pdf/xpdf/rightArrowDis.xbm
@@ -0,0 +1,5 @@
+#define rightArrowDis_width 8
+#define rightArrowDis_height 15
+static unsigned char rightArrowDis_bits[] = {
+ 0x01, 0x02, 0x05, 0x0a, 0x15, 0x2a, 0x55, 0xaa, 0x55, 0x2a, 0x15, 0x0a,
+ 0x05, 0x02, 0x01};