~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to src/gdevpdti.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2001-2006 Artifex Software, Inc.
2
 
   All Rights Reserved.
3
 
  
4
 
   This software is provided AS-IS with no warranty, either express or
5
 
   implied.
6
 
 
7
 
   This software is distributed under license and may not be copied, modified
8
 
   or distributed except as expressly authorized under the terms of that
9
 
   license.  Refer to licensing information at http://www.artifex.com/
10
 
   or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11
 
   San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12
 
*/
13
 
 
14
 
/* $Id: gdevpdti.c 8611 2008-03-27 08:37:58Z ken $ */
15
 
/* Bitmap font implementation for pdfwrite */
16
 
#include "memory_.h"
17
 
#include "string_.h"
18
 
#include "gx.h"
19
 
#include "gxpath.h"
20
 
#include "gserrors.h"
21
 
#include "gsutil.h"
22
 
#include "gdevpdfx.h"
23
 
#include "gdevpdfg.h"
24
 
#include "gdevpdtf.h"
25
 
#include "gdevpdti.h"
26
 
#include "gdevpdts.h"
27
 
#include "gdevpdtw.h"
28
 
#include "gdevpdtt.h"
29
 
#include "gdevpdfo.h"
30
 
 
31
 
/* ---------------- Private ---------------- */
32
 
 
33
 
/* Define the structure for a CharProc pseudo-resource. */
34
 
/*typedef struct pdf_char_proc_s pdf_char_proc_t;*/  /* gdevpdfx.h */
35
 
struct pdf_char_proc_s {
36
 
    pdf_resource_common(pdf_char_proc_t);
37
 
    pdf_char_proc_ownership_t *owner_fonts; /* fonts using this charproc. */
38
 
    int y_offset;               /* of character (0,0) */
39
 
    gs_point real_width;        /* Not used with synthesised bitmap fonts. */
40
 
    gs_point v;                 /* Not used with synthesised bitmap fonts. */
41
 
};
42
 
 
43
 
/* The descriptor is public for pdf_resource_type_structs. */
44
 
gs_public_st_suffix_add1(st_pdf_char_proc, pdf_char_proc_t,
45
 
  "pdf_char_proc_t", pdf_char_proc_enum_ptrs, pdf_char_proc_reloc_ptrs,
46
 
  st_pdf_resource, owner_fonts);
47
 
 
48
 
struct pdf_char_proc_ownership_s {
49
 
    pdf_char_proc_t *char_proc;
50
 
    pdf_char_proc_ownership_t *font_next;       /* next char_proc for same font */
51
 
    pdf_char_proc_ownership_t *char_next;       /* next char_proc for same charproc */
52
 
    pdf_font_resource_t *font;
53
 
    gs_char char_code;          /* Character code in PDF font. */
54
 
    gs_glyph glyph;             /* Glyph id in Postscript font. */
55
 
    gs_const_string char_name;
56
 
    bool duplicate_char_name;
57
 
};
58
 
gs_private_st_strings1_ptrs4(st_pdf_char_proc_ownership, pdf_char_proc_ownership_t,
59
 
  "pdf_char_proc_ownership_t", pdf_char_proc_ownership_enum_ptrs,
60
 
  pdf_char_proc_ownership_reloc_ptrs, char_name, char_proc, char_next, font_next, font);
61
 
 
62
 
/* Define the state structure for tracking bitmap fonts. */
63
 
/*typedef struct pdf_bitmap_fonts_s pdf_bitmap_fonts_t;*/
64
 
struct pdf_bitmap_fonts_s {
65
 
    pdf_font_resource_t *open_font;  /* current Type 3 synthesized font */
66
 
    bool use_open_font;         /* if false, start new open_font */
67
 
    long bitmap_encoding_id;
68
 
    int max_embedded_code;      /* max Type 3 code used */
69
 
};
70
 
gs_private_st_ptrs1(st_pdf_bitmap_fonts, pdf_bitmap_fonts_t,
71
 
  "pdf_bitmap_fonts_t", pdf_bitmap_fonts_enum_ptrs,
72
 
  pdf_bitmap_fonts_reloc_ptrs, open_font);
73
 
 
74
 
static inline long
75
 
pdf_char_proc_id(const pdf_char_proc_t *pcp)
76
 
{
77
 
    return pdf_resource_id((const pdf_resource_t *)pcp);
78
 
}
79
 
 
80
 
/* Assign a code for a char_proc. */
81
 
static int
82
 
assign_char_code(gx_device_pdf * pdev, gs_text_enum_t *pte)
83
 
{
84
 
    pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
85
 
    pdf_font_resource_t *pdfont = pbfs->open_font; /* Type 3 */
86
 
    int c, code;
87
 
 
88
 
    if (pbfs->bitmap_encoding_id == 0)
89
 
        pbfs->bitmap_encoding_id = pdf_obj_ref(pdev);
90
 
    if (pdfont == 0 || pdfont->u.simple.LastChar == 255 ||
91
 
        !pbfs->use_open_font
92
 
        ) {
93
 
        /* Start a new synthesized font. */
94
 
        char *pc;
95
 
 
96
 
        code = pdf_font_type3_alloc(pdev, &pdfont, pdf_write_contents_bitmap);
97
 
        if (code < 0)
98
 
            return code;
99
 
        pdfont->u.simple.s.type3.bitmap_font = true;
100
 
        if (pbfs->open_font == 0)
101
 
            pdfont->rname[0] = 0;
102
 
        else
103
 
            strcpy(pdfont->rname, pbfs->open_font->rname);
104
 
        pdfont->u.simple.s.type3.FontBBox.p.x = 0;
105
 
        pdfont->u.simple.s.type3.FontBBox.p.y = 0;
106
 
        pdfont->u.simple.s.type3.FontBBox.q.x = 1000;
107
 
        pdfont->u.simple.s.type3.FontBBox.q.y = 1000;
108
 
        pdfont->mark_glyph = NULL;
109
 
        gs_make_identity(&pdfont->u.simple.s.type3.FontMatrix);
110
 
        /*
111
 
         * We "increment" the font name as a radix-26 "number".
112
 
         * This cannot possibly overflow.
113
 
         */
114
 
        for (pc = pdfont->rname; *pc == 'Z'; ++pc)
115
 
            *pc = '@';
116
 
        if ((*pc)++ == 0)
117
 
            *pc = 'A', pc[1] = 0;
118
 
        pbfs->open_font = pdfont;
119
 
        pbfs->use_open_font = true;
120
 
        pdfont->u.simple.FirstChar = 0;
121
 
    }
122
 
    c = ++(pdfont->u.simple.LastChar);
123
 
    pdfont->Widths[c] = psdf_round(pdev->char_width.x, 100, 10); /* See 
124
 
                        pdf_write_Widths about rounding. We need to provide 
125
 
                        a compatible data for Tj. */
126
 
    if (c > pbfs->max_embedded_code)
127
 
        pbfs->max_embedded_code = c;
128
 
 
129
 
    return c;
130
 
}
131
 
 
132
 
