~ubuntu-branches/debian/experimental/cups-filters/experimental

« back to all changes in this revision

Viewing changes to .pc/fcfontsort-no-trim.patch/filter/texttopdf.c

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2012-07-22 18:57:32 UTC
  • mfrom: (1.1.17)
  • Revision ID: package-import@ubuntu.com-20120722185732-26kkte5p1lth3rt5
Tags: 1.0.20-0bzr1
* New upstream release
   - pdftops: Added another workaround for Kyocera printers: Some
     models get very slow on images which request interpolation,
     so now we remove the image interpolation requests by additional
     PostScript code only inserted for Kyocera printers (LP: #1026974).
   - Made the Poppler-based filters pdftopdf and pdftoopvp build with
     both Poppler 0.18.x and 0.20.x (Upstream bug #1055).
   - Fixes according to Coverity scan results (Upstream bug #1054).
   - Switched build system to autotools. This especially fixes several
     build problems in Gentoo. Also build-tested with CUPS 1.6.0b1.
   - Fixes for compatibility with clang/gcc-4.7.
   - textonly: Filter did not work as a pipe with copies=1 (Upstream bug
     #1032).
   - texttopdf: Avoid trimming the results of FcFontSort(), as this may
     miss some reasonable candidates under certain circumstances. BTW,
     fix passing a non-pointer as a pointer to "result" (Closes: #670055).
   - Corrected documentation. The option for the maximum image rendering
     resolution in pdftops is "pdftops-max-image-resolution", not
     "pdftops-max-image-resolution-default".
* debian/patches/fcfontsort-no-trim.patch: Removed, fixed upstream.
* debian/rules: Updated options for ./configure and make for the new autotools
  build system.
* debian/watch: Switched to bz2 upstream packages.
* debian/rules, debian/copyright, debian/cups-filters.docs: Updated for
  renamed documentation files.
* debian/control, debian/libfontembed1.install,
  debian/libfontembed-dev.install: Added new binary packages for libfontembed.
* debian/copyright: Updated for recent file additions, and rearrangement of
  directories.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *   Text to PDF filter for the Common UNIX Printing System (CUPS).
3
 
 *
4
 
 *   Copyright 2008,2012 by Tobias Hoffmann.
5
 
 *   Copyright 2007 by Apple Inc.
6
 
 *   Copyright 1993-2007 by Easy Software Products.
7
 
 *
8
 
 *   These coded instructions, statements, and computer programs are the
9
 
 *   property of Apple Inc. and are protected by Federal copyright
10
 
 *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
11
 
 *   which should have been included with this file.  If this file is
12
 
 *   file is missing or damaged, see the license at "http://www.cups.org/".
13
 
 *
14
 
 *   This file is subject to the Apple OS-Developed Software exception.
15
 
 *
16
 
 * Contents:
17
 
 *
18
 
 *   main()          - Main entry for text to PDF filter.
19
 
 *   WriteEpilogue() - Write the PDF file epilogue.
20
 
 *   WritePage()     - Write a page of text.
21
 
 *   WriteProlog()   - Write the PDF file prolog with options.
22
 
 *   write_line()    - Write a row of text.
23
 
 *   write_string()  - Write a string of text.
24
 
 */
25
 
 
26
 
/*
27
 
 * Include necessary headers...
28
 
 */
29
 
 
30
 
#include "textcommon.h"
31
 
#include "pdfutils.h"
32
 
#include "fontembed/embed.h"
33
 
#include <assert.h>
34
 
#include "fontembed/sfnt.h"
35
 
#include <fontconfig/fontconfig.h>
36
 
 
37
 
/*
38
 
 * Globals...
39
 
 */
40
 
 
41
 
#ifdef CUPS_1_4 /* CUPS 1.4.x or newer: only UTF8 is supported */
42
 
int     UTF8 = 1;               /* Use UTF-8 encoding? */
43
 
#endif /* CUPS_1_4 */
44
 
 
45
 
EMB_PARAMS *font_load(const char *font);
46
 
 
47
 
EMB_PARAMS *font_load(const char *font)
48
 
{
49
 
  OTF_FILE *otf;
50
 
 
51
 
  FcPattern *pattern;
52
 
  FcFontSet *candidates;
53
 
  FcChar8   *fontname = NULL;
54
 
  int i;
55
 
 
56
 
  if ( (font[0]=='/')||(font[0]=='.') ) {
57
 
    candidates = NULL;
58
 
    fontname=(FcChar8 *)strdup(font);
59
 
  } else {
60
 
    FcInit ();
61
 
    pattern = FcNameParse ((const FcChar8 *)font);
62
 
    FcPatternAddInteger (pattern, FC_SPACING, FC_MONO); // guide fc, in case substitution becomes necessary
63
 
    FcConfigSubstitute (0, pattern, FcMatchPattern);
64
 
    FcDefaultSubstitute (pattern);
65
 
 
66
 
    /* Receive a sorted list of fonts matching our pattern */
67
 
    candidates = FcFontSort (0, pattern, FcTrue, 0, 0);
68
 
    FcPatternDestroy (pattern);
69
 
 
70
 
    /* In the list of fonts returned by FcFontSort()
71
 
       find the first one that is both in TrueType format and monospaced */
72
 
    for (i = 0; i < candidates->nfont; i++) {
73
 
      FcChar8 *fontformat=NULL; // TODO? or just try?
74
 
      int spacing=0; // sane default, as FC_MONO == 100
75
 
      FcPatternGetString  (candidates->fonts[i], FC_FONTFORMAT, 0, &fontformat);
76
 
      FcPatternGetInteger (candidates->fonts[i], FC_SPACING,    0, &spacing);
77
 
 
78
 
      if ( (fontformat)&&(spacing == FC_MONO) ) {
79
 
        if (strcmp((const char *)fontformat, "TrueType") == 0) {
80
 
          fontname = FcPatternFormat (candidates->fonts[i], (const FcChar8 *)"%{file|cescape}/%{index}");
81
 
          break;
82
 
        } else if (strcmp((const char *)fontformat, "CFF") == 0) {
83
 
          fontname = FcPatternFormat (candidates->fonts[i], (const FcChar8 *)"%{file|cescape}"); // TTC only possible with non-cff glyphs!
84
 
          break;
85
 
        }
86
 
      }
87
 
    }
88
 
    FcFontSetDestroy (candidates);
89
 
  }
90
 
 
91
 
  if (!fontname) {
92
 
    // TODO: try /usr/share/fonts/*/*/%s.ttf
93
 
    fprintf(stderr,"No viable font found\n");
94
 
    return NULL;
95
 
  }
96
 
 
97
 
  otf = otf_load((const char *)fontname);
98
 
  free(fontname);
99
 
  if (!otf) {
100
 
    return NULL;
101
 
  }
102
 
 
103
 
  FONTFILE *ff=fontfile_open_sfnt(otf);
104
 
  assert(ff);
105
 
  EMB_PARAMS *emb=emb_new(ff,
106
 
                          EMB_DEST_PDF16,
107
 
                          EMB_C_FORCE_MULTIBYTE|
108
 
                          EMB_C_TAKE_FONTFILE);
109
 
  assert(emb);
110
 
  assert(emb->plan&EMB_A_MULTIBYTE);
111
 
  return emb;
112
 
}
113
 
 
114
 
EMB_PARAMS *font_std(const char *name)
115
 
{
116
 
  FONTFILE *ff=fontfile_open_std(name);
117
 
  assert(ff);
118
 
  EMB_PARAMS *emb=emb_new(ff,
119
 
                          EMB_DEST_PDF16,
120
 
                          EMB_C_TAKE_FONTFILE);
121
 
  assert(emb);
122
 
  return emb;
123
 
}
124
 
 
125
 
/*
126
 
 * Globals...
127
 
 */
128
 
 
129
 
int             NumFonts;       /* Number of fonts to use */
130
 
EMB_PARAMS      *Fonts[256][4]; /* Fonts to use */
131
 
unsigned short  Chars[256];     /* Input char to unicode */
132
 
unsigned char   Codes[65536];   /* Unicode glyph mapping to font */
133
 
int             Widths[256];    /* Widths of each font */
134
 
int             Directions[256];/* Text directions for each font */
135
 
pdfOut *pdf;
136
 
int    FontResource;   /* Object number of font resource dictionary */
137
 
float  FontScaleX,FontScaleY;  /* The font matrix */
138
 
lchar_t *Title,*Date;   /* The title and date strings */
139
 
 
140
 
/*
141
 
 * Local functions...
142
 
 */
143
 
 
144
 
static void     write_line(int row, lchar_t *line);
145
 
static void     write_string(int col, int row, int len, lchar_t *s);
146
 
static lchar_t *make_wide(const char *buf);
147
 
static void     write_font_str(float x,float y,int fontid, lchar_t *str, int len);
148
 
static void     write_pretty_header();
149
 
 
150
 
 
151
 
/*
152
 
 * 'main()' - Main entry for text to PDF filter.
153
 
 */
154
 
 
155
 
int                     /* O - Exit status */
156
 
main(int  argc,         /* I - Number of command-line arguments */
157
 
     char *argv[])      /* I - Command-line arguments */
158
 
{
159
 
  return (TextMain("texttopdf", argc, argv));
160
 
}
161
 
 
162
 
 
163
 
/*
164
 
 * 'WriteEpilogue()' - Write the PDF file epilogue.
165
 
 */
166
 
 
167
 
void
168
 
WriteEpilogue(void)
169
 
{
170
 
  static char   *names[] =      /* Font names */
171
 
                { "FN","FB","FI" };
172
 
  int i,j;
173
 
 
174
 
  free(Page[0]);
175
 
  free(Page);
176
 
 
177
 
  // embed fonts
178
 
  for (i = PrettyPrint ? 2 : 1; i >= 0; i --) {
179
 
    for (j = 0; j < NumFonts; j ++) 
180
 
    {
181
 
      EMB_PARAMS *emb=Fonts[j][i];
182
 
      if (emb->font->fobj) { // already embedded
183
 
        continue;
184
 
      }
185
 
      if ( (!emb->subset)||(bits_used(emb->subset,emb->font->sfnt->numGlyphs)) ) {
186
 
        emb->font->fobj=pdfOut_write_font(pdf,emb);
187
 
        assert(emb->font->fobj);
188
 
      }
189
 
    }
190
 
  }
191
 
 
192
 
  /*
193
 
   * Create the global fontdict
194
 
   */
195
 
 
196
 
  // now fix FontResource
197
 
  pdf->xref[FontResource-1]=pdf->filepos;
198
 
  pdfOut_printf(pdf,"%d 0 obj\n"
199
 
                    "<<\n",
200
 
                    FontResource);
201
 
 
202
 
  for (i = PrettyPrint ? 2 : 1; i >= 0; i --) {
203
 
    for (j = 0; j < NumFonts; j ++) {
204
 
      EMB_PARAMS *emb=Fonts[j][i];
205
 
      if (emb->font->fobj) { // used
206
 
        pdfOut_printf(pdf,"  /%s%02x %d 0 R\n",names[i],j,emb->font->fobj);
207
 
      }
208
 
    }
209
 
  }
210
 
 
211
 
  pdfOut_printf(pdf,">>\n"
212
 
                    "endobj\n");
213
 
 
214
 
  pdfOut_finish_pdf(pdf);
215
 
 
216
 
  pdfOut_free(pdf);
217
 
}
218
 
 
219
 
/*
220
 
 * {{{ 'WritePage()' - Write a page of text.
221
 
 */
222
 
 
223
 
void
224
 
WritePage(void)
225
 
{
226
 
  int   line;                   /* Current line */
227
 
 
228
 
  int content=pdfOut_add_xref(pdf);
229
 
  pdfOut_printf(pdf,"%d 0 obj\n"
230
 
                    "<</Length %d 0 R\n"
231
 
                    ">>\n"
232
 
                    "stream\n"
233
 
                    "q\n"
234
 
                    ,content,content+1);
235
 
  long size=-(pdf->filepos-2);
236
 
 
237
 
  NumPages ++;
238
 
  if (PrettyPrint)
239
 
    write_pretty_header(pdf);
240
 
 
241
 
  for (line = 0; line < SizeLines; line ++)
242
 
    write_line(line, Page[line]);
243
 
 
244
 
  size+=pdf->filepos+2;
245
 
  pdfOut_printf(pdf,"Q\n"
246
 
                    "endstream\n"
247
 
                    "endobj\n");
248
 
  
249
 
  int len_obj=pdfOut_add_xref(pdf);
250
 
  assert(len_obj==content+1);
251
 
  pdfOut_printf(pdf,"%d 0 obj\n"
252
 
                    "%d\n"
253
 
                    "endobj\n",
254
 
                    len_obj,size);
255
 
 
256
 
  int obj=pdfOut_add_xref(pdf);
257
 
  pdfOut_printf(pdf,"%d 0 obj\n"
258
 
                    "<</Type/Page\n"
259
 
                    "  /Parent 1 0 R\n"
260
 
                    "  /MediaBox [0 0 %.0f %.0f]\n"
261
 
                    "  /Contents %d 0 R\n"
262
 
                    "  /Resources << /Font %d 0 R >>\n"
263
 
                    ">>\n"
264
 
                    "endobj\n",
265
 
                    obj,PageWidth,PageLength,content,FontResource);
266
 
  pdfOut_add_page(pdf,obj);
267
 
 
268
 
  memset(Page[0], 0, sizeof(lchar_t) * SizeColumns * SizeLines);
269
 
}
270
 
// }}}
271
 
 
272
 
/* 
273
 
 * {{{'WriteProlog()' - Write the PDF file prolog with options.
274
 
 */
275
 
 
276
 
void
277
 
WriteProlog(const char *title,          /* I - Title of job */
278
 
            const char *user,           /* I - Username */
279
 
            const char *classification, /* I - Classification */
280
 
            const char *label,          /* I - Page label */
281
 
            ppd_file_t *ppd)            /* I - PPD file info */
282
 
{
283
 
  int           i, j, k;        /* Looping vars */
284
 
  char          *charset;       /* Character set string */
285
 
  char          filename[1024]; /* Glyph filenames */
286
 
  FILE          *fp;            /* Glyph files */
287
 
  const char    *datadir;       /* CUPS_DATADIR environment variable */
288
 
  char          line[1024],     /* Line from file */
289
 
                *lineptr,       /* Pointer into line */
290
 
                *valptr;        /* Pointer to value in line */
291
 
#ifndef CUPS_1_4 /* CUPS 1.4.x or newer: support for non-utf8 removed */
292
 
  int           ch, unicode;    /* Character values */
293
 
#endif
294
 
  int           start, end;     /* Start and end values for range */
295
 
  time_t        curtime;        /* Current time */
296
 
  struct tm     *curtm;         /* Current date */
297
 
  char          curdate[255];   /* Current date (text format) */
298
 
  int           num_fonts=0;    /* Number of unique fonts */
299
 
  EMB_PARAMS    *fonts[1024];   /* Unique fonts */
300
 
  char          *fontnames[1024];       /* Unique fonts */
301
 
#if 0
302
 
  static char   *names[] =      /* Font names */
303
 
                {
304
 
                  "FN","FB","FI"
305
 
                /*
306
 
                  "cupsNormal",
307
 
                  "cupsBold",
308
 
                  "cupsItalic"
309
 
                */
310
 
                };
311
 
#endif
312
 
 
313
 
 
314
 
 /*
315
 
  * Get the data directory...
316
 
  */
317
 
 
318
 
  if ((datadir = getenv("CUPS_DATADIR")) == NULL)
319
 
    datadir = CUPS_DATADIR;
320
 
 
321
 
 /*
322
 
  * Adjust margins as necessary...
323
 
  */
324
 
 
325
 
  if (classification || label)
326
 
  {
327
 
   /*
328
 
    * Leave room for labels...
329
 
    */
330
 
 
331
 
    PageBottom += 36;
332
 
    PageTop    -= 36;
333
 
  }
334
 
 
335
 
 /*
336
 
  * Allocate memory for the page...
337
 
  */
338
 
 
339
 
  SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch;
340
 
  SizeLines   = (PageTop - PageBottom) / 72.0 * LinesPerInch;
341
 
 
342
 
  Page    = calloc(sizeof(lchar_t *), SizeLines);
343
 
  Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines);
344
 
  for (i = 1; i < SizeLines; i ++)
345
 
    Page[i] = Page[0] + i * SizeColumns;
346
 
 
347
 
  if (PageColumns > 1)
348
 
  {
349
 
    ColumnGutter = CharsPerInch / 2;
350
 
    ColumnWidth  = (SizeColumns - ColumnGutter * (PageColumns - 1)) /
351
 
                   PageColumns;
352
 
  }
353
 
  else
354
 
    ColumnWidth = SizeColumns;
355
 
 
356
 
 /*
357
 
  * {{{ Output the PDF header...
358
 
  */
359
 
 
360
 
  assert(!pdf);
361
 
  pdf=pdfOut_new();
362
 
  assert(pdf);
363
 
 
364
 
  pdfOut_begin_pdf(pdf);
365
 
  pdfOut_printf(pdf,"%%cupsRotation: %d\n", (Orientation & 3) * 90); // TODO?
366
 
 
367
 
  pdfOut_add_kv(pdf,"Creator","texttopdf/" CUPSFILTERS_SVERSION);
368
 
 
369
 
  curtime = time(NULL);
370
 
  curtm   = localtime(&curtime);
371
 
  strftime(curdate, sizeof(curdate), "%c", curtm);
372
 
 
373
 
  pdfOut_add_kv(pdf,"CreationDate",pdfOut_to_pdfdate(curtm));
374
 
  pdfOut_add_kv(pdf,"Title",title);
375
 
  pdfOut_add_kv(pdf,"Author",user); // was(PostScript): /For
376
 
  // }}}
377
 
 
378
 
 /*
379
 
  * {{{ Initialize globals...
380
 
  */
381
 
 
382
 
  NumFonts = 0;
383
 
  memset(Fonts, 0, sizeof(Fonts));
384
 
  memset(Chars, 0, sizeof(Chars));
385
 
  memset(Codes, 0, sizeof(Codes));
386
 
  // }}}
387
 
 
388
 
 /*
389
 
  * Get the output character set...
390
 
  */
391
 
 
392
 
  charset = getenv("CHARSET");
393
 
  if (charset != NULL && strcmp(charset, "us-ascii") != 0) // {{{
394
 
  {
395
 
    snprintf(filename, sizeof(filename), "%s/charsets/pdf.%s", datadir, charset);
396
 
 
397
 
    if ((fp = fopen(filename, "r")) == NULL)
398
 
    {
399
 
     /*
400
 
      * Can't open charset file!
401
 
      */
402
 
 
403
 
      fprintf(stderr, "ERROR: Unable to open %s: %s\n", filename,
404
 
              strerror(errno));
405
 
      exit(1);
406
 
    }
407
 
 
408
 
   /*
409
 
    * Opened charset file; now see if this is really a charset file...
410
 
    */
411
 
 
412
 
    if (fgets(line, sizeof(line), fp) == NULL)
413
 
    {
414
 
     /*
415
 
      * Bad/empty charset file!
416
 
      */
417
 
 
418
 
      fclose(fp);
419
 
      fprintf(stderr, "ERROR: Bad charset file %s\n", filename);
420
 
      exit(1);
421
 
    }
422
 
 
423
 
    if (strncmp(line, "charset", 7) != 0)
424
 
    {
425
 
     /*
426
 
      * Bad format/not a charset file!
427
 
      */
428
 
 
429
 
      fclose(fp);
430
 
      fprintf(stderr, "ERROR: Bad charset file %s\n", filename);
431
 
      exit(1);
432
 
    }
433
 
 
434
 
   /*
435
 
    * See if this is an 8-bit or UTF-8 character set file...
436
 
    */
437
 
 
438
 
    line[strlen(line) - 1] = '\0'; /* Drop \n */
439
 
    for (lineptr = line + 7; isspace(*lineptr & 255); lineptr ++); /* Skip whitespace */
440
 
 
441
 
#ifndef CUPS_1_4 /* CUPS 1.4.x or newer: support for non-utf8 removed */
442
 
    if (strcmp(lineptr, "8bit") == 0) // {{{
443
 
    {
444
 
     /*
445
 
      * 8-bit text...
446
 
      */
447
 
 
448
 
      UTF8     = 0;
449
 
      NumFonts = 0;
450
 
 
451
 
     /*
452
 
      * Read the font description(s)...
453
 
      */
454
 
 
455
 
      while (fgets(line, sizeof(line), fp) != NULL)
456
 
      {
457
 
       /*
458
 
        * Skip comment and blank lines...
459
 
        */
460
 
 
461
 
        if (line[0] == '#' || line[0] == '\n')
462
 
          continue;
463
 
 
464
 
       /*
465
 
        * Read the font descriptions that should look like:
466
 
        *
467
 
        *   first last direction width normal [bold italic bold-italic]
468
 
        */
469
 
 
470
 
        lineptr = line;
471
 
 
472
 
        start = strtol(lineptr, &lineptr, 16);
473
 
        end   = strtol(lineptr, &lineptr, 16);
474
 
 
475
 
        while (isspace(*lineptr & 255))
476
 
          lineptr ++;
477
 
 
478
 
        if (!*lineptr)
479
 
          break;        /* Must be a font mapping */
480
 
 
481
 
        valptr = lineptr;
482
 
 
483
 
        while (!isspace(*lineptr & 255) && *lineptr)
484
 
          lineptr ++;
485
 
 
486
 
        if (!*lineptr)
487
 
        {
488
 
         /*
489
 
          * Can't have a font without all required values...
490
 
          */
491
 
 
492
 
          fprintf(stderr, "ERROR: Bad font description line: %s\n", valptr);
493
 
          fclose(fp);
494
 
          exit(1);
495
 
        }
496
 
 
497
 
        *lineptr++ = '\0';
498
 
 
499
 
        if (strcmp(valptr, "ltor") == 0)
500
 
          Directions[NumFonts] = 1;
501
 
        else if (strcmp(valptr, "rtol") == 0)
502
 
          Directions[NumFonts] = -1;
503
 
        else
504
 
        {
505
 
          fprintf(stderr, "ERROR: Bad text direction %s\n", valptr);
506
 
          fclose(fp);
507
 
          exit(1);
508
 
        }
509
 
 
510
 
       /*
511
 
        * Got the direction, now get the width...
512
 
        */
513
 
 
514
 
        while (isspace(*lineptr & 255))
515
 
          lineptr ++;
516
 
 
517
 
        valptr = lineptr;
518
 
 
519
 
        while (!isspace(*lineptr & 255) && *lineptr)
520
 
          lineptr ++;
521
 
 
522
 
        if (!*lineptr)
523
 
        {
524
 
         /*
525
 
          * Can't have a font without all required values...
526
 
          */
527
 
 
528
 
          fprintf(stderr, "ERROR: Bad font description line: %s\n", valptr);
529
 
          fclose(fp);
530
 
          exit(1);
531
 
        }
532
 
 
533
 
        *lineptr++ = '\0';
534
 
 
535
 
        if (strcmp(valptr, "single") == 0)
536
 
          Widths[NumFonts] = 1;
537
 
        else if (strcmp(valptr, "double") == 0)
538
 
          Widths[NumFonts] = 2;
539
 
        else 
540
 
        {
541
 
          fprintf(stderr, "ERROR: Bad text width %s\n", valptr);
542
 
          fclose(fp);
543
 
          exit(1);
544
 
        }
545
 
 
546
 
       /*
547
 
        * Get the fonts...
548
 
        */
549
 
 
550
 
        for (i = 0; *lineptr && i < 4; i ++)
551
 
        {
552
 
          while (isspace(*lineptr & 255))
553
 
            lineptr ++;
554
 
 
555
 
          valptr = lineptr;
556
 
 
557
 
          while (!isspace(*lineptr & 255) && *lineptr)
558
 
            lineptr ++;
559
 
 
560
 
          if (*lineptr)
561
 
            *lineptr++ = '\0';
562
 
 
563
 
          if (lineptr > valptr) {
564
 
            // search for duplicates
565
 
            for (k = 0; k < num_fonts; k ++)
566
 
              if (strcmp(valptr, fontnames[k]) == 0) {
567
 
                Fonts[NumFonts][i] = fonts[k];
568
 
                break;
569
 
              }
570
 
 
571
 
            if (k==num_fonts) {  // not found
572
 
              fonts[num_fonts] = Fonts[NumFonts][i] = font_load(valptr);
573
 
              if (!fonts[num_fonts]) { // font missing/corrupt, replace by first
574
 
                fprintf(stderr,"WARNING: Ignored bad font \"%s\"\n",valptr);
575
 
                break;
576
 
              }
577
 
              fontnames[num_fonts++] = strdup(valptr);
578
 
            }
579
 
          }
580
 
        }
581
 
 
582
 
        /* ignore complete range, when the first font is not available */
583
 
        if (i==0) {
584
 
          continue;
585
 
        }
586
 
 
587
 
       /*
588
 
        * Fill in remaining fonts as needed...
589
 
        */
590
 
 
591
 
        for (j = i; j < 4; j ++)
592
 
          Fonts[NumFonts][j] = Fonts[NumFonts][0];
593
 
 
594
 
       /*
595
 
        * Define the character mappings...
596
 
        */
597
 
 
598
 
        for (i = start; i <= end; i ++)
599
 
          Codes[i] = NumFonts;
600
 
 
601
 
        NumFonts ++;
602
 
      }
603
 
 
604
 
     /*
605
 
      * Read encoding lines...
606
 
      */
607
 
 
608
 
      do
609
 
      {
610
 
       /*
611
 
        * Skip comment and blank lines...
612
 
        */
613
 
 
614
 
        if (line[0] == '#' || line[0] == '\n')
615
 
          continue;
616
 
 
617
 
       /*
618
 
        * Grab the character and unicode glyph number.
619
 
        */
620
 
 
621
 
        if (sscanf(line, "%x%x", &ch, &unicode) == 2 && ch < 256)
622
 
          Chars[ch] = unicode;
623
 
      }
624
 
      while (fgets(line, sizeof(line), fp) != NULL);
625
 
 
626
 
      fclose(fp);
627
 
    } else // }}}
628
 
#endif
629
 
    if (strcmp(lineptr, "utf8") == 0) { // {{{
630
 
     /*
631
 
      * UTF-8 (Unicode) text...
632
 
      */
633
 
 
634
 
      UTF8 = 1;
635
 
 
636
 
     /*
637
 
      * Read the font descriptions...
638
 
      */
639
 
 
640
 
      NumFonts = 0;
641
 
 
642
 
      while (fgets(line, sizeof(line), fp) != NULL)
643
 
      {
644
 
       /*
645
 
        * Skip comment and blank lines...
646
 
        */
647
 
 
648
 
        if (line[0] == '#' || line[0] == '\n')
649
 
          continue;
650
 
 
651
 
       /*
652
 
        * Read the font descriptions that should look like:
653
 
        *
654
 
        *   start end direction width normal [bold italic bold-italic]
655
 
        */
656
 
 
657
 
        lineptr = line;
658
 
 
659
 
        start = strtol(lineptr, &lineptr, 16);
660
 
        end   = strtol(lineptr, &lineptr, 16);
661
 
 
662
 
        while (isspace(*lineptr & 255))
663
 
          lineptr ++;
664
 
 
665
 
        valptr = lineptr;
666
 
 
667
 
        while (!isspace(*lineptr & 255) && *lineptr)
668
 
          lineptr ++;
669
 
 
670
 
        if (!*lineptr)
671
 
        {
672
 
         /*
673
 
          * Can't have a font without all required values...
674
 
          */
675
 
 
676
 
          fprintf(stderr, "ERROR: Bad font description line: %s\n", valptr);
677
 
          fclose(fp);
678
 
          exit(1);
679
 
        }
680
 
 
681
 
        *lineptr++ = '\0';
682
 
 
683
 
        if (strcmp(valptr, "ltor") == 0)
684
 
          Directions[NumFonts] = 1;
685
 
        else if (strcmp(valptr, "rtol") == 0)
686
 
          Directions[NumFonts] = -1;
687
 
        else
688
 
        {
689
 
          fprintf(stderr, "ERROR: Bad text direction %s\n", valptr);
690
 
          fclose(fp);
691
 
          exit(1);
692
 
        }
693
 
 
694
 
       /*
695
 
        * Got the direction, now get the width...
696
 
        */
697
 
 
698
 
        while (isspace(*lineptr & 255))
699
 
          lineptr ++;
700
 
 
701
 
        valptr = lineptr;
702
 
 
703
 
        while (!isspace(*lineptr & 255) && *lineptr)
704
 
          lineptr ++;
705
 
 
706
 
        if (!*lineptr)
707
 
        {
708
 
         /*
709
 
          * Can't have a font without all required values...
710
 
          */
711
 
 
712
 
          fprintf(stderr, "ERROR: Bad font description line: %s\n", valptr);
713
 
          fclose(fp);
714
 
          exit(1);
715
 
        }
716
 
 
717
 
        *lineptr++ = '\0';
718
 
 
719
 
        if (strcmp(valptr, "single") == 0)
720
 
          Widths[NumFonts] = 1;
721
 
        else if (strcmp(valptr, "double") == 0)
722
 
          Widths[NumFonts] = 2;
723
 
        else 
724
 
        {
725
 
          fprintf(stderr, "ERROR: Bad text width %s\n", valptr);
726
 
          fclose(fp);
727
 
          exit(1);
728
 
        }
729
 
 
730
 
       /*
731
 
        * Get the fonts...
732
 
        */
733
 
 
734
 
        for (i = 0; *lineptr && i < 4; i ++)
735
 
        {
736
 
          while (isspace(*lineptr & 255))
737
 
            lineptr ++;
738
 
 
739
 
          valptr = lineptr;
740
 
 
741
 
          while (!isspace(*lineptr & 255) && *lineptr)
742
 
            lineptr ++;
743
 
 
744
 
          if (*lineptr)
745
 
            *lineptr++ = '\0';
746
 
 
747
 
          if (lineptr > valptr) {
748
 
            // search for duplicates
749
 
            for (k = 0; k < num_fonts; k ++)
750
 
              if (strcmp(valptr, fontnames[k]) == 0) {
751
 
                Fonts[NumFonts][i] = fonts[k];
752
 
                break;
753
 
              }
754
 
 
755
 
            if (k==num_fonts) {  // not found
756
 
              fonts[num_fonts] = Fonts[NumFonts][i] = font_load(valptr);
757
 
              if (!fonts[num_fonts]) { // font missing/corrupt, replace by first
758
 
                fprintf(stderr,"WARNING: Ignored bad font \"%s\"\n",valptr);
759
 
                break;
760
 
              }
761
 
              fontnames[num_fonts++] = strdup(valptr);
762
 
            }
763
 
          }
764
 
        }
765
 
 
766
 
        /* ignore complete range, when the first font is not available */
767
 
        if (i==0) {
768
 
          continue;
769
 
        }
770
 
 
771
 
       /*
772
 
        * Fill in remaining fonts as needed...
773
 
        */
774
 
 
775
 
        for (j = i; j < 4; j ++)
776
 
          Fonts[NumFonts][j] = Fonts[NumFonts][0];
777
 
 
778
 
       /*
779
 
        * Define the character mappings...
780
 
        */
781
 
 
782
 
        for (i = start; i <= end; i ++)
783
 
        {
784
 
          Codes[i] = NumFonts;
785
 
        }
786
 
 
787
 
       /*
788
 
        * Move to the next font, stopping if needed...
789
 
        */
790
 
 
791
 
        NumFonts ++;
792
 
        if (NumFonts >= 256)
793
 
          break;
794
 
      }
795
 
 
796
 
      fclose(fp);
797
 
    } // }}}
798
 
    else // {{{
799
 
    {
800
 
      fprintf(stderr, "ERROR: Bad charset type %s\n", lineptr);
801
 
      fclose(fp);
802
 
      exit(1);
803
 
    } // }}}
804
 
  } // }}}
805
 
  else // {{{ Standard ASCII
806
 
  {
807
 
   /*
808
 
    * Standard ASCII output just uses Courier, Courier-Bold, and
809
 
    * possibly Courier-Oblique.
810
 
    */
811
 
 
812
 
    NumFonts = 1;
813
 
 
814
 
    Fonts[0][ATTR_NORMAL]     = font_std("Courier");
815
 
    Fonts[0][ATTR_BOLD]       = font_std("Courier-Bold");
816
 
    Fonts[0][ATTR_ITALIC]     = font_std("Courier-Oblique");
817
 
    Fonts[0][ATTR_BOLDITALIC] = font_std("Courier-BoldOblique");
818
 
 
819
 
    Widths[0]     = 1;
820
 
    Directions[0] = 1;
821
 
 
822
 
   /*
823
 
    * Define US-ASCII characters...
824
 
    */
825
 
 
826
 
    for (i = 32; i < 127; i ++)
827
 
    {
828
 
      Chars[i] = i;
829
 
      Codes[i] = NumFonts-1;
830
 
    }
831
 
  }
832
 
  // }}}
833
 
 
834
 
  if (NumFonts==0) {
835
 
    fprintf(stderr, "ERROR: No usable font available\n");
836
 
    exit(1);
837
 
  }
838
 
 
839
 
  FontScaleX=120.0 / CharsPerInch;
840
 
  FontScaleY=68.0 / LinesPerInch;
841
 
 
842
 
  // allocate now, for pages to use. will be fixed in epilogue
843
 
  FontResource=pdfOut_add_xref(pdf);
844
 
 
845
 
  if (PrettyPrint)
846
 
  {
847
 
    Date=make_wide(curdate);
848
 
    Title=make_wide(title);
849
 
  }
850
 
}
851
 
// }}}
852
 
 
853
 
/*
854
 
 * {{{ 'write_line()' - Write a row of text.
855
 
 */
856
 
 
857
 
static void
858
 
write_line(int     row,         /* I - Row number (0 to N) */
859
 
           lchar_t *line)       /* I - Line to print */
860
 
{
861
 
  int           i;              /* Looping var */
862
 
  int           col,xcol,xwid;          /* Current column */
863
 
  int           attr;           /* Current attribute */
864
 
  int           font,           /* Font to use */
865
 
                lastfont,       /* Last font */
866
 
                mono;           /* Monospaced? */
867
 
  lchar_t       *start;         /* First character in sequence */
868
 
 
869
 
 
870
 
  xcol=0;
871
 
  for (col = 0, start = line; col < SizeColumns;)
872
 
  {
873
 
    while (col < SizeColumns && (line->ch == ' ' || line->ch == 0))
874
 
    {
875
 
      col ++;
876
 
      xcol ++;
877
 
      line ++;
878
 
    }
879
 
 
880
 
    if (col >= SizeColumns)
881
 
      break;
882
 
 
883
 
    if (NumFonts == 1)
884
 
    {
885
 
     /*
886
 
      * All characters in a single font - assume monospaced and single width...
887
 
      */
888
 
 
889
 
      attr  = line->attr;
890
 
      start = line;
891
 
 
892
 
      while (col < SizeColumns && line->ch != 0 && attr == line->attr)
893
 
      {
894
 
        col ++;
895
 
        line ++;
896
 
      }
897
 
 
898
 
      write_string(col - (line - start), row, line - start, start);
899
 
    }
900
 
    else
901
 
    {
902
 
     /*
903
 
      * Multiple fonts; break up based on the font...
904
 
      */
905
 
 
906
 
      attr     = line->attr;
907
 
      start    = line;
908
 
      xwid     = 0;
909
 
      if (UTF8) {
910
 
        lastfont = Codes[line->ch];
911
 
      } else {
912
 
        lastfont = Codes[Chars[line->ch]];
913
 
      }
914
 
//      mono     = strncmp(Fonts[lastfont][0], "Courier", 7) == 0;
915
 
mono=1; // TODO
916
 
 
917
 
      col ++;
918
 
      xwid += Widths[lastfont];
919
 
      line ++;
920
 
 
921
 
      if (mono)
922
 
      {
923
 
        while (col < SizeColumns && line->ch != 0 && attr == line->attr)
924
 
        {
925
 
          if (UTF8) {
926
 
            font = Codes[line->ch];
927
 
          } else {
928
 
            font = Codes[Chars[line->ch]];
929
 
          }
930
 
          if (/*strncmp(Fonts[font][0], "Courier", 7) != 0 ||*/ // TODO
931
 
              font != lastfont)
932
 
            break;
933
 
 
934
 
          col ++;
935
 
          xwid += Widths[lastfont];
936
 
          line ++;
937
 
        }
938
 
      }
939
 
 
940
 
      if (Directions[lastfont] > 0) {
941
 
        write_string(xcol, row, line - start, start);
942
 
        xcol += xwid;
943
 
      }
944
 
      else
945
 
      {
946
 
       /*
947
 
        * Do right-to-left text... ; assume no font change without direction change
948
 
        */
949
 
 
950
 
        while (col < SizeColumns && line->ch != 0 && attr == line->attr)
951
 
        {
952
 
          if (UTF8) {
953
 
            font = Codes[line->ch];
954
 
          } else {
955
 
            font = Codes[Chars[line->ch]];
956
 
          }
957
 
          if (Directions[font] > 0 &&
958
 
              !ispunct(line->ch & 255) && !isspace(line->ch & 255))
959
 
            break;
960
 
 
961
 
          col ++;
962
 
          xwid += Widths[lastfont];
963
 
          line ++;
964
 
        }
965
 
 
966
 
        for (i = 1; start < line; i ++, start ++)
967
 
          if (!isspace(start->ch & 255)) {
968
 
            xwid-=Widths[lastfont];
969
 
            write_string(xcol + xwid, row, 1, start);
970
 
          } else {
971
 
            xwid--;
972
 
          }
973
 
      }
974
 
    }
975
 
  }
976
 
}
977
 
// }}}
978
 
 
979
 
static lchar_t *make_wide(const char *buf)  // {{{ - convert to lchar_t
980
 
{
981
 
  const unsigned char   *utf8;  /* UTF8 text */
982
 
  lchar_t *ret,*out;
983
 
  
984
 
  // this is enough, utf8 chars will only require less space
985
 
  out=ret=malloc((strlen(buf)+1)*sizeof(lchar_t)); 
986
 
 
987
 
  utf8 = (const unsigned char *)buf;
988
 
  while (*utf8)
989
 
  {
990
 
    out->attr=0;
991
 
 
992
 
    if (*utf8 < 0xc0 || !UTF8)
993
 
      out->ch = *utf8 ++;
994
 
    else if ((*utf8 & 0xe0) == 0xc0)
995
 
    {
996
 
     /*
997
 
      * Two byte character...
998
 
      */
999
 
 
1000
 
      out->ch = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f);
1001
 
      utf8 += 2;
1002
 
    }
1003
 
    else
1004
 
    {
1005
 
     /*
1006
 
      * Three byte character...
1007
 
      */
1008
 
 
1009
 
      out->ch = ((((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)) << 6) |
1010
 
                (utf8[2] & 0x3f);
1011
 
      utf8 += 3;
1012
 
    }
1013
 
 
1014
 
    out++;
1015
 
  }
1016
 
  out->ch=out->attr=0;
1017
 
  return ret;
1018
 
}
1019
 
// }}}
1020
 
 
1021
 
/*
1022
 
 * {{{ 'write_string()' - Write a string of text.
1023
 
 */
1024
 
 
1025
 
static void
1026
 
write_string(int     col,       /* I - Start column */
1027
 
             int     row,       /* I - Row */
1028
 
             int     len,       /* I - Number of characters */
1029
 
             lchar_t *s)        /* I - String to print */
1030
 
{
1031
 
  float         x, y;           /* Position of text */
1032
 
  unsigned      attr;           /* Character attributes */
1033
 
 
1034
 
 
1035
 
 /*
1036
 
  * Position the text and set the font...
1037
 
  */
1038
 
 
1039
 
  if (Duplex && (NumPages & 1) == 0)
1040
 
  {
1041
 
    x = PageWidth - PageRight;
1042
 
    y = PageTop;
1043
 
  }
1044
 
  else
1045
 
  {
1046
 
    x = PageLeft;
1047
 
    y = PageTop;
1048
 
  }
1049
 
 
1050
 
  x += (float)col * 72.0f / (float)CharsPerInch;
1051
 
  y -= (float)(row + 0.843) * 72.0f / (float)LinesPerInch;
1052
 
 
1053
 
  attr = s->attr;
1054
 
 
1055
 
  if (attr & ATTR_RAISED)
1056
 
    y += 36.0 / (float)LinesPerInch;
1057
 
  else if (attr & ATTR_LOWERED)
1058
 
    y -= 36.0 / (float)LinesPerInch;
1059
 
 
1060
 
  if (attr & ATTR_UNDERLINE)
1061
 
    pdfOut_printf(pdf,"q 0.5 w 0 g %.3f %.3f m %.3f %.3f l S Q ",
1062
 
                      x, y - 6.8 / LinesPerInch,
1063
 
                      x + (float)len * 72.0 / (float)CharsPerInch,
1064
 
                      y - 6.8 / LinesPerInch);
1065
 
 
1066
 
  if (PrettyPrint)
1067
 
  {
1068
 
    if (ColorDevice) {
1069
 
      if (attr & ATTR_RED)
1070
 
        pdfOut_printf(pdf,"0.5 0 0 rg\n");
1071
 
      else if (attr & ATTR_GREEN)
1072
 
        pdfOut_printf(pdf,"0 0.5 0 rg\n");
1073
 
      else if (attr & ATTR_BLUE)
1074
 
        pdfOut_printf(pdf,"0 0 0.5 rg\n");
1075
 
      else
1076
 
        pdfOut_printf(pdf,"0 g\n");
1077
 
    } else {
1078
 
      if ( (attr & ATTR_RED)||(attr & ATTR_GREEN)||(attr & ATTR_BLUE) )
1079
 
        pdfOut_printf(pdf,"0.2 g\n");
1080
 
      else
1081
 
        pdfOut_printf(pdf,"0 g\n");
1082
 
    }
1083
 
  }
1084
 
  else
1085
 
    pdfOut_printf(pdf,"0 g\n");
1086
 
  
1087
 
  write_font_str(x,y,attr & ATTR_FONT,s,len);
1088
 
}
1089
 
// }}}
1090
 
 
1091
 
// {{{ show >len characters from >str, using the right font(s) at >x,>y
1092
 
static void write_font_str(float x,float y,int fontid, lchar_t *str, int len)
1093
 
{
1094
 
  unsigned short                ch;             /* Current character */
1095
 
  static char   *names[] =      /* Font names */
1096
 
                { "FN","FB","FI" };
1097
 
 
1098
 
  if (len==-1) {
1099
 
    for (len=0;str[len].ch;len++);
1100
 
  }
1101
 
  pdfOut_printf(pdf,"BT\n");
1102
 
 
1103
 
  if (x == (int)x)
1104
 
    pdfOut_printf(pdf,"  %.0f ", x);
1105
 
  else
1106
 
    pdfOut_printf(pdf,"  %.3f ", x);
1107
 
 
1108
 
  if (y == (int)y)
1109
 
    pdfOut_printf(pdf,"%.0f Td\n", y);
1110
 
  else
1111
 
    pdfOut_printf(pdf,"%.3f Td\n", y);
1112
 
 
1113
 
  int lastfont,font;
1114
 
 
1115
 
  // split on font boundary
1116
 
  while (len > 0) 
1117
 
  {
1118
 
   /*
1119
 
    * Write a hex string...
1120
 
    */
1121
 
    if (UTF8) {
1122
 
      lastfont=Codes[str->ch];
1123
 
    } else {
1124
 
      lastfont=Codes[Chars[str->ch]];
1125
 
    }
1126
 
    EMB_PARAMS *emb=Fonts[lastfont][fontid];
1127
 
    OTF_FILE *otf=emb->font->sfnt;
1128
 
 
1129
 
    if (otf) { // TODO?
1130
 
      pdfOut_printf(pdf,"  %.3f Tz\n",
1131
 
                        FontScaleX*600.0/(otf_get_width(otf,4)*1000.0/otf->unitsPerEm)*100.0/FontScaleY); // TODO? 
1132
 
      // gid==4 is usually '!', the char after space. We just need "the" width for the monospaced font. gid==0 is bad, and space might also be bad.
1133
 
    } else {
1134
 
      pdfOut_printf(pdf,"  %.3f Tz\n",
1135
 
                        FontScaleX*100.0/FontScaleY); // TODO?
1136
 
    }
1137
 
 
1138
 
    pdfOut_printf(pdf,"  /%s%02x %.3f Tf <",
1139
 
                      names[fontid],lastfont,FontScaleY);
1140
 
 
1141
 
    while (len > 0)
1142
 
    {
1143
 
      if (UTF8) {
1144
 
        ch=str->ch;
1145
 
      } else {
1146
 
        ch=Chars[str->ch];
1147
 
      }
1148
 
 
1149
 
      font = Codes[ch];
1150
 
      if (lastfont != font) {
1151
 
        assert(0); // should never happen; TODO
1152
 
        break;
1153
 
      }
1154
 
      if (otf) { // TODO 
1155
 
        const unsigned short gid=emb_get(emb,ch);
1156
 
        pdfOut_printf(pdf,"%04x", gid);
1157
 
      } else { // std 14 font with 7-bit us-ascii uses single byte encoding, TODO
1158
 
        pdfOut_printf(pdf,"%02x",ch);
1159
 
      }
1160
 
 
1161
 
      len --;
1162
 
      str ++;
1163
 
    }
1164
 
 
1165
 
    pdfOut_printf(pdf,"> Tj\n");
1166
 
  }
1167
 
  pdfOut_printf(pdf,"ET\n");
1168
 
}
1169
 
// }}}
1170
 
 
1171
 
static float stringwidth_x(lchar_t *str)
1172
 
{
1173
 
  int len;
1174
 
 
1175
 
  for (len=0;str[len].ch;len++);
1176
 
 
1177
 
  return  (float)len * 72.0 / (float)CharsPerInch;
1178
 
}
1179
 
 
1180
 
static void write_pretty_header() // {{{
1181
 
{
1182
 
  float x,y;
1183
 
  pdfOut_printf(pdf,"q\n"
1184
 
                    "0.9 g\n");
1185
 
 
1186
 
  if (Duplex && (NumPages & 1) == 0) {
1187
 
    x = PageWidth - PageRight;
1188
 
    y = PageTop + 72.0f / LinesPerInch;
1189
 
  } else {
1190
 
    x = PageLeft;
1191
 
    y = PageTop + 72.0f / LinesPerInch;
1192
 
  }
1193
 
 
1194
 
  pdfOut_printf(pdf,"1 0 0 1 %.3f %.3f cm\n",x,y); // translate
1195
 
  pdfOut_printf(pdf,"0 0 %.3f %.3f re f\n",
1196
 
                    PageRight - PageLeft, 144.0f / LinesPerInch);
1197
 
  pdfOut_printf(pdf,"0 g 0 G\n");
1198
 
 
1199
 
  if (Duplex && (NumPages & 1) == 0) {
1200
 
      x = PageRight - PageLeft - 36.0f / LinesPerInch - stringwidth_x(Title);
1201
 
      y = (0.5f + 0.157f) * 72.0f / LinesPerInch;
1202
 
  } else {
1203
 
      x = 36.0f / LinesPerInch;
1204
 
      y = (0.5f + 0.157f) * 72.0f / LinesPerInch;
1205
 
  }
1206
 
  write_font_str(x,y,ATTR_BOLD,Title,-1);
1207
 
 
1208
 
  x = (-stringwidth_x(Date) + PageRight - PageLeft) * 0.5;
1209
 
  write_font_str(x,y,ATTR_BOLD,Date,-1);
1210
 
 
1211
 
  // convert pagenumber to string
1212
 
  char tmp[20];
1213
 
  tmp[19]=0;
1214
 
  snprintf(tmp,19,"%d",NumPages);
1215
 
  lchar_t *pagestr=make_wide(tmp);
1216
 
 
1217
 
  if (Duplex && (NumPages & 1) == 0) {
1218
 
      x = 36.0f / LinesPerInch;
1219
 
  } else {
1220
 
      x = PageRight - PageLeft - 36.0f / LinesPerInch - stringwidth_x(pagestr);
1221
 
  }
1222
 
  write_font_str(x,y,ATTR_BOLD,pagestr,-1);
1223
 
 
1224
 
  pdfOut_printf(pdf,"Q\n");
1225
 
}
1226
 
// }}}
1227