On Sun, Feb 03, 2008 at 04:38:42PM +0100, Carlos Garcia Campos wrote:
Hi Michael, thank you very much for the patches. I have tested them with several documents and it works pretty well. The only thing that it's still broken is multiline form fields. It was already broken indeed (see bug http://bugzilla.gnome.org/show_bug.cgi?id=499939) but in a different way. Now it seems to enter into an infinite loop after editing a multiline form field.

You can use this file to reproduce the problem:

http://www.okular.org/stuff/forms-scribus.pdf

You're right, there is an infinite loop. It should be fixed now--the test file was very helpful for spotting the problem.

The attached infinite-loop.patch fixes this problem. The problem was in the code that strips trailing space from a line when wrapping. While there, I made another fix so that it does not skip over spaces following a newline character--though I think there are still a few corner cases where line-wrapping may not be quite correct. I'll continue to do some testing and work on this.

I'm also attaching a new version of the original patch with this fix included.

--Michael Vrable
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index e1b7809..44db791 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -1548,17 +1548,17 @@ void Annot::layoutText(GooString *text, GooString *outBuf, int *i,
     }
   }
 
-  // If splitting input into lines, then consume any remaining trailing spaces
-  // that would go on this line from the input.
-  if (widthLimit > 0.0) {
-    while (*i < text->getLength()) {
-      if (unicode) {
-        if (text->getChar(*i) == '\0' && text->getChar(*i + 1) == ' ')
-          *i += 2;
-      } else {
-        if (text->getChar(*i) == ' ')
-          *i += 1;
-      }
+  // If splitting input into lines because we reached the width limit, then
+  // consume any remaining trailing spaces that would go on this line from the
+  // input.
+  if (widthLimit > 0.0 && w > widthLimit) {
+    if (unicode) {
+      while (*i < text->getLength()
+             && text->getChar(*i) == '\0' && text->getChar(*i + 1) == ' ')
+        *i += 2;
+    } else {
+      while (*i < text->getLength() && text->getChar(*i) == ' ')
+        *i += 1;
     }
   }
 
-- 
1.5.3.8

Major rework of text display in form fields code.

This adds support for UTF-16 strings as input, and will recode them to the
appropriate character set for the font.  Some support for CID-keyed fonts
is still missing, but parts are implemented.

The method Annot::layoutText packs a lot of functionality together, but I
could see a good way to split it apart.  It will convert an input text
string from PDFDocEncoding or UTF-16 (autodetected) to the appropriate
encoding for the font which will be used to display the form field.  At the
same time, it can compute the width of the resulting string, and optionally
break the string at a specified width (for wrapping multi-line text).
Text wrapping is integrated with encoding conversion since wrapping is
easiest with the original text (where spaces and newlines are easily
identified), but text widths can only be computed after re-encoding.
---
 poppler/Annot.cc |  460 ++++++++++++++++++++++++++++++++++--------------------
 poppler/Annot.h  |   10 +-
 2 files changed, 295 insertions(+), 175 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index b23be2e..44db791 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -24,6 +24,7 @@
 #include "Annot.h"
 #include "GfxFont.h"
 #include "CharCodeToUnicode.h"
+#include "PDFDocEncoding.h"
 #include "Form.h"
 #include "Error.h"
 #include "Page.h"
@@ -1398,51 +1399,221 @@ void Annot::setColor(Array *a, GBool fill, int adjust) {
   }
 }
 
-void Annot::writeTextString (GooString *text, GooString *appearBuf, int *i, int j,
-                             CharCodeToUnicode *ccToUnicode, GBool password)
+// Grand unified handler for preparing text strings to be drawn into form
+// fields.  Takes as input a text string (in PDFDocEncoding or UTF-16).
+// Converts some or all of this string to the appropriate encoding for the
+// specified font, and computes the width of the text.  Can optionally stop
+// converting when a specified width has been reached, to perform line-breaking
+// for multi-line fields.
+//
+// Parameters:
+//   text: input text string to convert
+//   outBuf: buffer for writing re-encoded string
+//   i: index at which to start converting; will be updated to point just after
+//      last character processed
+//   font: the font which will be used for display
+//   width: computed width (unscaled by font size) will be stored here
+//   widthLimit: if non-zero, stop converting to keep width under this value
+//      (should be scaled down by font size)
+//   charCount: count of number of characters will be stored here
+//   noReencode: if set, do not try to translate the character encoding
+//      (useful for Zapf Dingbats or other unusual encodings)
+//      can only be used with simple fonts, not CID-keyed fonts
+//
+// TODO: Handle surrogate pairs in UTF-16.
+//       Should be able to generate output for CID-keyed fonts.
+//       Doesn't handle vertical fonts--should it?
+void Annot::layoutText(GooString *text, GooString *outBuf, int *i,
+                       GfxFont *font, double *width, double widthLimit,
+                       int *charCount, GBool noReencode)
 {
   CharCode c;
-  int charSize;
-
-  if (*i == 0 && text->hasUnicodeMarker()) {
-    //we need to have an even number of chars
-    if (text->getLength () % 2 != 0) {
-      error(-1, "Annot::writeTextString, bad unicode string");
-      return;
-    }
-    //skip unicode marker an go one char forward because we read character by pairs
-    (*i) += 3;
-    charSize = 2;
-  } else
-    charSize = 1;
-
-  for (; (*i) < j; (*i)+=charSize) {
-    // Render '*' instead of characters for password
-    if (password)
-      appearBuf->append('*');
-    else {
-      c = text->getChar(*i);
-      if (ccToUnicode && text->hasUnicodeMarker()) {
-        char ctmp[2];
-        ctmp[0] = text->getChar((*i)-1);
-        ctmp[1] = text->getChar((*i));
-        ccToUnicode->mapToCharCode((Unicode*)ctmp, &c, 2);
-        if (c == '(' || c == ')' || c == '\\')
-          appearBuf->append('\\');
-        appearBuf->append(c);
+  Unicode uChar;
+  double w = 0.0;
+  int uLen, n;
+  double dx, dy, ox, oy;
+  GBool unicode = text->hasUnicodeMarker();
+  CharCodeToUnicode *ccToUnicode = font->getToUnicode();
+  GBool spacePrev;              // previous character was a space
+
+  // State for backtracking when more text has been processed than fits within
+  // widthLimit.  We track for both input (text) and output (outBuf) the offset
+  // to the first character to discard.
+  //
+  // We keep track of several points:
+  //   1 - end of previous completed word which fits
+  //   2 - previous character which fit
+  int last_i1, last_i2, last_o1, last_o2;
+
+  if (unicode && text->getLength() % 2 != 0) {
+    error(-1, "Annot::layoutText, bad unicode string");
+    return;
+  }
+
+  // skip Unicode marker on string if needed
+  if (unicode && *i == 0)
+    *i = 2;
+
+  // Start decoding and copying characters, until either:
+  //   we reach the end of the string
+  //   we reach the maximum width
+  //   we reach a newline character
+  // As we copy characters, keep track of the last full word to fit, so that we
+  // can backtrack if we exceed the maximum width.
+  last_i1 = last_i2 = *i;
+  last_o1 = last_o2 = 0;
+  spacePrev = false;
+  outBuf->clear();
+
+  while (*i < text->getLength()) {
+    last_i2 = *i;
+    last_o2 = outBuf->getLength();
+
+    if (unicode) {
+      uChar = (unsigned char)(text->getChar(*i)) << 8;
+      uChar += (unsigned char)(text->getChar(*i + 1));
+      *i += 2;
+    } else {
+      if (noReencode)
+        uChar = text->getChar(*i) & 0xff;
+      else
+        uChar = pdfDocEncoding[text->getChar(*i) & 0xff];
+      *i += 1;
+    }
+
+    // Explicit line break?
+    if (uChar == '\r' || uChar == '\n') {
+      // Treat a <CR><LF> sequence as a single line break
+      if (uChar == '\r' && *i < text->getLength()) {
+        if (unicode && text->getChar(*i) == '\0'
+            && text->getChar(*i + 1) == '\n')
+          *i += 2;
+        else if (!unicode && text->getChar(*i) == '\n')
+          *i += 1;
+      }
+
+      break;
+    }
+
+    if (noReencode) {
+      outBuf->append(uChar);
+    } else if (ccToUnicode->mapToCharCode(&uChar, &c, 1)) {
+      // TODO: Output as multiple bytes as appropriate for CID-keyed font
+      outBuf->append(c);
+    } else {
+      fprintf(stderr,
+              "warning: layoutText: cannot convert U+%04X\n", uChar);
+    }
+
+    // If we see a space, then we have a linebreak opportunity.
+    if (uChar == ' ') {
+      last_i1 = *i;
+      if (!spacePrev)
+        last_o1 = last_o2;
+      spacePrev = true;
+    } else {
+      spacePrev = false;
+    }
+
+    // Compute width of character just output
+    if (outBuf->getLength() > last_o2) {
+      dx = 0.0;
+      font->getNextChar(outBuf->getCString() + last_o2,
+                        outBuf->getLength() - last_o2,
+                        &c, &uChar, 1, &uLen, &dx, &dy, &ox, &oy);
+      w += dx;
+    }
+
+    // Current line over-full now?
+    if (widthLimit > 0.0 && w > widthLimit) {
+      // Back up to the last full word to fit, unless this is the first word,
+      // in which case back up to the previous character, unless this is the
+      // first character, in which case stuff it into the current line
+      // regardless.  FIXME: Right now, always backs up a full word.
+      if (last_o1 > 0) {
+        // Back up to the previous word which fit, if there was a previous
+        // word.
+        *i = last_i1;
+        outBuf->del(last_o1, outBuf->getLength() - last_o1);
+      } else if (last_o2 > 0) {
+        // Otherwise, back up to the previous character (in the only word on
+        // this line)
+        *i = last_i2;
+        outBuf->del(last_o2, outBuf->getLength() - last_o2);
       } else {
-        c &= 0xff;
-        if (c == '(' || c == ')' || c == '\\') {
-          appearBuf->append('\\');
-          appearBuf->append(c);
-        } else if (c < 0x20 || c >= 0x80) {
-          appearBuf->appendf("\\{0:03o}", c);
-        } else {
-          appearBuf->append(c);
-        }
+        // Otherwise, we were trying to fit the first character; include it
+        // anyway even if it overflows the space--no updates to make.
+      }
+      break;
+    }
+  }
+
+  // If splitting input into lines because we reached the width limit, then
+  // consume any remaining trailing spaces that would go on this line from the
+  // input.
+  if (widthLimit > 0.0 && w > widthLimit) {
+    if (unicode) {
+      while (*i < text->getLength()
+             && text->getChar(*i) == '\0' && text->getChar(*i + 1) == ' ')
+        *i += 2;
+    } else {
+      while (*i < text->getLength() && text->getChar(*i) == ' ')
+        *i += 1;
+    }
+  }
+
+  // Compute the actual width and character count of the final string, based on
+  // breakpoint, if this information is requested by the caller.
+  if (width != NULL || charCount != NULL) {
+    char *s = outBuf->getCString();
+    int len = outBuf->getLength();
+
+    if (width != NULL)
+      *width = 0.0;
+    if (charCount != NULL)
+      *charCount = 0;
+
+    while (len > 0) {
+      dx = 0.0;
+      n = font->getNextChar(s, len, &c, &uChar, 1, &uLen, &dx, &dy, &ox, &oy);
+
+      if (n == 0) {
+        break;
       }
+
+      if (width != NULL)
+        *width += dx;
+      if (charCount != NULL)
+        *charCount += 1;
+
+      s += n;
+      len -= n;
+    }
+  }
+}
+
+// Copy the given string to appearBuf, adding parentheses around it and
+// escaping characters as appropriate.
+void Annot::writeString(GooString *str, GooString *appearBuf)
+{
+  char c;
+  int i;
+
+  appearBuf->append('(');
+
+  for (i = 0; i < str->getLength(); ++i) {
+    c = str->getChar(i);
+    if (c == '(' || c == ')' || c == '\\') {
+      appearBuf->append('\\');
+      appearBuf->append(c);
+    } else if (c < 0x20) {
+      appearBuf->appendf("\\{0:03o}", (unsigned char)c);
+    } else {
+      appearBuf->append(c);
     }
   }
+
+  appearBuf->append(')');
 }
 
 // Draw the variable text or caption for a field.
@@ -1451,10 +1622,11 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
     GBool txField, GBool forceZapfDingbats,
     GBool password) {
   GooList *daToks;
-  GooString *tok;
+  GooString *tok, *convertedText;
   GfxFont *font;
-  double fontSize, fontSize2, borderWidth, x, xPrev, y, w, w2, wMax;
-  int tfPos, tmPos, i, j, k;
+  double fontSize, fontSize2, borderWidth, x, xPrev, y, w, wMax;
+  int tfPos, tmPos, i, j;
+  GBool freeText = false;       // true if text should be freed before return
 
   //~ if there is no MK entry, this should use the existing content stream,
   //~ and only replace the marked content portion of it
@@ -1523,6 +1695,22 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
   // get the border width
   borderWidth = border ? border->getWidth() : 0;
 
+  // for a password field, replace all characters with asterisks
+  if (password) {
+    int len;
+    if (text->hasUnicodeMarker())
+      len = (text->getLength() - 2) / 2;
+    else
+      len = text->getLength();
+
+    text = new GooString;
+    for (i = 0; i < len; ++i)
+      text->append('*');
+    freeText = true;
+  }
+
+  convertedText = new GooString;
+
   // setup
   if (txField) {
     appearBuf->append("/Tx BMC\n");
@@ -1539,14 +1727,10 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
     if (fontSize == 0) {
       for (fontSize = 20; fontSize > 1; --fontSize) {
         y = rect->y2 - rect->y1;
-        w2 = 0;
         i = 0;
         while (i < text->getLength()) {
-          getNextLine(text, i, font, fontSize, wMax, &j, &w, &k);
-          if (w > w2) {
-            w2 = w;
-          }
-          i = k;
+          layoutText(text, convertedText, &i, font, &w, wMax / fontSize, NULL,
+                     forceZapfDingbats);
           y -= fontSize;
         }
         // approximate the descender for the last line
@@ -1592,8 +1776,9 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
     i = 0;
     xPrev = 0;
     while (i < text->getLength()) {
-
-      getNextLine(text, i, font, fontSize, wMax, &j, &w, &k);
+      layoutText(text, convertedText, &i, font, &w, wMax / fontSize, NULL,
+                 forceZapfDingbats);
+      w *= fontSize;
 
       // compute text start position
       switch (quadding) {
@@ -1611,12 +1796,10 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
 
       // draw the line
       appearBuf->appendf("{0:.2f} {1:.2f} Td\n", x - xPrev, -fontSize);
-      appearBuf->append('(');
-      writeTextString (text, appearBuf, &i, j, font->getToUnicode(), password);
-      appearBuf->append(") Tj\n");
+      writeString(convertedText, appearBuf);
+      appearBuf->append(" Tj\n");
 
       // next line
-      i = k;
       xPrev = x;
     }
 
@@ -1626,6 +1809,8 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
 
     // comb formatting
     if (comb > 0) {
+      int charCount;
+
       // compute comb spacing
       w = (rect->x2 - rect->x1 - 2 * borderWidth) / comb;
 
@@ -1643,17 +1828,23 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
         }
       }
 
-      // compute text start position
+      i = 0;
+      layoutText(text, convertedText, &i, font, NULL, 0.0, &charCount,
+                 forceZapfDingbats);
+      if (charCount > comb)
+        charCount = comb;
+
+      // compute starting text cell
       switch (quadding) {
         case fieldQuadLeft:
         default:
           x = borderWidth + 2;
           break;
         case fieldQuadCenter:
-          x = borderWidth + 2 + 0.5 * (comb - text->getLength()) * w;
+          x = borderWidth + 2 + 0.5 * (comb - charCount) * w;
           break;
         case fieldQuadRight:
-          x = borderWidth + 2 + (comb - text->getLength()) * w;
+          x = borderWidth + 2 + (comb - charCount) * w;
           break;
       }
       y = 0.5 * (rect->y2 - rect->y1) - 0.4 * fontSize;
@@ -1682,29 +1873,37 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
       // write the text string
       //~ this should center (instead of left-justify) each character within
       //~     its comb cell
-      for (i = 0; i < text->getLength(); ++i) {
-        if (i > 0) {
+      char *s = convertedText->getCString();
+      int len = convertedText->getLength();
+      i = 0;
+      while (i < comb && len > 0) {
+        CharCode code;
+        Unicode u;
+        int uLen, n;
+        double dx, dy, ox, oy;
+
+        dx = 0.0;
+        n = font->getNextChar(s, len, &code, &u, 1, &uLen, &dx, &dy, &ox, &oy);
+
+        if (s != convertedText->getCString()) {
+          // Only advance text position if we are not at the first character
           appearBuf->appendf("{0:.2f} 0 Td\n", w);
         }
-        appearBuf->append('(');
-        //~ it would be better to call it only once for the whole string instead of once for
-        //each character => but we need to handle centering in writeTextString
-        writeTextString (text, appearBuf, &i, i+1, font->getToUnicode(), password);
-        appearBuf->append(") Tj\n");
+        GooString *charBuf = new GooString(s, n);
+        writeString(charBuf, appearBuf);
+        appearBuf->append(" Tj\n");
+        delete charBuf;
+
+        i++;
+        s += n;
+        len -= n;
       }
 
       // regular (non-comb) formatting
     } else {
-      // compute string width
-      if (font && !font->isCIDFont()) {
-        w = 0;
-        for (i = 0; i < text->getLength(); ++i) {
-          w += ((Gfx8BitFont *)font)->getWidth(text->getChar(i));
-        }
-      } else {
-        // otherwise, make a crude estimate
-        w = text->getLength() * 0.5;
-      }
+      i = 0;
+      layoutText(text, convertedText, &i, font, &w, 0.0, NULL,
+                 forceZapfDingbats);
 
       // compute font autosize
       if (fontSize == 0) {
@@ -1758,11 +1957,10 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
       if (tmPos < 0) {
         appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
       }
+
       // write the text string
-      appearBuf->append('(');
-      i=0;
-      writeTextString (text, appearBuf, &i, text->getLength(), font->getToUnicode(), password);
-      appearBuf->append(") Tj\n");
+      writeString(convertedText, appearBuf);
+      appearBuf->append(" Tj\n");
     }
   }
   // cleanup
@@ -1774,6 +1972,10 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
   if (daToks) {
     deleteGooList(daToks, GooString);
   }
+  if (freeText) {
+    delete text;
+  }
+  delete convertedText;
 }
 
 // Draw the variable text or caption for a field.
@@ -1781,7 +1983,7 @@ void Annot::drawListBox(GooString **text, GBool *selection,
 			int nOptions, int topIdx,
 			GooString *da, GfxFontDict *fontDict, GBool quadding) {
   GooList *daToks;
-  GooString *tok;
+  GooString *tok, *convertedText;
   GfxFont *font;
   double fontSize, fontSize2, borderWidth, x, y, w, wMax;
   int tfPos, tmPos, i, j;
@@ -1839,6 +2041,8 @@ void Annot::drawListBox(GooString **text, GBool *selection,
     return;
   }
 
+  convertedText = new GooString;
+
   // get the border width
   borderWidth = border ? border->getWidth() : 0;
 
@@ -1846,15 +2050,8 @@ void Annot::drawListBox(GooString **text, GBool *selection,
   if (fontSize == 0) {
     wMax = 0;
     for (i = 0; i < nOptions; ++i) {
-      if (font && !font->isCIDFont()) {
-        w = 0;
-        for (j = 0; j < text[i]->getLength(); ++j) {
-          w += ((Gfx8BitFont *)font)->getWidth(text[i]->getChar(j));
-        }
-      } else {
-        // otherwise, make a crude estimate
-        w = text[i]->getLength() * 0.5;
-      }
+      j = 0;
+      layoutText(text[i], convertedText, &j, font, &w, 0.0, NULL, false);
       if (w > wMax) {
         wMax = w;
       }
@@ -1890,18 +2087,9 @@ void Annot::drawListBox(GooString **text, GBool *selection,
     // setup
     appearBuf->append("BT\n");
 
-    // compute string width
-    if (font && !font->isCIDFont()) {
-      w = 0;
-      for (j = 0; j < text[i]->getLength(); ++j) {
-        w += ((Gfx8BitFont *)font)->getWidth(text[i]->getChar(j));
-      }
-    } else {
-      // otherwise, make a crude estimate
-      w = text[i]->getLength() * 0.5;
-    }
-
-    // compute text start position
+    // compute text width and start position
+    j = 0;
+    layoutText(text[i], convertedText, &j, font, &w, 0.0, NULL, false);
     w *= fontSize;
     switch (quadding) {
       case fieldQuadLeft:
@@ -1944,10 +2132,8 @@ void Annot::drawListBox(GooString **text, GBool *selection,
     }
 
     // write the text string
-    appearBuf->append('(');
-    j = 0;
-    writeTextString (text[i], appearBuf, &j, text[i]->getLength(), font->getToUnicode(), false);
-    appearBuf->append(") Tj\n");
+    writeString(convertedText, appearBuf);
+    appearBuf->append(" Tj\n");
 
     // cleanup
     appearBuf->append("ET\n");
@@ -1960,72 +2146,8 @@ void Annot::drawListBox(GooString **text, GBool *selection,
   if (daToks) {
     deleteGooList(daToks, GooString);
   }
-}
-
-// Figure out how much text will fit on the next line.  Returns:
-// *end = one past the last character to be included
-// *width = width of the characters start .. end-1
-// *next = index of first character on the following line
-void Annot::getNextLine(GooString *text, int start,
-    GfxFont *font, double fontSize, double wMax,
-    int *end, double *width, int *next) {
-  double w, dw;
-  int j, k, c;
 
-  // figure out how much text will fit on the line
-  //~ what does Adobe do with tabs?
-  w = 0;
-  for (j = start; j < text->getLength() && w <= wMax; ++j) {
-    c = text->getChar(j) & 0xff;
-    if (c == 0x0a || c == 0x0d) {
-      break;
-    }
-    if (font && !font->isCIDFont()) {
-      dw = ((Gfx8BitFont *)font)->getWidth(c) * fontSize;
-    } else {
-      // otherwise, make a crude estimate
-      dw = 0.5 * fontSize;
-    }
-    w += dw;
-  }
-  if (w > wMax) {
-    for (k = j; k > start && text->getChar(k-1) != ' '; --k) ;
-    for (; k > start && text->getChar(k-1) == ' '; --k) ;
-    if (k > start) {
-      j = k;
-    }
-    if (j == start) {
-      // handle the pathological case where the first character is
-      // too wide to fit on the line all by itself
-      j = start + 1;
-    }
-  }
-  *end = j;
-
-  // compute the width
-  w = 0;
-  for (k = start; k < j; ++k) {
-    if (font && !font->isCIDFont()) {
-      dw = ((Gfx8BitFont *)font)->getWidth(text->getChar(k)) * fontSize;
-    } else {
-      // otherwise, make a crude estimate
-      dw = 0.5 * fontSize;
-    }
-    w += dw;
-  }
-  *width = w;
-
-  // next line
-  while (j < text->getLength() && text->getChar(j) == ' ') {
-    ++j;
-  }
-  if (j < text->getLength() && text->getChar(j) == 0x0d) {
-    ++j;
-  }
-  if (j < text->getLength() && text->getChar(j) == 0x0a) {
-    ++j;
-  }
-  *next = j;
+  delete convertedText;
 }
 
 // Draw an (approximate) circle of radius <r> centered at (<cx>, <cy>).
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 0ae07e8..f22b955 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -473,16 +473,14 @@ private:
   void drawListBox(GooString **text, GBool *selection,
 		   int nOptions, int topIdx,
 		   GooString *da, GfxFontDict *fontDict, GBool quadding);
-  void getNextLine(GooString *text, int start,
-		   GfxFont *font, double fontSize, double wMax,
-		   int *end, double *width, int *next);
   void drawCircle(double cx, double cy, double r, GBool fill);
   void drawCircleTopLeft(double cx, double cy, double r);
   void drawCircleBottomRight(double cx, double cy, double r);
   void readArrayNum(Object *pdfArray, int key, double *value);
-  // write vStr[i:j[ in appearBuf
-  void writeTextString (GooString *text, GooString *appearBuf, int *i, int j, CharCodeToUnicode *ccToUnicode, GBool password); 
-
+  void layoutText(GooString *text, GooString *outBuf, int *i, GfxFont *font,
+                  double *width, double widthLimit, int *charCount,
+                  GBool noReencode);
+  void writeString(GooString *str, GooString *appearBuf);
   void initialize (XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog);
 
 protected:
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to