/* Write the contents of a Type 3 bitmap or vector font resource. */
133
 
int
134
 
pdf_write_contents_bitmap(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
135
 
{
136
 
    stream *s = pdev->strm;
137
 
    const pdf_char_proc_ownership_t *pcpo;
138
 
    long diff_id = 0;
139
 
    int code;
140
 
 
141
 
    if (pdfont->u.simple.s.type3.bitmap_font)
142
 
        diff_id = pdev->text->bitmap_fonts->bitmap_encoding_id;
143
 
    else {
144
 
        /* See comment in pdf_write_encoding. */
145
 
        diff_id = pdf_obj_ref(pdev);
146
 
    }
147
 
    code = pdf_write_encoding_ref(pdev, pdfont, diff_id);
148
 
    if (code < 0)
149
 
        return code;
150
 
    stream_puts(s, "/CharProcs <<");
151
 
    /* Write real characters. */
152
 
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo;
153
 
         pcpo = pcpo->char_next
154
 
         ) {
155
 
        if (pdfont->u.simple.s.type3.bitmap_font)
156
 
            pprintld2(s, "/a%ld %ld 0 R\n", (long)pcpo->char_code,
157
 
                      pdf_char_proc_id(pcpo->char_proc));
158
 
        else if (!pcpo-> duplicate_char_name) {
159
 
            pdf_put_name(pdev, pcpo->char_name.data, pcpo->char_name.size);
160
 
            pprintld1(s, " %ld 0 R\n", pdf_char_proc_id(pcpo->char_proc));
161
 
        }
162
 
    }
163
 
    stream_puts(s, ">>");
164
 
    pprintg6(s, "/FontMatrix[%g %g %g %g %g %g]", 
165
 
            (float)pdfont->u.simple.s.type3.FontMatrix.xx,
166
 
            (float)pdfont->u.simple.s.type3.FontMatrix.xy,
167
 
            (float)pdfont->u.simple.s.type3.FontMatrix.yx,
168
 
            (float)pdfont->u.simple.s.type3.FontMatrix.yy,
169
 
            (float)pdfont->u.simple.s.type3.FontMatrix.tx,
170
 
            (float)pdfont->u.simple.s.type3.FontMatrix.ty);
171
 
    code = pdf_finish_write_contents_type3(pdev, pdfont);
172
 
    if (code < 0)
173
 
        return code;
174
 
    s = pdev->strm; /* pdf_finish_write_contents_type3 changes pdev->strm . */
175
 
    if (!pdfont->u.simple.s.type3.bitmap_font && diff_id > 0) {
176
 
        code = pdf_write_encoding(pdev, pdfont, diff_id, 0);
177
 
        if (code < 0)
178
 
            return code;
179
 
    }
180
 
    return 0;
181
 
}
182
 
 
183
 
/* ---------------- Public ---------------- */
184
 
 
185
 
/*
186
 
 * Allocate and initialize bookkeeping for bitmap fonts.
187
 
 */
188
 
pdf_bitmap_fonts_t *
189
 
pdf_bitmap_fonts_alloc(gs_memory_t *mem)
190
 
{
191
 
    pdf_bitmap_fonts_t *pbfs =
192
 
        gs_alloc_struct(mem, pdf_bitmap_fonts_t, &st_pdf_bitmap_fonts,
193
 
                        "pdf_bitmap_fonts_alloc");
194
 
 
195
 
    if (pbfs == 0)
196
 
        return 0;
197
 
    memset(pbfs, 0, sizeof(*pbfs));
198
 
    pbfs->max_embedded_code = -1;
199
 
    return pbfs;
200
 
}
201
 
 
202
 
/*
203
 
 * Update text state at the end of a page.
204
 
 */
205
 
void
206
 
pdf_close_text_page(gx_device_pdf *pdev)
207
 
{
208
 
    /*
209
 
     * When Acrobat Reader 3 prints a file containing a Type 3 font with a
210
 
     * non-standard Encoding, it apparently only emits the subset of the
211
 
     * font actually used on the page.  Thus, if the "Download Fonts Once"
212
 
     * option is selected, characters not used on the page where the font
213
 
     * first appears will not be defined, and hence will print as blank if
214
 
     * used on subsequent pages.  Thus, we can't allow a Type 3 font to
215
 
     * add additional characters on subsequent pages.
216
 
     */
217
 
    if (pdev->CompatibilityLevel <= 1.2)
218
 
        pdev->text->bitmap_fonts->use_open_font = false;
219
 
}
220
 
 
221
 
/* Return the Y offset for a bitmap character image. */
222
 
int
223
 
pdf_char_image_y_offset(const gx_device_pdf *pdev, int x, int y, int h)
224
 
{
225
 
    const pdf_text_data_t *const ptd = pdev->text;
226
 
    gs_point pt;
227
 
    int max_off, off;
228
 
 
229
 
    pdf_text_position(pdev, &pt);
230
 
    if (x < pt.x)
231
 
        return 0;
232
 
    max_off = (ptd->bitmap_fonts->open_font == 0 ? 0 :
233
 
               ptd->bitmap_fonts->open_font->u.simple.s.type3.max_y_offset);
234
 
    off = (y + h) - (int)(pt.y + 0.5);
235
 
    if (off < -max_off || off > max_off)
236
 
        off = 0;
237
 
    return off;
238
 
}
239
 
 
240
 
/* Attach a CharProc to a font. */
241
 
static int
242
 
pdf_attach_charproc(gx_device_pdf * pdev, pdf_font_resource_t *pdfont, pdf_char_proc_t *pcp,
243
 
                    gs_glyph glyph, gs_char char_code, const gs_const_string *gnstr)
244
 
{
245
 
    pdf_char_proc_ownership_t *pcpo;
246
 
    bool duplicate_char_name = false;
247
 
    
248
 
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
249
 
        if (pcpo->glyph == glyph && pcpo->char_code == char_code)
250
 
            return 0;
251
 
    }
252
 
    if (!pdfont->u.simple.s.type3.bitmap_font) {
253
 
        for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
254
 
            if (!bytes_compare(pcpo->char_name.data, pcpo->char_name.size, gnstr->data, gnstr->size)) {
255
 
                duplicate_char_name = true;
256
 
                break;
257
 
            }
258
 
        }
