1% pdfglyph.w
2%
3% Copyright 2009-2011 Taco Hoekwater <taco@@luatex.org>
4%
5% This file is part of LuaTeX.
6%
7% LuaTeX is free software; you can redistribute it and/or modify it under
8% the terms of the GNU General Public License as published by the Free
9% Software Foundation; either version 2 of the License, or (at your
10% option) any later version.
11%
12% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15% License for more details.
16%
17% You should have received a copy of the GNU General Public License along
18% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
19
20@ @c
21
22
23#include "ptexlib.h"
24#include "pdf/pdfpage.h"
25
26#define pdf2double(a) ((double) (a).m / ten_pow[(a).e])
27
28@ eternal constants
29@c
30#define one_bp ((double) 65536 * (double) 72.27 / 72)   /* number of sp per 1bp */
31#define e_tj 3                  /* must be 3; movements in []TJ are in fontsize/$10^3$ units */
32
33@ @c
34static int64_t pdf_char_width(pdfstructure * p, internal_font_number f, int i)
35{
36    /* use exactly this formula also for calculating the /Width array values */
37    return
38        i64round((double) char_width(f, i) / font_size(f) *
39               ten_pow[e_tj + p->cw.e]);
40}
41
42@ @c
43void pdf_print_charwidth(PDF pdf, internal_font_number f, int i)
44{
45    pdffloat cw;
46    pdfstructure *p = pdf->pstruct;
47    cw.m = pdf_char_width(p, f, i);
48    cw.e = p->cw.e;
49    print_pdffloat(pdf, cw);
50}
51
52@ @c
53static void setup_fontparameters(PDF pdf, internal_font_number f, int ex_glyph)
54{
55    float slant, extend, expand, scale = 1.0;
56    float u = 1.0;
57    pdfstructure *p = pdf->pstruct;
58    /* fix mantis bug \# 0000200 (acroread "feature") */
59    if ((font_format(f) == opentype_format ||
60         (font_format(f) == type1_format && font_encodingbytes(f) == 2))
61        && font_units_per_em(f) > 0)
62        u = font_units_per_em(f) / 1000.0;
63    pdf->f_cur = f;
64    p->f_pdf = pdf_set_font(pdf, f);
65    p->fs.m = i64round(font_size(f) / u / one_bp * ten_pow[p->fs.e]);
66    slant = font_slant(f) / 1000.0;
67    extend = font_extend(f) / 1000.0;
68    expand = 1.0 + (ex_glyph/1) / 1000.0;
69    p->tj_delta.e = p->cw.e - 1;        /* "- 1" makes less corrections inside []TJ */
70    /* no need to be more precise than TeX (1sp) */
71    while (p->tj_delta.e > 0
72           && (double) font_size(f) / ten_pow[p->tj_delta.e + e_tj] < 0.5)
73        p->tj_delta.e--;        /* happens for very tiny fonts */
74    assert(p->cw.e >= p->tj_delta.e);   /* else we would need, e. g., |ten_pow[-1]| */
75    p->tm[0].m = i64round(scale * expand * extend * ten_pow[p->tm[0].e]);
76    p->tm[2].m = i64round(slant * ten_pow[p->tm[2].e]);
77    p->tm[3].m = i64round(scale * ten_pow[p->tm[3].e]);
78    p->k2 =
79        ten_pow[e_tj +
80                p->cw.e] * scale / (ten_pow[p->pdf.h.e] * pdf2double(p->fs) *
81                                    pdf2double(p->tm[0]));
82    p->cur_ex = ex_glyph ;  /* we keep track of the state of ex */
83}
84
85
86@ @c
87static void set_font(PDF pdf)
88{
89    pdfstructure *p = pdf->pstruct;
90    pdf_printf(pdf, "/F%d", (int) p->f_pdf);
91    pdf_print_resname_prefix(pdf);
92    pdf_out(pdf, ' ');
93    print_pdffloat(pdf, p->fs);
94    pdf_puts(pdf, " Tf ");
95    p->f_pdf_cur = p->f_pdf;
96    p->fs_cur.m = p->fs.m;
97    p->need_tf = false;
98    p->need_tm = true;          /* always follow Tf by Tm */
99}
100
101@ @c
102static void set_textmatrix(PDF pdf, scaledpos pos)
103{
104    boolean move;
105    pdfstructure *p = pdf->pstruct;
106    assert(is_textmode(p));
107    move = calc_pdfpos(p, pos);
108    if (p->need_tm || move) {
109        print_pdf_matrix(pdf, p->tm);
110        pdf_puts(pdf, " Tm ");
111        p->pdf.h.m = p->pdf_bt_pos.h.m + p->tm[4].m;    /* Tm replaces */
112        p->pdf.v.m = p->pdf_bt_pos.v.m + p->tm[5].m;
113        p->need_tm = false;
114    }
115    p->tm0_cur.m = p->tm[0].m;
116}
117
118@ Print out a character to PDF buffer; the character will be printed in octal
119form in the following cases: chars <= 32, backslash (92), left parenthesis
120(40), and right parenthesis (41).
121@c
122static void pdf_print_char(PDF pdf, int c)
123{
124    if (c > 255)
125        return;
126    /* pdf_print_escaped(c) */
127    if (c <= 32 || c == '\\' || c == '(' || c == ')' || c > 127) {
128        pdf_room(pdf, 4);
129        pdf_quick_out(pdf, '\\');
130        pdf_quick_out(pdf, (unsigned char) ('0' + ((c >> 6) & 0x3)));
131        pdf_quick_out(pdf, (unsigned char) ('0' + ((c >> 3) & 0x7)));
132        pdf_quick_out(pdf, (unsigned char) ('0' + (c & 0x7)));
133    } else
134        pdf_out(pdf, c);
135}
136
137static void pdf_print_wide_char(PDF pdf, int c)
138{
139    char hex[5];
140    snprintf(hex, 5, "%04X", c);
141    pdf_out_block(pdf, (const char *) hex, 4);
142}
143
144@ @c
145static void begin_charmode(PDF pdf, internal_font_number f, pdfstructure * p)
146{
147    assert(is_chararraymode(p));
148    if (font_encodingbytes(f) == 2) {
149        p->ishex = 1;
150        pdf_out(pdf, '<');
151    } else {
152        p->ishex = 0;
153        pdf_out(pdf, '(');
154    }
155    p->mode = PMODE_CHAR;
156}
157
158@ @c
159void end_charmode(PDF pdf)
160{
161    pdfstructure *p = pdf->pstruct;
162    assert(is_charmode(p));
163    if (p->ishex == 1) {
164        p->ishex = 0;
165        pdf_out(pdf, '>');
166    } else {
167        pdf_out(pdf, ')');
168    }
169    p->mode = PMODE_CHARARRAY;
170}
171
172@ @c
173static void begin_chararray(PDF pdf)
174{
175    pdfstructure *p = pdf->pstruct;
176    assert(is_textmode(p));
177    p->pdf_tj_pos = p->pdf;
178    p->cw.m = 0;
179    pdf_out(pdf, '[');
180    p->mode = PMODE_CHARARRAY;
181}
182
183@ @c
184void end_chararray(PDF pdf)
185{
186    pdfstructure *p = pdf->pstruct;
187    assert(is_chararraymode(p));
188    pdf_puts(pdf, "]TJ\n");
189    p->pdf = p->pdf_tj_pos;
190    p->mode = PMODE_TEXT;
191}
192
193@ @c
194void pdf_place_glyph(PDF pdf, internal_font_number f, int c, int ex)
195{
196    boolean move;
197    pdfstructure *p = pdf->pstruct;
198    scaledpos pos = pdf->posstruct->pos;
199
200    if (!char_exists(f, c))
201        return;
202
203/*
204 p->need_tf : okay, set somewhere else
205 f != pdf->f_cur : font change
206 p->f_pdf != p->f_pdf_cur : font change
207 p->fs.m ~= p->fs_cur.m : move
208 is_pagemode(p) -> stream change
209 p->tm0_cur.m -> p->tm[0].m : also move
210*/
211
212    /* fix issue 857 */
213    /* /\* ensure to be within BT...ET *\/ */
214    /* if (is_pagemode(p)) { */
215    /*     pdf_goto_textmode(pdf); */
216    /*     p->need_tf = true; */
217    /* } */
218    /* /\* all font setup *\/ */
219    /* if (true || f != pdf->f_cur || p->need_tf) { */
220    /*     setup_fontparameters(pdf, f, ex); */
221    /*     if (p->need_tf || p->f_pdf != p->f_pdf_cur || p->fs.m != p->fs_cur.m) { */
222    /*         pdf_goto_textmode(pdf); */
223    /*         set_font(pdf); */
224    /*     } else if (p->tm0_cur.m != p->tm[0].m) { */
225    /*         /\* catch in-line HZ expand change due to efcode *\/ */
226    /*         p->need_tm = true; */
227    /*     } */
228    /* } */
229
230
231    /* LS/HH: We need to adapt the tm when a font changes. A change can be a change in
232       id (frontend) or pdf reference (backend, as we share font resources). At
233       such a change we also need to adapt to the slant and extend. Initially
234       we also need to take the exfactor of a glyph into account. When the font is
235       unchanged, we still need to check each glyph for a change in exfactor. We
236       store the current one on the state record so that we can minimize testing. */
237
238   /* is the p->need_tf test really needed ? */
239    if (p->need_tf || f != pdf->f_cur || p->f_pdf != p->f_pdf_cur || p->fs.m != p->fs_cur.m || is_pagemode(p)) {
240         pdf_goto_textmode(pdf);
241         setup_fontparameters(pdf, f, ex);
242         set_font(pdf);
243    } else if (p->tm0_cur.m != p->tm[0].m || p->cur_ex != ex) {
244         setup_fontparameters(pdf, f, ex);
245         p->need_tm = true;
246    }
247
248    /* all movements */
249    move = calc_pdfpos(p, pos); /* within text or chararray or char mode */
250    if (move || p->need_tm) {
251        if (p->need_tm || (p->wmode == WMODE_H
252                           && (p->pdf_bt_pos.v.m + p->tm[5].m) != p->pdf.v.m)
253            || (p->wmode == WMODE_V
254                && (p->pdf_bt_pos.h.m + p->tm[4].m) != p->pdf.h.m)
255            || abs(p->tj_delta.m) >= 1000000) {
256            pdf_goto_textmode(pdf);
257            set_textmatrix(pdf, pos);
258            begin_chararray(pdf);
259            move = calc_pdfpos(p, pos); /* for fine adjustment */
260        }
261        if (move) {
262            assert((p->wmode == WMODE_H
263                    && (p->pdf_bt_pos.v.m + p->tm[5].m) == p->pdf.v.m)
264                   || (p->wmode == WMODE_V
265                       && (p->pdf_bt_pos.h.m + p->tm[4].m) == p->pdf.h.m));
266            if (is_charmode(p))
267                end_charmode(pdf);
268            assert(p->tj_delta.m != 0);
269            print_pdffloat(pdf, p->tj_delta);
270            p->cw.m -= p->tj_delta.m * ten_pow[p->cw.e - p->tj_delta.e];
271        }
272    }
273    /* glyph output */
274    assert(is_chararraymode(p) || is_charmode(p));
275    if (is_chararraymode(p))
276        begin_charmode(pdf, f, p);
277    pdf_mark_char(f, c);
278    if (font_encodingbytes(f) == 2)
279        pdf_print_wide_char(pdf, char_index(f, c));
280    else
281        pdf_print_char(pdf, c);
282    p->cw.m += pdf_char_width(p, p->f_pdf, c);  /* aka |adv_char_width()| */
283}
284