home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Magazine / UsingPDF / GhostScript / source / gs5.10 / gdevpdft.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-08  |  23.5 KB  |  756 lines

  1. /* Copyright (C) 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevpdft.c */
  20. /* Text handling for PDF-writing driver. */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "string_.h"
  24. #include "gx.h"
  25. #include "gserrors.h"
  26. #include "gsutil.h"            /* for bytes_compare */
  27. #include "gdevpdfx.h"
  28. #include "scommon.h"
  29.  
  30. /*
  31.  * When a base font is selected, we have many alternatives for how to handle
  32.  * characters whose encoding doesn't match their encoding in the base font's
  33.  * built-in encoding.  If a character's glyph doesn't match the character's
  34.  * glyph in the encoding built up so far, we check if the font has that
  35.  * glyph at all; if not, we fall back to a bitmap.  Otherwise, we use one
  36.  * or both of the following algorithms:
  37.  *
  38.  *    1. If this is the first time a character at this position has been
  39.  *    seen, assign its glyph to that position in the encoding.
  40.  *    We do this step if the device parameter ReAssignCharacters is true.
  41.  *    (This is the default.)
  42.  *
  43.  *    2. If the glyph is present in the encoding at some other position,
  44.  *    substitute that position for the character; otherwise, assign the
  45.  *    glyph to an unoccupied (.notdef) position.
  46.  *    We do this step if the device parameter ReEncodeCharacters is true.
  47.  *    (This is the default.)
  48.  *
  49.  *    3. Finally, fall back to using bitmaps (for the entire string).
  50.  *
  51.  * If it is essential that all strings in the output contain exactly the
  52.  * same character codes as the input, set ReEncodeCharacters to false.  If
  53.  * it is important that strings be searchable, but some non-searchable
  54.  * strings can be tolerated, the defaults are appropriate.  If searchability
  55.  * is not important, set ReAssignCharacters to false.
  56.  */
  57.  
  58. /*
  59.  * The show pseudo-parameter is currently the way that the PostScript code
  60.  * passes show operations to the PDF writer.  It is a hack!  Its "value"
  61.  * is a dictionary with the following keys and values:
  62.  *    /String (str)
  63.  *    /Values [cx cy char ax ay px py]
  64.  *    /FontName /fontname
  65.  *    /Matrix [xx xy yx yy tx ty]
  66.  *    /Encoding [e0 .. e255] (optional)
  67.  *    /BaseEncoding [e0 ... e255] (optional)
  68. %    /CharStrings << charnames => anything >> (optional)
  69.  * Note that px/y and tx/y are floating point values in device space;
  70.  * cx/y and ax/y are in text space.  The matrix is the concatenation of
  71.  *    FontMatrix
  72.  *    inverse of base FontMatrix
  73.  *    CTM
  74.  * This represents the transformation from a 1-unit-based character space
  75.  * to device space.  The base encoding is StandardEncoding for all fonts
  76.  * except Symbol and ZapfDingbats; the encodings are not passed if the
  77.  * encoding is eq to the base encoding, since in this case no check for
  78.  * whether the string is encodable in the base encoding is needed.
  79.  */
  80.  
  81. /* Define the 14 standard built-in fonts. */
  82. private const char *standard_font_names[] = {
  83.   "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
  84.   "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique",
  85.   "Symbol",
  86.   "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",
  87.   "ZapfDingbats",
  88.   0
  89. };
  90.  
  91. /* Define StandardEncoding. */
  92. private const char notdef_string[] = ".notdef";
  93. #define notdef notdef_string
  94. private const char *std_enc_strings[256] = {
  95.   /* \00x */
  96.     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
  97.     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
  98.     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
  99.     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
  100.   /* \04x */
  101.     "space", "exclam", "quotedbl", "numbersign",
  102.       "dollar", "percent", "ampersand", "quoteright",
  103.     "parenleft", "parenright", "asterisk", "plus",
  104.       "comma", "hyphen", "period", "slash",
  105.     "zero", "one", "two", "three",
  106.       "four", "five", "six", "seven",
  107.     "eight", "nine", "colon", "semicolon",
  108.       "less", "equal", "greater", "question",
  109.   /* \10x */
  110.     "at", "A", "B", "C", "D", "E", "F", "G",
  111.     "H", "I", "J", "K", "L", "M", "N", "O",
  112.     "P", "Q", "R", "S", "T", "U", "V", "W",
  113.     "X", "Y", "Z", "bracketleft",
  114.       "backslash", "bracketright", "asciicircum", "underscore",
  115.   /* \14x */
  116.     "quoteleft", "a", "b", "c", "d", "e", "f", "g",
  117.     "h", "i", "j", "k", "l", "m", "n", "o",
  118.     "p", "q", "r", "s", "t", "u", "v", "w",
  119.     "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", notdef,
  120.   /* \20x */
  121.     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
  122.     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
  123.     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
  124.     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
  125.   /* \24x */
  126.     notdef, "exclamdown", "cent", "sterling",
  127.       "fraction", "yen", "florin", "section",
  128.     "currency", "quotesingle", "quotedblleft", "guillemotleft",
  129.       "guilsinglleft", "guilsinglright", "fi", "fl",
  130.     notdef, "endash", "dagger", "daggerdbl",
  131.       "periodcentered", notdef, "paragraph", "bullet",
  132.     "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright",
  133.       "ellipsis", "perthousand", notdef, "questiondown",
  134.   /* \30x */
  135.     notdef, "grave", "acute", "circumflex",
  136.       "tilde", "macron", "breve", "dotaccent",
  137.     "dieresis", notdef, "ring", "cedilla",
  138.       notdef, "hungarumlaut", "ogonek", "caron",
  139.     "emdash", notdef, notdef, notdef,
  140.       notdef, notdef, notdef, notdef,
  141.     notdef, notdef, notdef, notdef,
  142.       notdef, notdef, notdef, notdef,
  143.   /* \34x", */
  144.     notdef, "AE", notdef, "ordfeminine", notdef, notdef, notdef, notdef,
  145.     "Lslash", "Oslash", "OE", "ordmasculine", notdef, notdef, notdef, notdef,
  146.     notdef, "ae", notdef, notdef, notdef, "dotlessi", notdef, notdef,
  147.     "lslash", "oslash", "oe", "germandbls", notdef, notdef, notdef, notdef
  148. };
  149. #undef notdef
  150.  
  151. /* Forward references */
  152. private int pdf_set_font_and_size(P3(gx_device_pdf *pdev, pdf_font *font,
  153.                      floatp size));
  154. private int pdf_set_text_matrix(P2(gx_device_pdf *pdev,
  155.                    const gs_matrix *pmat));
  156. private int pdf_append_chars(P3(gx_device_pdf *pdev, const byte *str,
  157.                 uint size));
  158. private int pdf_check_encoding(P6(gx_device_pdf *pdev, gs_param_string *pstr,
  159.                   const gs_param_dict *ptd,
  160.                   byte *strbuf, int max_strbuf,
  161.                   pdf_font *ppf));
  162.  
  163. /* Process a show operation. */
  164. int
  165. pdfshow_process(gx_device_pdf *pdev, const gs_param_dict *ptd)
  166. {
  167. #define plist (ptd->list)
  168.     gs_param_string str, fnstr;
  169.     gs_param_float_array va;
  170. #define v_cx va.data[0]
  171. #define v_cy va.data[1]
  172. #define v_cch (int)va.data[2]
  173. #define v_ax va.data[3]
  174. #define v_ay va.data[4]
  175. #define v_px va.data[5]
  176. #define v_py va.data[6]
  177.     gs_param_float_array ma;
  178.     int code;
  179.     pdf_font *ppf;
  180.     stream *s;
  181.     double sx = pdev->HWResolution[0] / 72.0,
  182.       sy = pdev->HWResolution[1] / 72.0;
  183.     float size;
  184.     byte strbuf[200];
  185.  
  186.     if ( (code = param_read_string(plist, "String", &str)) )
  187.       return_error(gs_error_rangecheck);
  188.     if ( str.size == 0 )
  189.       return 0;        /* nothing to do */
  190.     /* Find or create the font resource. */
  191.     if ( (code = param_read_string(plist, "FontName", &fnstr)) )
  192.       return_error(gs_error_rangecheck);
  193.     { int i;
  194.  
  195.       for ( i = 0; i < num_resource_chains; ++i )
  196.         for ( ppf = (pdf_font *)pdev->resources[resourceFont].chains[i];
  197.           ppf != 0; ppf = ppf->next
  198.         )
  199.           if ( !bytes_compare(ppf->fname.chars, ppf->fname.size,
  200.                   fnstr.data, fnstr.size)
  201.          )
  202.         goto found;
  203. found:      DO_NOTHING;
  204.     }
  205.     if ( ppf == 0 ) {
  206.         /*
  207.          * Currently, we only handle the built-in fonts.  By doing
  208.          * things in this order, we may wind up including some base
  209.          * fonts that aren't actually needed, but it's unlikely.
  210.          */
  211.         const char **ppfn;
  212.  
  213.         for ( ppfn = standard_font_names; *ppfn; ++ppfn )
  214.           if ( strlen(*ppfn) == fnstr.size &&
  215.                !strncmp(*ppfn, (const char *)fnstr.data, fnstr.size)
  216.              )
  217.             break;
  218.         if ( !*ppfn )
  219.           return_error(gs_error_undefined);
  220.         /*
  221.          * Allocate the font resource, but don't write it yet,
  222.          * because we don't know yet whether it will need
  223.          * a modified Encoding.
  224.          */
  225.         code = pdf_alloc_resource(pdev, resourceFont, gs_no_id,
  226.                       (pdf_resource **)&ppf);
  227.         if ( code < 0 )
  228.           return_error(gs_error_undefined);
  229.         memcpy(ppf->fname.chars, fnstr.data, fnstr.size);
  230.         ppf->fname.size = fnstr.size;
  231.         ppf->frname[0] = 0;    /* not an embedded font */
  232.         memset(ppf->chars_used, 0, sizeof(ppf->chars_used));
  233.         ppf->differences = 0;
  234.         ppf->num_chars = 0;    /* ditto */
  235.         ppf->char_procs = 0;    /* for GC */
  236.     }
  237.     /* Check that all characters can be encoded. */
  238.     code = pdf_check_encoding(pdev, &str, ptd, strbuf, sizeof(strbuf), ppf);
  239.     if ( code < 0 )
  240.       return code;
  241.     /* Read and check the rest of the parameters now. */
  242.     if ( (code = param_read_float_array(plist, "Values", &va)) ||
  243.          va.size != 7 ||
  244.          (code = param_read_float_array(plist, "Matrix", &ma)) ||
  245.          ma.size != 6
  246.        )
  247.       return_error(gs_error_rangecheck);
  248.     if ( v_cy != 0 || (v_cch != 32 && v_cx != 0) || v_ay != 0 )
  249.       return_error(gs_error_undefined);
  250.     /* Try to find a reasonable size value.  This isn't necessary, */
  251.     /* but it's worth the effort. */
  252.     size = fabs(ma.data[0]) / sx;
  253.     if ( size < 0.01 )
  254.       size = fabs(ma.data[1]) / sy;
  255.     if ( size < 0.01 )
  256.       size = 1;
  257.     /* We attempt to eliminate redundant parameter settings. */
  258.     pdf_set_font_and_size(pdev, ppf, size);
  259.     { float chars = v_ax * size;
  260.  
  261.       if ( pdev->text.character_spacing != chars )
  262.         { code = pdf_open_contents(pdev, pdf_in_text);
  263.           if ( code < 0 )
  264.         return code;
  265.           s = pdev->strm;
  266.           pprintg1(s, "%g Tc\n", chars);
  267.           pdev->text.character_spacing = chars;
  268.         }
  269.     }
  270.     { float words = v_cx * size;
  271.  
  272.       if ( pdev->text.word_spacing != words )
  273.         { code = pdf_open_contents(pdev, pdf_in_text);
  274.           if ( code < 0 )
  275.         return code;
  276.           s = pdev->strm;
  277.           pprintg1(s, "%g Tw\n", words);
  278.           pdev->text.word_spacing = words;
  279.         }
  280.     }
  281.     { gs_matrix tmat;
  282.  
  283.       tmat.xx = ma.data[0] / size;
  284.       tmat.xy = ma.data[1] / size;
  285.       tmat.yx = ma.data[2] / size;
  286.       tmat.yy = ma.data[3] / size;
  287.       tmat.tx = v_px + ma.data[4];
  288.       tmat.ty = v_py + ma.data[5];
  289.       pdf_set_text_matrix(pdev, &tmat);
  290.     }
  291.  
  292.     /* If we re-encoded the string, pdf_check_encoding changed */
  293.     /* str.data to strbuf. */
  294.     return pdf_append_chars(pdev, str.data, str.size);
  295. }
  296.  
  297. /* Create an encoding differences vector for a font. */
  298. private int
  299. pdf_create_differences(gx_device_pdf *pdev, pdf_font *ppf)
  300. {    gs_const_string *pdiff = ppf->differences;
  301.     int i;
  302.  
  303.     if ( pdiff != 0 )
  304.       return 0;
  305.     ppf->diff_id = pdf_obj_ref(pdev);
  306.     pdiff = gs_alloc_struct_array(pdev->pdf_memory, 256, gs_const_string,
  307.                       &st_const_string_element,
  308.                       "differences");
  309.     if ( pdiff == 0 )
  310.       return_error(gs_error_VMerror);
  311.     for ( i = 0; i < 256; ++i )
  312.       pdiff[i].data = 0, pdiff[i].size = 0;
  313.     ppf->differences = pdiff;
  314.     return 0;
  315. }
  316.  
  317. /*
  318.  * Check whether the encodings are compatible, and if not,
  319.  * whether we can re-encode the string using the base encoding.
  320.  */
  321. private int
  322. pdf_check_encoding(gx_device_pdf *pdev, gs_param_string *pstr,
  323.   const gs_param_dict *ptd, byte *strbuf, int max_strbuf, pdf_font *ppf)
  324. {    gs_param_string_array ea, bea;
  325.     int code;
  326.     gs_const_string *pdiff = ppf->differences;
  327.     uint i;
  328.  
  329.     ea.data = bea.data = 0;
  330.     switch ( (code = param_read_name_array(ptd->list, "Encoding", &ea)) )
  331.       {
  332.       default:
  333.         return code;
  334.       case 0:
  335.         if ( ea.size != 256 )
  336.           return_error(gs_error_rangecheck);
  337.       case 1:
  338.         DO_NOTHING;
  339.       }
  340.     switch ( (code = param_read_name_array(ptd->list, "BaseEncoding", &bea)) )
  341.       {
  342.       default:
  343.         return code;
  344.       case 0:
  345.         if ( bea.size != 256 )
  346.           return_error(gs_error_rangecheck);
  347.       case 1:
  348.         DO_NOTHING;
  349.       }
  350.  
  351.     if ( ea.data == bea.data && pdiff == 0 ) {
  352.       /*
  353.        * Just note the characters that have been used with their
  354.        * original encodings.
  355.        */
  356.       for ( i = 0; i < pstr->size; ++i ) {
  357.         byte chr = pstr->data[i];
  358.  
  359.         ppf->chars_used[chr >> 3] |= 1 << (chr & 7);
  360.       }
  361.       return 0;        /* encodings are the same */
  362.     }
  363.     for ( i = 0; i < pstr->size; ++i )
  364.         { byte chr = pstr->data[i];
  365. #define set_encoded(sdata, ssize, ch)\
  366.   (pdiff != 0 && pdiff[ch].data != 0 ?\
  367.    (sdata = pdiff[ch].data, ssize = pdiff[ch].size) :\
  368.    bea.data == 0 ?\
  369.    (sdata = (const byte *)std_enc_strings[ch],\
  370.     ssize = strlen((const char *)sdata)) :\
  371.    (sdata = bea.data[ch].data, ssize = bea.data[ch].size))
  372.           const byte *fedata;
  373.           uint fesize;
  374.           const byte *edata;
  375.           uint esize;
  376.  
  377.           set_encoded(fedata, fesize, chr);
  378.           if ( ea.data == 0 )
  379.         esize = strlen(edata = (const byte *)std_enc_strings[chr]);
  380.           else
  381.         edata = ea.data[chr].data, esize = ea.data[chr].size;
  382.           if ( edata == fedata ||
  383.            (esize == fesize &&
  384.             !memcmp(edata, fedata, esize))
  385.          )
  386.         ppf->chars_used[chr >> 3] |= 1 << (chr & 7);
  387.           else
  388.         {
  389.           if ( pdev->ReAssignCharacters ) {
  390.             /*
  391.              * If this is the first time we've seen this character,
  392.              * assign the glyph to its position in the encoding.
  393.              */
  394.             if ( (pdiff == 0 || pdiff[chr].data == 0) &&
  395.              !(ppf->chars_used[chr >> 3] & (1 << (chr & 7)))
  396.                ) {
  397.               int code = pdf_create_differences(pdev, ppf);
  398.  
  399.               if ( code < 0 )
  400.             return code;
  401.               pdiff = ppf->differences;
  402.               /*
  403.                * Since the entry in ea is the string for a name,
  404.                * or a const C string, we don't need to copy it.
  405.                */
  406.               pdiff[chr].data = edata;
  407.               pdiff[chr].size = esize;
  408.               continue;
  409.             }
  410.           }
  411.           if ( pdev->ReEncodeCharacters ) {
  412.             /*
  413.              * Look for the character at some other position in the
  414.              * encoding.
  415.              */
  416.             int c;
  417.  
  418.             for ( c = 0; c < 256; ++c ) {
  419.               set_encoded(fedata, fesize, c);
  420.               if ( esize == fesize && !memcmp(edata, fedata, esize) )
  421.             break;
  422.             }
  423.             if ( c == 256 ) {
  424.               /*
  425.                * The character isn't encoded anywhere.  Look for a
  426.                * never-referenced .notdef position where we can put
  427.                * it.
  428.                */
  429.               int code;
  430.  
  431.               for ( c = 0; c < 256; ++c ) {
  432.             set_encoded(fedata, fesize, c);
  433.             if ( !bytes_compare(fedata, fesize,
  434.                         (const byte *)".notdef", 7) &&
  435.                  !(ppf->chars_used[c >> 3] & (1 << (c & 7)))
  436.                )
  437.               break;
  438.               }
  439.               if ( c == 256 ) /* no .notdef positions left */
  440.             return_error(gs_error_undefined);
  441.               code = pdf_create_differences(pdev, ppf);
  442.               if ( code < 0 )
  443.             return code;
  444.               ppf->differences[c].data = edata;
  445.               ppf->differences[c].size = esize;
  446.             }
  447.             /*
  448.              * It really simplifies things if we can buffer
  449.              * the entire string locally in one piece....
  450.              */
  451.             if ( pstr->data != strbuf ) {
  452.               if ( pstr->size > max_strbuf )
  453.                 return_error(gs_error_limitcheck);
  454.               memcpy(strbuf, pstr->data, pstr->size);
  455.               pstr->data = strbuf;
  456.             }
  457.             strbuf[i] = (byte)c;
  458.             continue;
  459.           }
  460.           return_error(gs_error_undefined);
  461.         }
  462.         }
  463.     return 0;
  464. }
  465.  
  466. /* ---------------- Embedded fonts ---------------- */
  467.  
  468. /*
  469.  * Set the current font and size, writing a Tf command if needed.
  470.  */
  471. private int
  472. pdf_set_font_and_size(gx_device_pdf *pdev, pdf_font *font, floatp size)
  473. {    if ( font != pdev->text.font || size != pdev->text.size )
  474.       { int code = pdf_open_contents(pdev, pdf_in_text);
  475.         stream *s = pdev->strm;
  476.  
  477.         if ( code < 0 )
  478.           return code;
  479.         if ( font->frname[0] )
  480.           pprints1(s, "/%s ", font->frname);
  481.         else
  482.           pprintld1(s, "/R%ld ", font->id);
  483.         pprintg1(s, "%g Tf\n", size);
  484.         pdev->text.font = font;
  485.         pdev->text.size = size;
  486.       }
  487.     font->used_on_page = true;
  488.     return 0;
  489. }
  490.  
  491. /* Assign a code for a char_proc. */
  492. private int
  493. assign_char_code(gx_device_pdf *pdev)
  494. {    pdf_font *font = pdev->open_font;
  495.  
  496.     if ( font == 0 )
  497.       { /* This is the very first embedded font. */
  498.         /* Create the (canned) Encoding array. */
  499.         long id = pdf_begin_separate(pdev);
  500.         stream *s = pdev->strm;
  501.         int i;
  502.  
  503.         /*
  504.          * Even though the PDF reference documentation says that a
  505.          * BaseEncoding key is required unless the encoding is
  506.          * "based on the base font's encoding" (and there is no base
  507.          * font in this case), Acrobat 2.1 gives an error if the
  508.          * BaseEncoding key is present.
  509.          */
  510.         pputs(s, "<</Type/Encoding/Differences[0");
  511.         for ( i = 0; i < 256; ++i )
  512.           { if ( !(i & 15) )
  513.           pputs(s, "\n");
  514.             pprintd1(s, "/a%d", i);
  515.           }
  516.         pputs(s, "\n] >>\n");
  517.         pdf_end_separate(pdev);
  518.         pdev->embedded_encoding_id = id;
  519.       }
  520.     if ( font == 0 || font->num_chars == 256 )
  521.       { /* Start a new embedded font. */
  522.         pdf_resource *pres;
  523.         int code = pdf_alloc_resource(pdev, resourceFont, gs_no_id, &pres);
  524.         char *pc;
  525.  
  526.         if ( code < 0 )
  527.           return code;
  528.         font = (pdf_font *)pres;
  529.         font->fname.size = 0;
  530.         font->used_on_page = false;
  531.         if ( pdev->open_font == 0 )
  532.           memset(font->frname, 0, sizeof(font->frname));
  533.         else
  534.           strcpy(font->frname, pdev->open_font->frname);
  535.         for ( pc = font->frname; *pc == 'Z'; ++pc )
  536.           *pc = '@';
  537.         if ( (*pc)++ == 0 )
  538.           *pc = 'A', pc[1] = 0;
  539.         font->differences = 0;
  540.         font->num_chars = 0;
  541.         font->char_procs = 0;
  542.         font->max_y_offset = 0;
  543.         memset(font->spaces, 0, sizeof(font->spaces));
  544.         pdev->open_font = font;
  545.       }
  546.     return font->num_chars++;
  547. }
  548.  
  549. /*
  550.  * Set the text matrix for writing text.
  551.  * The translation component of the matrix is the text origin.
  552.  * If the non-translation components of the matrix differ from the
  553.  * current ones, write a Tm command; otherwise, write either a Td command
  554.  * or a Tj command using space pseudo-characters.
  555.  * Do not write a \n after the command.
  556.  */
  557. private int
  558. set_text_distance(gs_point *pdist, const gs_point *ppt, const gs_matrix *pmat)
  559. {    double rounded;
  560.  
  561.     gs_distance_transform_inverse(pmat->tx - ppt->x, pmat->ty - ppt->y,
  562.                       pmat, pdist);
  563.     /* If the distance is very close to integers, round it. */
  564.     if ( fabs(pdist->x - (rounded = floor(pdist->x + 0.5))) < 0.0005 )
  565.       pdist->x = rounded;
  566.     if ( fabs(pdist->y - (rounded = floor(pdist->y + 0.5))) < 0.0005 )
  567.       pdist->y = rounded;
  568.     return 0;
  569. }
  570. private int
  571. pdf_set_text_matrix(gx_device_pdf *pdev, const gs_matrix *pmat)
  572. {    stream *s = pdev->strm;
  573.     double sx = 72.0 / pdev->HWResolution[0],
  574.       sy = 72.0 / pdev->HWResolution[1];
  575.     int code;
  576.  
  577.     if ( pmat->xx == pdev->text.matrix.xx &&
  578.          pmat->xy == pdev->text.matrix.xy &&
  579.          pmat->yx == pdev->text.matrix.yx &&
  580.          pmat->yy == pdev->text.matrix.yy &&
  581.          /*
  582.           * If we aren't already in text context, BT will reset
  583.           * the text matrix.
  584.           */
  585.          (pdev->context == pdf_in_text || pdev->context == pdf_in_string)
  586.        )
  587.       { /* Use Td or a pseudo-character. */
  588.         gs_point dist;
  589.  
  590.         set_text_distance(&dist, &pdev->text.current, pmat);
  591.         if ( dist.y == 0 && dist.x >= x_space_min &&
  592.          dist.x <= x_space_max &&
  593.          pdev->text.font != 0 &&
  594.          font_is_embedded(pdev->text.font)
  595.            )
  596.           { /* Use a pseudo-character. */
  597.         int dx = (int)dist.x;
  598.         int dx_i = dx - x_space_min;
  599.         byte space_char = pdev->text.font->spaces[dx_i];
  600.  
  601.         if ( space_char == 0 )
  602.           { if ( pdev->text.font != pdev->open_font )
  603.               goto td;
  604.             code = assign_char_code(pdev);
  605.             if ( code <= 0 )
  606.               goto td;
  607.             space_char =
  608.               pdev->open_font->spaces[dx_i] =
  609.                 (byte)code;
  610.             if ( pdev->space_char_ids[dx_i] == 0 )
  611.               { /* Create the space char_proc now. */
  612.             char spstr[3 + 14 + 1];
  613.                 stream *s;
  614.  
  615.                 sprintf(spstr, "%d 0 0 0 0 0 d1\n", dx);
  616.                 pdev->space_char_ids[dx_i] = pdf_begin_separate(pdev);
  617.             s = pdev->strm;
  618.             pprintd1(s, "<</Length %d>>\nstream\n", strlen(spstr));
  619.             pprints1(s, "%sendstream\n", spstr);
  620.             pdf_end_separate(pdev);
  621.               }
  622.               }
  623.         pdf_append_chars(pdev, &space_char, 1);
  624.         pdev->text.current.x += dist.x * pmat->xx;
  625.         return 0;
  626.           }
  627. td:        /* Use Td. */
  628.         code = pdf_open_page(pdev, pdf_in_text);
  629.         if ( code < 0 )
  630.           return code;
  631.         set_text_distance(&dist, &pdev->text.line_start, pmat);
  632.         pprintg2(s, "%g %g Td", dist.x, dist.y);
  633.       }
  634.     else
  635.       { /* Use Tm. */
  636.         code = pdf_open_page(pdev, pdf_in_text);
  637.         if ( code < 0 )
  638.           return code;
  639.         /*
  640.          * See stream_to_text in gdevpdf.c for why we need the following
  641.          * matrix adjustments.
  642.          */
  643.         pprintg6(pdev->strm, "%g %g %g %g %g %g Tm",
  644.              pmat->xx * sx, pmat->xy * sy,
  645.              pmat->yx * sx, pmat->yy * sy,
  646.              pmat->tx * sx, pmat->ty * sy);
  647.         pdev->text.matrix = *pmat;
  648.       }
  649.     pdev->text.line_start.x = pmat->tx;
  650.     pdev->text.line_start.y = pmat->ty;
  651.     pdev->text.current.x = pmat->tx;
  652.     pdev->text.current.y = pmat->ty;
  653.     return 0;
  654. }
  655.  
  656. /* Append characters to a string being accumulated. */
  657. private int
  658. pdf_append_chars(gx_device_pdf *pdev, const byte *str, uint size)
  659. {    const byte *p = str;
  660.     uint left = size;
  661.  
  662.     while ( left )
  663.       if ( pdev->text.buffer_count == max_text_buffer )
  664.         { int code = pdf_open_contents(pdev, pdf_in_text);
  665.  
  666.           if ( code < 0 )
  667.         return code;
  668.         }
  669.       else
  670.         { int code = pdf_open_contents(pdev, pdf_in_string);
  671.           uint copy;
  672.  
  673.           if ( code < 0 )
  674.         return code;
  675.           copy = min(max_text_buffer - pdev->text.buffer_count, left);
  676.           memcpy(pdev->text.buffer + pdev->text.buffer_count, p, copy);
  677.           pdev->text.buffer_count += copy;
  678.           p += copy;
  679.           left -= copy;
  680.         }
  681.     return 0;
  682. }
  683.  
  684. /* Begin a CharProc for an embedded (bitmap) font. */
  685. int
  686. pdf_begin_char_proc(gx_device_pdf *pdev, int w, int h, int x_width,
  687.   int y_offset, gs_id id, pdf_char_proc **ppcp, pdf_stream_position *ppos)
  688. {    pdf_resource *pres;
  689.     pdf_char_proc *pcp;
  690.     int char_code = assign_char_code(pdev);
  691.     pdf_font *font = pdev->open_font;
  692.     int code;
  693.  
  694.     if ( char_code < 0 )
  695.       return char_code;
  696.     code = pdf_begin_resource(pdev, resourceCharProc, id, &pres);
  697.     if ( code < 0 )
  698.       return code;
  699.     pcp = (pdf_char_proc *)pres;
  700.     pcp->font = font;
  701.     pcp->char_next = font->char_procs;
  702.     font->char_procs = pcp;
  703.     pcp->char_code = char_code;
  704.     pcp->width = w;
  705.     pcp->height = h;
  706.     pcp->x_width = x_width;
  707.     pcp->y_offset = y_offset;
  708.     font->max_y_offset = max(font->max_y_offset, h + (h >> 2));
  709.     *ppcp = pcp;
  710.     { stream *s = pdev->strm;
  711.       /*
  712.        * The resource file is positionable, so rather than use an
  713.        * object reference for the length, we'll go back and fill it in
  714.        * at the end of the definition.  Take 10K as the longest
  715.        * definition we can handle.
  716.        */
  717.       pputs(s, "<</Length     >>\nstream\n");
  718.       ppos->start_pos = stell(s);
  719.     }
  720.     return 0;
  721. }
  722.  
  723. /* End a CharProc. */
  724. int
  725. pdf_end_char_proc(gx_device_pdf *pdev, pdf_stream_position *ppos)
  726. {    stream *s = pdev->strm;
  727.     long start_pos = ppos->start_pos;
  728.     long end_pos = stell(s);
  729.     long length = end_pos - start_pos;
  730.  
  731.     if ( length > 9999 )
  732.       return_error(gs_error_limitcheck);
  733.     sseek(s, start_pos - 14);
  734.     pprintd1(s, "%d", length);
  735.     sseek(s, end_pos);
  736.     pputs(s, "endstream\n");
  737.     pdf_end_separate(pdev);
  738.     return 0;
  739. }
  740.  
  741. /* Put out a reference to an image as a character in an embedded font. */
  742. int
  743. pdf_do_char_image(gx_device_pdf *pdev, const pdf_char_proc *pcp,
  744.   const gs_matrix *pimat)
  745. {    pdf_set_font_and_size(pdev, pcp->font, 1.0);
  746.     { gs_matrix tmat;
  747.  
  748.       tmat = *pimat;
  749.       tmat.ty -= pcp->y_offset;
  750.       pdf_set_text_matrix(pdev, &tmat);
  751.     }
  752.     pdf_append_chars(pdev, &pcp->char_code, 1);
  753.     pdev->text.current.x += pcp->x_width * pdev->text.matrix.xx;
  754.     return 0;
  755. }
  756.