259
 
    }
260
 
    pcpo = gs_alloc_struct(pdev->pdf_memory, 
261
 
            pdf_char_proc_ownership_t, &st_pdf_char_proc_ownership, "pdf_attach_charproc");
262
 
 
263
 
    if (pcpo == NULL)
264
 
        return_error(gs_error_VMerror);
265
 
    pcpo->font = pdfont;
266
 
    pcpo->char_next = pdfont->u.simple.s.type3.char_procs;
267
 
    pdfont->u.simple.s.type3.char_procs = pcpo;
268
 
    pcpo->char_proc = pcp;
269
 
    pcpo->font_next = pcp->owner_fonts;
270
 
    pcp->owner_fonts = pcpo;
271
 
    pcpo->char_code = char_code;
272
 
    pcpo->glyph = glyph;
273
 
    if (gnstr == NULL) {
274
 
        pcpo->char_name.data = 0; 
275
 
        pcpo->char_name.size = 0;
276
 
    } else
277
 
        pcpo->char_name = *gnstr;
278
 
    pcpo->duplicate_char_name = duplicate_char_name;
279
 
    return 0;
280
 
}
281
 
 
282
 
/* Begin a CharProc for a synthesized (bitmap) font. */
283
 
int
284
 
pdf_begin_char_proc(gx_device_pdf * pdev, int w, int h, int x_width,
285
 
                    int y_offset, gs_id id, pdf_char_proc_t ** ppcp,
286
 
                    pdf_stream_position_t * ppos)
287
 
{
288
 
    int char_code = assign_char_code(pdev, pdev->pte);
289
 
    pdf_bitmap_fonts_t *const pbfs = pdev->text->bitmap_fonts; 
290
 
    pdf_font_resource_t *font = pbfs->open_font; /* Type 3 */
291
 
    pdf_resource_t *pres;
292
 
    pdf_char_proc_t *pcp;
293
 
    int code = pdf_begin_resource(pdev, resourceCharProc, id, &pres);
294
 
 
295
 
    if (code < 0)
296
 
        return code;
297
 
    pcp = (pdf_char_proc_t *) pres;
298
 
    code = pdf_attach_charproc(pdev, font, pcp, GS_NO_GLYPH, char_code, NULL);
299
 
    if (code < 0)
300
 
        return code;
301
 
    pres->object->written = true;
302
 
    {
303
 
        stream *s = pdev->strm;
304
 
 
305
 
        /*
306
 
         * The resource file is positionable, so rather than use an
307
 
         * object reference for the length, we'll go back and fill it in
308
 
         * at the end of the definition.  Take 1M as the longest
309
 
         * definition we can handle.  (This used to be 10K, but there was
310
 
         * a real file that exceeded this limit.)
311
 
         */
312
 
        stream_puts(s, "<</Length       >>stream\n");
313
 
        ppos->start_pos = stell(s);
314
 
    }
315
 
    code = pdf_begin_encrypt(pdev, &pdev->strm, pres->object->id);
316
 
    if (code < 0)
317
 
        return code;
318
 
    if (code < 0)
319
 
        return code;
320
 
    pcp->y_offset = y_offset;
321
 
    font->u.simple.s.type3.FontBBox.p.y =
322
 
        min(font->u.simple.s.type3.FontBBox.p.y, y_offset);
323
 
    font->u.simple.s.type3.FontBBox.q.x =
324
 
        max(font->u.simple.s.type3.FontBBox.q.x, w);
325
 
    font->u.simple.s.type3.FontBBox.q.y =
326
 
        max(font->u.simple.s.type3.FontBBox.q.y, y_offset + h);
327
 
    font->u.simple.s.type3.max_y_offset =
328
 
        max(font->u.simple.s.type3.max_y_offset, h + (h >> 2));
329
 
    *ppcp = pcp;
330
 
    return 0;
331
 
}
332
 
 
333
 
/* End a CharProc. */
334
 
int
335
 
pdf_end_char_proc(gx_device_pdf * pdev, pdf_stream_position_t * ppos)
336
 
{
337
 
    stream *s;
338
 
    long start_pos, end_pos, length;
339
 
 
340
 
    pdf_end_encrypt(pdev);
341
 
    s = pdev->strm;
342
 
    start_pos = ppos->start_pos;
343
 
    end_pos = stell(s);
344
 
    length = end_pos - start_pos;
345
 
    if (length > 999999)
346
 
        return_error(gs_error_limitcheck);
347
 
    sseek(s, start_pos - 15);
348
 
    pprintd1(s, "%d", length);
349
 
    sseek(s, end_pos);
350
 
    if (pdev->PDFA)
351
 
        stream_puts(s, "\n");
352
 
    stream_puts(s, "endstream\n");
353
 
    pdf_end_separate(pdev);
354
 
    return 0;
355
 
}
356
 
 
357
 
/* Mark glyph names for garbager. */
358
 
void
359
 
pdf_mark_glyph_names(const pdf_font_resource_t *pdfont, const gs_memory_t *memory)
360
 
{
361
 
    if (pdfont->mark_glyph == NULL) {
362
 
        /* Synthesised bitmap fonts pass here. */
363
 
        return;
364
 
    }
365
 
    if (pdfont->u.simple.Encoding != NULL) {
366
 
         int i;
367
 
 
368
 
         for (i = 0; i < 256; i++)
369
 
             if (pdfont->u.simple.Encoding[i].glyph != GS_NO_GLYPH)
370
 
                pdfont->mark_glyph(memory, pdfont->u.simple.Encoding[i].glyph, pdfont->mark_glyph_data);
371
 
     }
372
 
    if (pdfont->FontType == ft_user_defined) {
373
 
        const pdf_char_proc_ownership_t *pcpo = pdfont->u.simple.s.type3.char_procs;
374
 
 
375
 
        for (; pcpo != NULL; pcpo = pcpo->font_next)
376
 
            pdfont->mark_glyph(memory, pcpo->glyph, pdfont->mark_glyph_data);
377
 
    }
378
 
}
379
 
 
380
 
/* Put out a reference to an image as a character in a synthesized font. */
381
 
int
382
 
pdf_do_char_image(gx_device_pdf * pdev, const pdf_char_proc_t * pcp,
383
 
                  const gs_matrix * pimat)
384
 
