]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/XPDFCore.cc
Import of Xpdf 2.03
[evince.git] / pdf / xpdf / XPDFCore.cc
index 554154cbb70d7fc3c39b20a3201bcda300f9bd28..d4d8fa6b86124e007ecf64721e8c5d27fe6c84f3 100644 (file)
@@ -2,7 +2,7 @@
 //
 // XPDFCore.cc
 //
-// Copyright 2002 Glyph & Cog, LLC
+// Copyright 2002-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -14,6 +14,7 @@
 
 #include <X11/keysym.h>
 #include <X11/cursorfont.h>
+#include <string.h>
 #include "gmem.h"
 #include "GString.h"
 #include "GList.h"
 
 //------------------------------------------------------------------------
 
-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;
+Atom XPDFCore::targetsAtom;
 
 //------------------------------------------------------------------------
 // XPDFCore
@@ -116,6 +110,7 @@ XPDFCore::XPDFCore(Widget shellA, Widget parentWidgetA,
   parentWidget = parentWidgetA;
   display = XtDisplay(parentWidget);
   screenNum = XScreenNumberOfScreen(XtScreen(parentWidget));
+  targetsAtom = XInternAtom(display, "TARGETS", False);
 
   paperColor = paperColorA;
   fullScreen = fullScreenA;
@@ -144,10 +139,8 @@ XPDFCore::XPDFCore(Widget shellA, Widget parentWidgetA,
     zoom = zoomWidth;
   } else {
     zoom = atoi(initialZoom->getCString());
-    if (zoom < minZoom) {
-      zoom = minZoom;
-    } else if (zoom > maxZoom) {
-      zoom = maxZoom;
+    if (zoom <= 0) {
+      zoom = defZoom;
     }
   }
   delete initialZoom;
@@ -217,18 +210,6 @@ XPDFCore::~XPDFCore() {
   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);
   }
@@ -315,6 +296,74 @@ int XPDFCore::loadFile(GString *fileName, GString *ownerPassword,
   return errNone;
 }
 
+int XPDFCore::loadFile(BaseStream *stream, GString *ownerPassword,
+                      GString *userPassword) {
+  PDFDoc *newDoc;
+  GString *password;
+  GBool again;
+  int err;
+
+  // busy cursor
+  setCursor(busyCursor);
+
+  // open the PDF file
+  newDoc = new PDFDoc(stream, 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(stream, 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;
@@ -339,11 +388,11 @@ void XPDFCore::resizeToPage(int 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);
+      width = (Dimension)(width1 * 0.01 * defZoom + 0.5);
+      height = (Dimension)(height1 * 0.01 * defZoom + 0.5);
     } else {
-      width = (Dimension)((width1 * zoomDPI[zoom - minZoom]) / 72 + 0.5);
-      height = (Dimension)((height1 * zoomDPI[zoom - minZoom]) / 72 + 0.5);
+      width = (Dimension)(width1 * 0.01 * zoom + 0.5);
+      height = (Dimension)(height1 * 0.01 * zoom + 0.5);
     }
     if (width > displayW - 100) {
       width = displayW - 100;
@@ -383,7 +432,7 @@ void XPDFCore::clear() {
   redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
 }
 
-void XPDFCore::displayPage(int pageA, int zoomA, int rotateA,
+void XPDFCore::displayPage(int pageA, double zoomA, int rotateA,
                           GBool scrollToTop, GBool addToHist) {
   double hDPI, vDPI;
   int rot;
@@ -467,10 +516,10 @@ void XPDFCore::displayPage(int pageA, int zoomA, int rotateA,
       dpi = (drawAreaWidth / doc->getPageWidth(page)) * 72;
     }
   } else {
-    dpi = zoomDPI[zoom - minZoom];
+    dpi = 0.01 * zoom * 72;
   }
   out->setWindow(XtWindow(drawArea));
-  doc->displayPage(out, page, dpi, rotate, gTrue);
+  doc->displayPage(out, page, dpi, dpi, rotate, gTrue);
   oldScrollX = scrollX;
   oldScrollY = scrollY;
   updateScrollBars();
@@ -478,6 +527,15 @@ void XPDFCore::displayPage(int pageA, int zoomA, int rotateA,
     redrawRectangle(scrollX, scrollY, drawAreaWidth, drawAreaHeight);
   }
 
+  // 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);
+
 
   // add to history
   if (addToHist) {
@@ -488,7 +546,11 @@ void XPDFCore::displayPage(int pageA, int zoomA, int rotateA,
     if (h->fileName) {
       delete h->fileName;
     }
-    h->fileName = doc->getFileName()->copy();
+    if (doc->getFileName()) {
+      h->fileName = doc->getFileName()->copy();
+    } else {
+      h->fileName = NULL;
+    }
     h->page = page;
     if (historyBLen < xpdfHistorySize) {
       ++historyBLen;
@@ -501,20 +563,11 @@ void XPDFCore::displayPage(int pageA, int zoomA, int rotateA,
     (*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,
+void XPDFCore::displayDest(LinkDest *dest, double zoomA, int rotateA,
                           GBool addToHist) {
   Ref pageRef;
   int pg;
@@ -623,7 +676,7 @@ void XPDFCore::goForward() {
   }
   --historyFLen;
   ++historyBLen;
-  if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
+  if (!doc || history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
     if (loadFile(history[historyCur].fileName) != errNone) {
       XBell(display, 0);
       return;
@@ -642,7 +695,7 @@ void XPDFCore::goBackward() {
   }
   --historyBLen;
   ++historyFLen;
-  if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
+  if (!doc || history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
     if (loadFile(history[historyCur].fileName) != errNone) {
       XBell(display, 0);
       return;
@@ -925,15 +978,31 @@ 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;
+  Atom *array;
+
+  // send back a list of supported conversion targets
+  if (*target == targetsAtom) {
+    if (!(array = (Atom *)XtMalloc(sizeof(Atom)))) {
+      return False;
+    }
+    array[0] = XA_STRING;
+    *value = (XtPointer)array;
+    *type = XA_ATOM;
+    *format = 32;
+    *length = 1;
+    return True;
+
+  // send the selected text
+  } else if (*target == XA_STRING) {
+    //~ for multithreading: need a mutex here
+    *value = XtNewString(currentSelection->getCString());
+    *length = currentSelection->getLength();
+    *type = XA_STRING;
+    *format = 8; // 8-bit elements
+    return True;
+  }
+
+  return False;
 }
 
 GBool XPDFCore::getSelection(int *xMin, int *yMin, int *xMax, int *yMax) {
@@ -962,12 +1031,12 @@ GString *XPDFCore::extractText(int pageNum,
   if (!doc->okToCopy()) {
     return NULL;
   }
-  textOut = new TextOutputDev(NULL, gFalse, gFalse, gFalse);
+  textOut = new TextOutputDev(NULL, gTrue, gFalse, gFalse);
   if (!textOut->isOk()) {
     delete textOut;
     return NULL;
   }
-  doc->displayPage(textOut, pageNum, dpi, rotate, gFalse);
+  doc->displayPage(textOut, pageNum, dpi, dpi, rotate, gFalse);
   s = textOut->getText(xMin, yMin, xMax, yMax);
   delete textOut;
   return s;
@@ -977,7 +1046,7 @@ GString *XPDFCore::extractText(int pageNum,
 // hyperlinks
 //------------------------------------------------------------------------
 
-void XPDFCore::doLink(int mx, int my) {
+GBool XPDFCore::doLink(int mx, int my) {
   double x, y;
   LinkAction *action;
 
@@ -985,7 +1054,9 @@ void XPDFCore::doLink(int mx, int my) {
   out->cvtDevToUser(mx, my, &x, &y);
   if ((action = doc->findLink(x, y))) {
     doAction(action);
+    return gTrue;
   }
+  return gFalse;
 }
 
 void XPDFCore::doAction(LinkAction *action) {
@@ -1193,26 +1264,9 @@ void XPDFCore::doAction(LinkAction *action) {
 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 = mungeURL(arg);
     cmd->insert(0, cmdFmt->getCString(),
                s - cmdFmt->getCString());
     cmd->append(s + 2);
@@ -1230,18 +1284,43 @@ void XPDFCore::runCommand(GString *cmdFmt, GString *arg) {
   delete cmd;
 }
 
+// Escape any characters in a URL which might cause problems when
+// calling system().
+GString *XPDFCore::mungeURL(GString *url) {
+  static char *allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                         "abcdefghijklmnopqrstuvwxyz"
+                         "0123456789"
+                         "-_.~/?:@&=+,#%";
+  GString *newURL;
+  char c;
+  char buf[4];
+  int i;
+
+  newURL = new GString();
+  for (i = 0; i < url->getLength(); ++i) {
+    c = url->getChar(i);
+    if (strchr(allowed, c)) {
+      newURL->append(c);
+    } else {
+      sprintf(buf, "%%%02x", c & 0xff);
+      newURL->append(buf);
+    }
+  }
+  return newURL;
+}
+
 
 //------------------------------------------------------------------------
 // find
 //------------------------------------------------------------------------
 
-void XPDFCore::find(char *s) {
+void XPDFCore::find(char *s, GBool next) {
   Unicode *u;
   TextOutputDev *textOut;
   int xMin, yMin, xMax, yMax;
   double xMin1, yMin1, xMax1, yMax1;
   int pg;
-  GBool top;
+  GBool startAtTop;
   int len, i;
 
   // check for zero-length string
@@ -1263,27 +1342,24 @@ void XPDFCore::find(char *s) {
 #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)) {
+  startAtTop = !next && !(selectXMin < selectXMax && selectYMin < selectYMax);
+  xMin = selectXMin + 1;
+  yMin = selectYMin + 1;
+  xMax = yMax = 0;
+  if (out->findText(u, len, startAtTop, gTrue, next, gFalse,
+                   &xMin, &yMin, &xMax, &yMax)) {
     goto found;
   }
 
   // search following pages
-  textOut = new TextOutputDev(NULL, gFalse, gFalse, gFalse);
+  textOut = new TextOutputDev(NULL, gTrue, 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,
+    doc->displayPage(textOut, pg, 72, 72, 0, gFalse);
+    if (textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse,
                          &xMin1, &yMin1, &xMax1, &yMax1)) {
       goto foundPage;
     }
@@ -1291,8 +1367,8 @@ void XPDFCore::find(char *s) {
 
   // search previous pages
   for (pg = 1; pg < page; ++pg) {
-    doc->displayPage(textOut, pg, 72, 0, gFalse);
-    if (textOut->findText(u, len, gTrue, gTrue,
+    doc->displayPage(textOut, pg, 72, 72, 0, gFalse);
+    if (textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse,
                          &xMin1, &yMin1, &xMax1, &yMax1)) {
       goto foundPage;
     }
@@ -1300,10 +1376,12 @@ void XPDFCore::find(char *s) {
   delete textOut;
 
   // search current page ending at current selection
-  if (selectXMin < selectXMax && selectYMin < selectYMax) {
+  if (!startAtTop) {
+    xMin = yMin = 0;
     xMax = selectXMin;
-    yMax = (selectYMin + selectYMax) / 2;
-    if (out->findText(u, len, gTrue, gFalse, &xMin, &yMin, &xMax, &yMax)) {
+    yMax = selectYMin;
+    if (out->findText(u, len, gTrue, gFalse, gFalse, next,
+                     &xMin, &yMin, &xMax, &yMax)) {
       goto found;
     }
   }
@@ -1316,7 +1394,8 @@ void XPDFCore::find(char *s) {
  foundPage:
   delete textOut;
   displayPage(pg, zoom, rotate, gTrue, gTrue);
-  if (!out->findText(u, len, gTrue, gTrue, &xMin, &yMin, &xMax, &yMax)) {
+  if (!out->findText(u, len, gTrue, gTrue, gFalse, gFalse,
+                    &xMin, &yMin, &xMax, &yMax)) {
     // this can happen if coalescing is bad
     goto done;
   }
@@ -1472,6 +1551,7 @@ void XPDFCore::resizeCbk(Widget widget, XtPointer ptr, XtPointer callData) {
   Arg args[2];
   int n;
   Dimension w, h;
+  int oldScrollX, oldScrollY;
 
   n = 0;
   XtSetArg(args[n], XmNwidth, &w); ++n;
@@ -1484,7 +1564,13 @@ void XPDFCore::resizeCbk(Widget widget, XtPointer ptr, XtPointer callData) {
     core->displayPage(core->page, core->zoom, core->rotate,
                      gFalse, gFalse);
   } else {
+    oldScrollX = core->scrollX;
+    oldScrollY = core->scrollY;
     core->updateScrollBars();
+    if (core->scrollX != oldScrollX || core->scrollY != oldScrollY) {
+      core->redrawRectangle(core->scrollX, core->scrollY,
+                           core->drawAreaWidth, core->drawAreaHeight);
+    }
   }
 }
 
@@ -1857,7 +1943,7 @@ void XPDFCore::doErrorDialog(char *title, GString *msg) {
 
 GBool XPDFCore::doDialog(int type, GBool hasCancel,
                         char *title, GString *msg) {
-  Widget dialog;
+  Widget dialog, scroll, text;
   XtAppContext appContext;
   Arg args[20];
   int n;
@@ -1869,11 +1955,31 @@ GBool XPDFCore::doDialog(int type, GBool hasCancel,
   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;
+  s2 = NULL; // make gcc happy
+  if (msg->getLength() <= 80) {
+    s2 = XmStringCreateLocalized(msg->getCString());
+    XtSetArg(args[n], XmNmessageString, s2); ++n;
+  }
   dialog = XmCreateMessageDialog(drawArea, "questionDialog", args, n);
   XmStringFree(s1);
-  XmStringFree(s2);
+  if (msg->getLength() <= 80) {
+    XmStringFree(s2);
+  } else {
+    n = 0;
+    XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); ++n;
+    if (drawAreaWidth > 300) {
+      XtSetArg(args[n], XmNwidth, drawAreaWidth - 100); ++n;
+    }
+    scroll = XmCreateScrolledWindow(dialog, "scroll", args, n);
+    XtManageChild(scroll);
+    n = 0;
+    XtSetArg(args[n], XmNeditable, False); ++n;
+    XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); ++n;
+    XtSetArg(args[n], XmNvalue, msg->getCString()); ++n;
+    XtSetArg(args[n], XmNshadowThickness, 0); ++n;
+    text = XmCreateText(scroll, "text", args, n);
+    XtManageChild(text);
+  }
   XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
   XtAddCallback(dialog, XmNokCallback,
                &dialogOkCbk, (XtPointer)this);