{
385
 
    /* We need to choose a font, which use the charproc.
386
 
       In most cases it is the last font, which the charproc is attached to.
387
 
       If the charproc is substituted, it causes a font change. */
388
 
    const pdf_char_proc_ownership_t * pcpo = pcp->owner_fonts;
389
 
    pdf_font_resource_t *pdfont = pcpo->font;
390
 
    byte ch = pcpo->char_code;
391
 
    pdf_text_state_values_t values;
392
 
 
393
 
    values.character_spacing = 0;
394
 
    values.pdfont = pdfont;
395
 
    values.size = 1;
396
 
    values.matrix = *pimat;
397
 
    values.matrix.ty -= pcp->y_offset;
398
 
    values.render_mode = 0;
399
 
    values.word_spacing = 0;
400
 
    pdf_set_text_state_values(pdev, &values);
401
 
    pdf_append_chars(pdev, &ch, 1, pdfont->Widths[ch] * pimat->xx, 0.0, false);
402
 
    return 0;
403
 
}
404
 
 
405
 
/*
406
 
 * Write the Encoding for bitmap fonts, if needed.
407
 
 */
408
 
int
409
 
pdf_write_bitmap_fonts_Encoding(gx_device_pdf *pdev)
410
 
{
411
 
    pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
412
 
 
413
 
    if (pbfs->bitmap_encoding_id) {
414
 
        stream *s;
415
 
        int i;
416
 
 
417
 
        pdf_open_separate(pdev, pbfs->bitmap_encoding_id);
418
 
        s = pdev->strm;
419
 
        /*
420
 
         * Even though the PDF reference documentation says that a
421
 
         * BaseEncoding key is required unless the encoding is
422
 
         * "based on the base font's encoding" (and there is no base
423
 
         * font in this case), Acrobat 2.1 gives an error if the
424
 
         * BaseEncoding key is present.
425
 
         */
426
 
        stream_puts(s, "<</Type/Encoding/Differences[0");
427
 
        for (i = 0; i <= pbfs->max_embedded_code; ++i) {
428
 
            if (!(i & 15))
429
 
                stream_puts(s, "\n");
430
 
            pprintd1(s, "/a%d", i);
431
 
        }
432
 
        stream_puts(s, "\n] >>\n");
433
 
        pdf_end_separate(pdev);
434
 
        pbfs->bitmap_encoding_id = 0;
435
 
    }
436
 
    return 0;
437
 
}
438
 
 
439
 
/*
440
 
 * Start charproc accumulation for a Type 3 font.
441
 
 */
442
 
int
443
 
pdf_start_charproc_accum(gx_device_pdf *pdev)
444
 
{
445
 
    pdf_char_proc_t *pcp;
446
 
    pdf_resource_t *pres;
447
 
    int code = pdf_enter_substream(pdev, resourceCharProc, gs_next_ids(pdev->memory, 1), 
448
 
                                   &pres, false, pdev->CompressFonts);
449
 
 
450
 
    if (code < 0)
451
 
       return code;
452
 
    pcp = (pdf_char_proc_t *)pres;
453
 
    pcp->owner_fonts = NULL;
454
 
    return 0;
455
 
}
456
 
 
457
 
/*
458
 
 * Install charproc accumulator for a Type 3 font.
459
 
 */
460
 
int
461
 
pdf_set_charproc_attrs(gx_device_pdf *pdev, gs_font *font, const double *pw, int narg,
462
 
                gs_text_cache_control_t control, gs_char ch)
463
 
{
464
 
    pdf_font_resource_t *pdfont;
465
 
    pdf_resource_t *pres = pdev->accumulating_substream_resource;
466
 
    pdf_char_proc_t *pcp;
467
 
    int code;
468
 
 
469
 
    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
470
 
    if (code < 0)
471
 
        return code;
472
 
    pcp = (pdf_char_proc_t *)pres;
473
 
    pcp->owner_fonts = NULL;
474
 
    pcp->real_width.x = pw[font->WMode && narg > 6 ? 6 : 0];
475
 
    pcp->real_width.y = pw[font->WMode && narg > 6 ? 7 : 1];
476
 
    pcp->v.x = (narg > 8 ? pw[8] : 0);
477
 
    pcp->v.y = (narg > 8 ? pw[9] : 0);
478
 
    if (control == TEXT_SET_CHAR_WIDTH) {
479
 
        /* PLRM 5.7.1 "BuildGlyph" reads : "Normally, it is unnecessary and 
480
 
        undesirable to initialize the current color parameter, because show 
481
 
        is defined to paint glyphs with the current color."
482
 
        However comparefiles/Bug687044.ps doesn't follow that. */
483
 
        pdev->skip_colors = false; 
484
 
        pprintg1(pdev->strm, "%g 0 d0\n", (float)pw[0]);
485
 
    } else {
486
 
        pdev->skip_colors = true;
487
 
        pprintg6(pdev->strm, "%g %g %g %g %g %g d1\n", 
488
 
            (float)pw[0], (float)0.0, (float)pw[2], 
489
 
            (float)pw[3], (float)pw[4], (float)pw[5]);
490
 
        pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
491
 
    }
492
 
    return 0;
493
 
}
494
 
 
495
 
/*
496
 
 * Open a stream object in the temporary file.
497
 
 */
498
 
 
499
 
int
500
 
pdf_open_aside(gx_device_pdf *pdev, pdf_resource_type_t rtype, 
501
 
        gs_id id, pdf_resource_t **ppres, bool reserve_object_id, int options) 
502
 
{
503
 
    int code;
504
 
    pdf_resource_t *pres;
505
 
    stream *s, *save_strm = pdev->strm;
506
 
    pdf_data_writer_t writer;
507
 
    static const pdf_filter_names_t fnames = {
508
 
        PDF_FILTER_NAMES
509
 
    };
510
 
 
511
 
    pdev->streams.save_strm = pdev->strm;
512
 
    code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, id),
513
 
                pdf_resource_type_structs[rtype], &pres, reserve_object_id ? 0 : -1);
514
 
    if (code < 0)
515
 
        return code;
516
 
    cos_become(pres->object, cos_type_stream);
517
 
    s = cos_write_stream_alloc((cos_stream_t *)pres->object, pdev, "pdf_enter_substream");
518
 
    if (s == 0)
519
 
        return_error(gs_error_VMerror);
520
 
    pdev->strm = s;
521
 
    code = pdf_append_data_stream_filters(pdev, &writer,
522
 
                             options | DATA_STREAM_NOLENGTH, pres->object->id);
523
 
    if (code < 0) {
524
 
        pdev->strm = save_strm;
525
 
        return code;
526
 
    }
527
 
    code = pdf_put_filters((cos_dict_t *)pres->object, pdev, writer.binary.strm, &fnames);
528
 
    if (code < 0) {
529
 
        pdev->strm = save_strm;
530
 
        return code;
531
 
    }
532
 
    pdev->strm = writer.binary.strm;
533
 
    *ppres = pres;
534
 
    return 0;
535
 
}
536
 
 
537
 
/*
538
 
 * Close a stream object in the temporary file.
539
 
 */
540
 
int
541
 
pdf_close_aside(gx_device_pdf *pdev) 
542
 
{
543
 
    /* We should call pdf_end_data here, but we don't want to put pdf_data_writer_t
544
 
       into pdf_substream_save stack to simplify garbager descriptors. 
545
 
       Use a lower level functions instead that. */
546
 
    stream *s = pdev->strm;
547
 
    int status = s_close_filters(&s, cos_write_stream_from_pipeline(s));
548
 
    cos_stream_t *pcs = cos_stream_from_pipeline(s);
549
 
    int code = 0;
550
 
 
551
 
    if (status < 0)
552
 
         code = gs_note_error(gs_error_ioerror);
553
 
    pcs->is_open = false;
554
 
    sclose(s);
555
 
    pdev->strm = pdev->streams.save_strm;
556
 
    return code;
557
 
}
558
 
 
559
 
/*
560
 
 * Enter the substream accumulation mode.
561
 
 */
562
 
int
563
 
pdf_enter_substream(gx_device_pdf *pdev, pdf_resource_type_t rtype, 
564
 
        gs_id id, pdf_resource_t **ppres, bool reserve_object_id, bool compress) 
565
 
{
566
 
    int sbstack_ptr = pdev->sbstack_depth;
567
 
    pdf_resource_t *pres;
568
 
    stream *save_strm = pdev->strm;
569
 
    int code;
570
 
 
571
 
    if (pdev->sbstack_depth >= pdev->sbstack_size)
572
 
        return_error(gs_error_unregistered); /* Must not happen. */
573
 
    if (pdev->sbstack[sbstack_ptr].text_state == 0) {
574
 
        pdev->sbstack[sbstack_ptr].text_state = pdf_text_state_alloc(pdev->pdf_memory);
575
 
        if (pdev->sbstack[sbstack_ptr].text_state == 0)
576
 
            return_error(gs_error_VMerror);
577
 
    }
578
 
    code = pdf_open_aside(pdev, rtype, id, &pres, reserve_object_id, 
579
 
                    (compress ? DATA_STREAM_COMPRESS : 0));
580
 
    if (code < 0)
581
 
        return code;
582
 
    code = pdf_save_viewer_state(pdev, NULL);
583
 
    if (code < 0) {
584
 
        pdev->strm = save_strm;
585
 
        return code;
586
 
    }
587
 
    pdev->sbstack[sbstack_ptr].context = pdev->context;
588
 
    pdf_text_state_copy(pdev->sbstack[sbstack_ptr].text_state, pdev->text->text_state);
589
 
    pdf_set_text_state_default(pdev->text->text_state);
590
 
    pdev->sbstack[sbstack_ptr].clip_path = pdev->clip_path;
591
 
    pdev->clip_path = 0;
592
 
    pdev->sbstack[sbstack_ptr].clip_path_id = pdev->clip_path_id;
593
 
    pdev->clip_path_id = pdev->no_clip_path_id;
594
 
    pdev->sbstack[sbstack_ptr].vgstack_bottom = pdev->vgstack_bottom;
595
 
    pdev->vgstack_bottom = pdev->vgstack_depth;
596
 
    pdev->sbstack[sbstack_ptr].strm = save_strm;
597
 
    pdev->sbstack[sbstack_ptr].procsets = pdev->procsets;
598
 
    pdev->sbstack[sbstack_ptr].substream_Resources = pdev->substream_Resources;
599
 
    pdev->sbstack[sbstack_ptr].skip_colors = pdev->skip_colors;
600
 
    pdev->sbstack[sbstack_ptr].font3 = pdev->font3;
601
 
    pdev->sbstack[sbstack_ptr].accumulating_substream_resource = pdev->accumulating_substream_resource;
602
 
    pdev->sbstack[sbstack_ptr].charproc_just_accumulated = pdev->charproc_just_accumulated;
603
 
    pdev->sbstack[sbstack_ptr].accumulating_a_global_object = pdev->accumulating_a_global_object;
604
 
    pdev->sbstack[sbstack_ptr].pres_soft_mask_dict = pdev->pres_soft_mask_dict;
605
 
    pdev->sbstack[sbstack_ptr].objname = pdev->objname;
606
 
    pdev->sbstack[sbstack_ptr].last_charpath_op = pdev->last_charpath_op;
607
 
    pdev->skip_colors = false;
608
 
    pdev->charproc_just_accumulated = false;
609
 
    pdev->pres_soft_mask_dict = NULL;
610
 
    pdev->objname.data = NULL;
611
 
    pdev->objname.size = 0;
612
 
    /* Do not reset pdev->accumulating_a_global_object - it inherits. */
613
 
    pdev->sbstack_depth++;
614
 
    pdev->procsets = 0;
615
 
    pdev->font3 = 0;
616
 
    pdev->context = PDF_IN_STREAM;
617
 
    pdev->accumulating_substream_resource = pres;
618
 
    pdev->last_charpath_op = 0;
619
 
    /* Do not alter type3charpath, inherit the current value. We need to know if */
620
 
    /* we are inside a charpath operation, and only reset this when the charpath */
621
 
    /* is complete */
622
 
    pdf_reset_graphics(pdev);
623
 
    *ppres = pres;
624
 
    return 0;
625
 
}
626
 
 
627
 
/*
628
 
 * Exit the substream accumulation mode.
629
 
 */
630
 
int
631
 
pdf_exit_substream(gx_device_pdf *pdev) 
632
 
{
633
 
    int code, code1;
634
 
    int sbstack_ptr;
635
 
 
636
 
    if (pdev->sbstack_depth <= 0)
637
 
        return_error(gs_error_unregistered); /* Must not happen. */
638
 
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
639
 
    sbstack_ptr = pdev->sbstack_depth - 1;
640
 
    while (pdev->vgstack_depth > pdev->vgstack_bottom) {
641
 
        code1 = pdf_restore_viewer_state(pdev, pdev->strm);
642
 
        if (code >= 0)
643
 
            code = code1;
644
 
    }
645
 
    if (pdev->clip_path != 0)
646
 
        gx_path_free(pdev->clip_path, "pdf_end_charproc_accum");
647
 
    code1 = pdf_close_aside(pdev);
648
 
    if (code1 < 0 && code >= 0)
649
 
        code = code1;
650
 
    pdev->context = pdev->sbstack[sbstack_ptr].context;
651
 
    pdf_text_state_copy(pdev->text->text_state, pdev->sbstack[sbstack_ptr].text_state);
652
 
    pdev->clip_path = pdev->sbstack[sbstack_ptr].clip_path;
653
 
    pdev->sbstack[sbstack_ptr].clip_path = 0;
654
 
    pdev->clip_path_id = pdev->sbstack[sbstack_ptr].clip_path_id;
655
 
    pdev->vgstack_bottom = pdev->sbstack[sbstack_ptr].vgstack_bottom;
656
 
    pdev->strm = pdev->sbstack[sbstack_ptr].strm;
657
 
    pdev->sbstack[sbstack_ptr].strm = 0;
658
 
    pdev->procsets = pdev->sbstack[sbstack_ptr].procsets;
659
 
    pdev->substream_Resources = pdev->sbstack[sbstack_ptr].substream_Resources;
660
 
    pdev->sbstack[sbstack_ptr].substream_Resources = 0;
661
 
    pdev->skip_colors = pdev->sbstack[sbstack_ptr].skip_colors;
662
 
    pdev->font3 = pdev->sbstack[sbstack_ptr].font3;
663
 
    pdev->sbstack[sbstack_ptr].font3 = 0;
664
 
    pdev->accumulating_substream_resource = pdev->sbstack[sbstack_ptr].accumulating_substream_resource;
665
 
    pdev->sbstack[sbstack_ptr].accumulating_substream_resource = 0;
666
 
    pdev->charproc_just_accumulated = pdev->sbstack[sbstack_ptr].charproc_just_accumulated;
667
 
    pdev->accumulating_a_global_object = pdev->sbstack[sbstack_ptr].accumulating_a_global_object;
668
 
    pdev->pres_soft_mask_dict = pdev->sbstack[sbstack_ptr].pres_soft_mask_dict;
669
 
    pdev->objname = pdev->sbstack[sbstack_ptr].objname;
670
 
    pdev->last_charpath_op = pdev->sbstack[sbstack_ptr].last_charpath_op;
671
 
    pdev->sbstack_depth = sbstack_ptr;
672
 
    code1 = pdf_restore_viewer_state(pdev, NULL);
673
 
    if (code1 < 0 && code >= 0)
674
 
        code = code1;
675
 
    return code;
676
 
}
677
 
 
678
 
static bool 
679
 
pdf_is_same_charproc_attrs1(gx_device_pdf *pdev, pdf_char_proc_t *pcp0, pdf_char_proc_t *pcp1)
680
 
{
681
 
    if (pcp0->real_width.x != pcp1->real_width.x)
682
 
        return false;
683
 
    if (pcp0->real_width.y != pcp1->real_width.y)
684
 
        return false;
685
 
    if (pcp0->v.x != pcp1->v.x)
686
 
        return false;
687
 
    if (pcp0->v.y != pcp1->v.y)
688
 
        return false;
689
 
    return true;
690
 
}
691
 
 
692
 
typedef struct charproc_compatibility_data_s {
693
 
    const pdf_char_glyph_pairs_t *cgp;
694
 
    pdf_font_resource_t *pdfont;
695
 
    gs_char char_code;
696
 
    gs_glyph glyph;
697
 
    gs_font *font;
698
 
} charproc_compatibility_data_t;
699
 
 
700
 
static bool
701
 
is_char_code_used(pdf_font_resource_t *pdfont, gs_char char_code)
702
 
{
703
 
    pdf_char_proc_ownership_t *pcpo;
704
 
 
705
 
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
706
 
        if (pcpo->char_code == char_code) {
707
 
            return true;
708
 
        }
709
 
    }
710
 
    return false;
711
 
}
712
 
 
713
 
static int 
714
 
pdf_is_charproc_compatible(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1)
715
 
{
716
 
    charproc_compatibility_data_t *data = (charproc_compatibility_data_t *)pdev->find_resource_param;
717
 
    pdf_char_proc_t *pcp0 = (pdf_char_proc_t *)pres0;
718
 
    pdf_char_proc_t *pcp1 = (pdf_char_proc_t *)pres1;
719
 
    pdf_font_resource_t *pdfont = data->pdfont;
720
 
    pdf_char_proc_ownership_t *pcpo;
721
 
    pdf_font_cache_elem_t **e;
722
 
    bool can_add_to_current_font = false, computed_can_add_to_current_font = false;
723
 
 
724
 
    /* Does it have same attributes ? */
725
 
    if (!pdf_is_same_charproc_attrs1(pdev, pcp0, pcp1))
726
 
        return 0;
727
 
    /* Is it from same font ? */
728
 
    for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
729
 
        if (pdfont == pcpo->font) {
730
 
            /* Check for encoding conflict. */
731
 
            if (pcpo->char_code == data->char_code && pcpo->glyph == data->glyph)
732
 
                return 1; /* Same char code. */
733
 
            if (!computed_can_add_to_current_font) {
734
 
                can_add_to_current_font = !is_char_code_used(pdfont, data->char_code);
735
 
                computed_can_add_to_current_font = true;
736
 
            }
737
 
            if (can_add_to_current_font)
738
 
                return 1; /* No conflict. */
739
 
        }
740
 
    }
741
 
    /* Look for another font with same encoding,
742
 
       because we want to reduce the number of new fonts. 
743
 
       We also restrict with ones attached to same PS font,
744
 
       otherwise it creates too mixed fonts and disturbs word breaks.
745
 
     */
746
 
    e = pdf_locate_font_cache_elem(pdev, data->font);
747
 
    if (e != NULL) {
748
 
        for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
749
 
            if (pcpo->char_code != data->char_code || pcpo->glyph != data->glyph)
750
 
                continue; /* Need same Encoding to generate a proper ToUnicode. */
751
 
            if (pdfont->u.simple.s.type3.bitmap_font != pcpo->font->u.simple.s.type3.bitmap_font)
752
 
                continue;
753
 
            if (memcmp(&pdfont->u.simple.s.type3.FontMatrix, &pcpo->font->u.simple.s.type3.FontMatrix,
754
 
                        sizeof(pdfont->u.simple.s.type3.FontMatrix)))
755
 
                continue;
756
 
            if (data->cgp != NULL) {
757
 
                if (!pdf_check_encoding_compatibility(pcpo->font, data->cgp->s, data->cgp->num_all_chars))
758
 
                    continue;
759
 
            }
760
 
            if ((*e)->pdfont != pcpo->font)
761
 
                continue;
762
 
            data->pdfont = pcpo->font; /* Switch to the other font. */
763
 
            return 1;
764
 
        }
765
 
    }
766
 
    /* Check whether it can be added into the current font. */
767
 
    if (!computed_can_add_to_current_font)
768
 
        can_add_to_current_font = !is_char_code_used(pdfont, data->char_code);
769
 
    if (!can_add_to_current_font) {
770
 
        /* Can't substitute due to encoding conflict. */
771
 
        return 0;
772
 
    }
773
 
    /* The current font will share it with another font. */
774
 
    return 1;
775
 
}
776
 
 
777
 
static int 
778
 
pdf_find_same_charproc_aux(gx_device_pdf *pdev, 
779
 
            pdf_font_resource_t **ppdfont, pdf_char_proc_t **ppcp)
780
 
{
781
 
    pdf_char_proc_ownership_t *pcpo;
782
 
    int code;
783
 
 
784
 
    /* fixme: this passes parameters to pdf_is_charproc_compatible 
785
 
       through special gx_device_pdf field pdev->find_resource_param
786
 
       due to prototype limitation of pdf_find_same_resource.
787
 
       It would be better to change the client data argument type in there to void. */
788
 
    for (pcpo = (*ppdfont)->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
789
 
        pdf_char_proc_t *pcp = pcpo->char_proc;
790
 
 
791
 
        if (*ppcp != pcp && pdf_is_same_charproc_attrs1(pdev, *ppcp, pcp)) {
792
 
            cos_object_t *pco0 = pcp->object;
793
 
            cos_object_t *pco1 = (*ppcp)->object;
794
 
 
795
 
            code = pco0->cos_procs->equal(pco0, pco1, pdev);
796
 
            if (code < 0) {
797
 
                return code;
798
 
            }
799
 
            if (code) {
800
 
                *ppcp = pcp;
801
 
                return 1;
802
 
            }
803
 
        }
804
 
    }
805
 
    return pdf_find_same_resource(pdev, resourceCharProc, (pdf_resource_t **)ppcp, pdf_is_charproc_compatible);
806
 
}
807
 
static int 
808
 
pdf_find_same_charproc(gx_device_pdf *pdev, 
809
 
            pdf_font_resource_t **ppdfont, const pdf_char_glyph_pairs_t *cgp, 
810
 
            pdf_char_proc_t **ppcp, gs_glyph glyph, gs_char char_code,
811
 
            gs_font *font)
812
 
{
813
 
    charproc_compatibility_data_t data;
814
 
    int code;
815
 
 
816
 
    data.cgp = cgp;
817
 
    data.pdfont = *ppdfont;
818
 
    data.char_code = char_code;
819
 
    data.glyph = glyph;
820
 
    data.font = font;
821
 
    pdev->find_resource_param = &data;
822
 
    code = pdf_find_same_charproc_aux(pdev, ppdfont, ppcp);
823
 
    pdev->find_resource_param = NULL;
824
 
    *ppdfont = data.pdfont;
825
 
    return code;
826
 
}
827
 
 
828
 
static bool
829
 
pdf_is_charproc_defined(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, gs_char ch)
830
 
{
831
 
    pdf_char_proc_ownership_t *pcpo;
832
 
 
833
 
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
834
 
        if (pcpo->char_code == ch)
835
 
            return true;
836
 
    }
837
 
    return false;
838
 
}
839
 
 
840
 
static int
841
 
complete_adding_char(gx_device_pdf *pdev, gs_font *font, 
842
 
                     gs_glyph glyph, gs_char ch, pdf_char_proc_t *pcp,
843
 
                     const gs_const_string *gnstr)
844
 
{   
845
 
    pdf_font_resource_t *pdfont;
846
 
    double *real_widths;
847
 
    byte *glyph_usage;
848
 
    int char_cache_size, width_cache_size;
849
 
    pdf_encoding_element_t *pet;
850
 
    int code;
851
 
 
852
 
    code = pdf_attached_font_resource(pdev, font, &pdfont,
853
 
                &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
854
 
    if (code < 0)
855
 
        return code;
856
 
    code = pdf_attach_charproc(pdev, pdfont, pcp, glyph, ch, gnstr);
857
 
    if (code < 0)
858
 
        return code;
859
 
    if (ch >= char_cache_size || ch >= width_cache_size)
860
 
        return_error(gs_error_unregistered); /* Must not happen. */
861
 
    pet = &pdfont->u.simple.Encoding[ch];
862
 
    pdfont->Widths[ch] = pcp->real_width.x;
863
 
    real_widths[ch * 2    ] = pcp->real_width.x;
864
 
    real_widths[ch * 2 + 1] = pcp->real_width.y;
865
 
    glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
866
 
    pdfont->used[ch >> 3] |= 0x80 >> (ch & 7);
867
 
    if (pdfont->u.simple.v != NULL && font->WMode) {
868
 
        pdfont->u.simple.v[ch].x = pcp->v.x;
869
 
        pdfont->u.simple.v[ch].y = pcp->v.x;
870
 
    }
871
 
    pet->glyph = glyph;
872
 
    pet->str = *gnstr;
873
 
    pet->is_difference = true;
874
 
    if (pdfont->u.simple.LastChar < (int)ch)
875
 
        pdfont->u.simple.LastChar = (int)ch;
876
 
    if (pdfont->u.simple.FirstChar > (int)ch)
877
 
        pdfont->u.simple.FirstChar = (int)ch;
878
 
    return 0;
879
 
}
880
 
 
881
 
static int
882
 
pdf_char_widths_from_charprocs(gx_device_pdf *pdev, gs_font *font)
883
 
{
884
 
    pdf_font_resource_t *pdfont;
885
 
    double *real_widths;
886
 
    byte *glyph_usage;
887
 
    int char_cache_size, width_cache_size;
888
 
    pdf_char_proc_ownership_t *pcpo;
889
 
    int code;
890
 
 
891
 
    code = pdf_attached_font_resource(pdev, font, &pdfont,
892
 
                &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
893
 
    if (code < 0)
894
 
        return code;
895
 
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
896
 
        pdf_char_proc_t *pcp = pcpo->char_proc;
897
 
        gs_char ch = pcpo->char_code;
898
 
 
899
 
        real_widths[ch * 2    ] = pcp->real_width.x;
900
 
        real_widths[ch * 2 + 1] = pcp->real_width.y;
901
 
        glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
902
 
    }
903
 
    return 0;
904
 
}
905
 
 
906
 
 
907
 
/*
908
 
 * Complete charproc accumulation for a Type 3 font.
909
 
 */
910
 
int
911
 
pdf_end_charproc_accum(gx_device_pdf *pdev, gs_font *font, const pdf_char_glyph_pairs_t *cgp, 
912
 
                       gs_glyph glyph, gs_char output_char_code, const gs_const_string *gnstr) 
913
 
{
914
 
    int code;
915
 
    pdf_resource_t *pres = (pdf_resource_t *)pdev->accumulating_substream_resource;
916
 
    /* We could use pdfont->u.simple.s.type3.char_procs insted the thing above
917
 
       unless the font is defined recursively.
918
 
       But we don't want such assumption. */
919
 
    pdf_char_proc_t *pcp = (pdf_char_proc_t *)pres;
920
 
    pdf_font_resource_t *pdfont;
921
 
    gs_char ch = output_char_code;
922
 
    bool checking_glyph_variation = false;
923
 
 
924
 
    if (ch == GS_NO_CHAR)
925
 
        return_error(gs_error_unregistered); /* Must not happen. */
926
 
    if (ch >= 256)
927
 
        return_error(gs_error_unregistered); /* Must not happen. */
928
 
    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
929
 
    if (code < 0)
930
 
        return code;
931
 
    if (pdfont != (pdf_font_resource_t *)pdev->font3)
932
 
        return_error(gs_error_unregistered); /* Must not happen. */
933
 
    code = pdf_exit_substream(pdev);
934
 
    if (code < 0)
935
 
        return code;
936
 
    if (!(pdfont->used[ch >> 3] & (0x80 >> (ch & 7))) ||
937
 
        !(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))) {
938
 
        /* First appearence or not cached - check for duplicates. */
939
 
        pdf_font_resource_t *pdfont1 = pdfont;
940
 
 
941
 
        checking_glyph_variation = true;
942
 
        /* CAUTION : a possible font change. */
943
 
        code = pdf_find_same_charproc(pdev, &pdfont, cgp, &pcp, glyph, ch, font);
944
 
        if (code < 0)
945
 
            return code;
946
 
        if (code != 0) {
947
 
            code = pdf_cancel_resource(pdev, pres, resourceCharProc);
948
 
            if (code < 0)
949
 
                return code;
950
 
            pdf_forget_resource(pdev, pres, resourceCharProc);
951
 
            if (pdfont1 != pdfont) {
952
 
                code = pdf_attach_font_resource(pdev, font, pdfont);
953
 
                if (code < 0)
954
 
                    return code;
955
 
                code = pdf_char_widths_from_charprocs(pdev, font);
956
 
                if (code < 0)
957
 
                    return code;
958
 
            }
959
 
            pdev->charproc_just_accumulated = true;
960
 
            return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
961
 
        }
962
 
        if (pdf_is_charproc_defined(pdev, pdfont, ch)) {
963
 
            /* Encoding conflict after a font change. */
964
 
            gs_font *base_font = font, *below;
965
 
 
966
 
            while ((below = base_font->base) != base_font &&
967
 
                    base_font->procs.same_font(base_font, below, FONT_SAME_OUTLINES))
968
 
                base_font = below;
969
 
            code = pdf_make_font3_resource(pdev, base_font, &pdfont);
970
 
            if (code < 0)
971
 
                return code;
972
 
            code = pdf_attach_font_resource(pdev, font, pdfont);
973
 
            if (code < 0)
974
 
                return code;
975
 
        }
976
 
    } 
977
 
    pdf_reserve_object_id(pdev, pres, 0);
978
 
    if (checking_glyph_variation)
979
 
        pdev->charproc_just_accumulated = true;
980
 
    return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
981
 
}
982
 
 
983
 
/* Add procsets to substream Resources. */
984
 
int
985
 
pdf_add_procsets(cos_dict_t *pcd, pdf_procset_t procsets)
986
 
{
987
 
    char str[5 + 7 + 7 + 7 + 5 + 2];
988
 
    cos_value_t v;
989
 
 
990
 
    strcpy(str, "[/PDF");
991
 
    if (procsets & ImageB)
992
 
        strcat(str, "/ImageB");
993
 
    if (procsets & ImageC)
994
 
        strcat(str, "/ImageC");
995
 
    if (procsets & ImageI)
996
 
        strcat(str, "/ImageI");
997
 
    if (procsets & Text)
998
 
        strcat(str, "/Text");
999
 
    strcat(str, "]");
1000
 
    cos_string_value(&v, (byte *)str, strlen(str));
1001
 
    return cos_dict_put_c_key(pcd, "/ProcSet", &v);
1002
 
}
1003
 
 
1004
 
/* Add a resource to substream Resources. */
1005
 
int
1006
 
pdf_add_resource(gx_device_pdf *pdev, cos_dict_t *pcd, const char *key, pdf_resource_t *pres)
1007
 
{
1008
 
    if (pcd != 0) {
1009
 
        const cos_value_t *v = cos_dict_find(pcd, (const byte *)key, strlen(key));
1010
 
        cos_dict_t *list;
1011
 
        int code;
1012
 
        char buf[10 + (sizeof(long) * 8 / 3 + 1)], buf1[sizeof(pres->rname) + 1];
1013
 
 
1014
 
        if (pdev->ForOPDFRead && !pres->global && pdev->accumulating_a_global_object) {
1015
 
            pres->global = true;
1016
 
            code = cos_dict_put_c_key_bool((cos_dict_t *)pres->object, "/.Global", true);
1017
 
            if (code < 0)
1018
 
                return code;
1019
 
        }
1020
 
        sprintf(buf, "%ld 0 R\n", pres->object->id);
1021
 
        if (v != NULL) {
1022
 
            if (v->value_type != COS_VALUE_OBJECT && 
1023
 
                v->value_type != COS_VALUE_RESOURCE)
1024
 
                return_error(gs_error_unregistered); /* Must not happen. */
1025
 
            list = (cos_dict_t *)v->contents.object;    
1026
 
            if (list->cos_procs != &cos_dict_procs)
1027
 
                return_error(gs_error_unregistered); /* Must not happen. */
1028
 
        } else {
1029
 
            list = cos_dict_alloc(pdev, "pdf_add_resource");
1030
 
            if (list == NULL)
1031
 
                return_error(gs_error_VMerror);
1032
 
            code = cos_dict_put_c_key_object((cos_dict_t *)pcd, key, (cos_object_t *)list);
1033
 
            if (code < 0)
1034
 
                return code;
1035
 
        }
1036
 
        buf1[0] = '/';
1037
 
        strcpy(buf1 + 1, pres->rname);
1038
 
        return cos_dict_put_string(list, (const byte *)buf1, strlen(buf1),
1039
 
                        (const byte *)buf, strlen(buf));
1040
 
    }
1041
 
    return 0;
1042
 
}
1043