3 This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5 Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6 the dvipdfmx project team.
8 Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
46 #include "pdfximage.h"
51 #include "pdflimits.h"
55 static int verbose = 0;
58 pdf_dev_set_verbose (void)
63 /* Not working yet... */
71 * Unit conversion, formatting and others.
74 #define TEX_ONE_HUNDRED_BP 6578176
77 long min_bp_val; /* Shortest resolvable distance in the output PDF. */
78 int precision; /* Number of decimal digits (in fractional part) kept. */
87 dev_unit_dviunit (void)
89 return (1.0/dev_unit.dvi2pts);
92 #define DEV_PRECISION_MAX 8
93 static unsigned long ten_pow[10] = {
94 1ul, 10ul, 100ul, 1000ul, 10000ul, 100000ul, 1000000ul, 10000000ul, 100000000ul, 1000000000ul
97 static double ten_pow_inv[10] = {
98 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001
101 #define bpt2spt(b) ( (spt_t) round( (b) / dev_unit.dvi2pts ) )
102 #define spt2bpt(s) ( (s) * dev_unit.dvi2pts )
103 #define dround_at(v,p) (ROUND( (v), ten_pow_inv[(p)] ))
106 p_itoa (long value, char *buf)
120 /* Generate at least one digit in reverse order */
122 p[ndigits++] = (value % 10) + '0';
124 } while (value != 0);
126 /* Reverse the digits */
130 for (i = 0; i < ndigits / 2 ; i++) {
132 p[i] = p[ndigits-i-1];
133 p[ndigits-i-1] = tmp;
138 return (sign ? ndigits + 1 : ndigits);
143 p_dtoa (double value, int prec, char *buf)
145 const long p[10] = { 1, 10, 100, 1000, 10000,
146 100000, 1000000, 10000000, 100000000, 1000000000 };
159 f = (long) ((value-i)*p[prec] + 0.5);
167 int m = p_itoa(i, c);
181 c[j] = (f % 10) + '0';
199 dev_sprint_bp (char *buf, spt_t value, spt_t *error)
203 int prec = dev_unit.precision;
205 value_in_bp = spt2bpt(value);
207 error_in_bp = value_in_bp - dround_at(value_in_bp, prec);
208 *error = bpt2spt(error_in_bp);
211 return p_dtoa(value_in_bp, prec, buf);
214 /* They are affected by precision (set at device initialization). */
216 pdf_sprint_matrix (char *buf, const pdf_tmatrix *M)
219 int prec2 = MIN(dev_unit.precision + 2, DEV_PRECISION_MAX);
220 int prec0 = MAX(dev_unit.precision, 2);
222 len = p_dtoa(M->a, prec2, buf);
224 len += p_dtoa(M->b, prec2, buf+len);
226 len += p_dtoa(M->c, prec2, buf+len);
228 len += p_dtoa(M->d, prec2, buf+len);
230 len += p_dtoa(M->e, prec0, buf+len);
232 len += p_dtoa(M->f, prec0, buf+len);
233 buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
239 pdf_sprint_rect (char *buf, const pdf_rect *rect)
243 len = p_dtoa(rect->llx, dev_unit.precision, buf);
245 len += p_dtoa(rect->lly, dev_unit.precision, buf+len);
247 len += p_dtoa(rect->urx, dev_unit.precision, buf+len);
249 len += p_dtoa(rect->ury, dev_unit.precision, buf+len);
250 buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
256 pdf_sprint_coord (char *buf, const pdf_coord *p)
260 len = p_dtoa(p->x, dev_unit.precision, buf);
262 len += p_dtoa(p->y, dev_unit.precision, buf+len);
263 buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
269 pdf_sprint_length (char *buf, double value)
273 len = p_dtoa(value, dev_unit.precision, buf);
274 buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
281 pdf_sprint_number (char *buf, double value)
285 len = p_dtoa(value, DEV_PRECISION_MAX, buf);
286 buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */
294 /* Text composition (direction) mode is ignored (always same
295 * as font's writing mode) if autorotate is unset (value zero).
300 * Ignore color migrated to here. This is device's capacity.
301 * colormode 0 for ignore colors
311 * Text handling routines.
315 * GRAPHICS_MODE Initial state (not within BT/ET block nor in string)
316 * TEXT_MODE Text section is started via BT operator but not
318 * STRING_MODE In string. A string or array of strings are currently
319 * in process. May started '[', '<' or '('.
321 #define GRAPHICS_MODE 1
323 #define STRING_MODE 3
325 static int motion_state = GRAPHICS_MODE;
327 #define FORMAT_BUF_SIZE 4096
328 static char format_buffer[FORMAT_BUF_SIZE];
331 * In PDF, vertical text positioning is always applied when current font
332 * is vertical font. While ASCII pTeX manages current writing direction
333 * and font's WMode separately.
335 * 000/101 WMODE_HH/VV h(v) font, h(v) direction.
336 * 001 WMODE_HV -90 deg. rotated
337 * 100 WMODE_VH +90 deg. rotated
338 * 011 WMODE_HD +90 deg. rotated
339 * 111 WMODE_VD 180 deg. rotated
341 * In MetaPost PostScript file processing (mp_mode = 1), only HH/VV mode
344 #define TEXT_WMODE_HH 0
345 #define TEXT_WMODE_HV 1
346 #define TEXT_WMODE_VH 4
347 #define TEXT_WMODE_VV 5
348 #define TEXT_WMODE_HD 3
349 #define TEXT_WMODE_VD 7
351 #define ANGLE_CHANGES(m1,m2) ((abs((m1)-(m2)) % 5) == 0 ? 0 : 1)
352 #define ROTATE_TEXT(m) ((m) != TEXT_WMODE_HH && (m) != TEXT_WMODE_VV)
357 * This is index within dev_fonts.
361 /* Dvipdfmx does compression of text by doing text positioning
362 * in relative motion and uses string array [(foo) -250 (bar)]
363 * with kerning (negative kern is used for white space as suited
364 * for TeX). This is offset within current string.
368 /* This is reference point of strings.
369 * It may include error correction induced by rounding.
374 /* Using text raise and leading is highly recommended for
375 * text extraction to work properly. But not implemented yet.
376 * We can't do consice output for \TeX without this.
378 spt_t raise; /* unused */
379 spt_t leading; /* unused */
381 /* This is not always text matrix but rather font matrix.
382 * We do not use horizontal scaling in PDF text state parameter
383 * since they always apply scaling in fixed direction regardless
389 int rotate; /* TEXT_WMODE_XX */
392 /* Fake bold parameter:
393 * If bold_param is positive, use text rendering mode
394 * fill-then-stroke with stroking line width specified
399 /* Text composition (direction) mode. */
404 /* Flag indicating text matrix to be forcibly reset.
405 * Enabled if synthetic font features (slant, extend, etc)
406 * are used for current font or when text rotation mode
411 /* This information is duplicated from dev[font_id].format.
412 * Set to 1 if font is composite (Type0) font.
418 0, 0, /* ref_x, ref_y */
419 0, 0, /* raise, leading */
422 0.0, /* Experimental boldness param */
431 #define PDF_FONTTYPE_SIMPLE 1
432 #define PDF_FONTTYPE_BITMAP 2
433 #define PDF_FONTTYPE_COMPOSITE 3
436 /* Needs to be big enough to hold name "Fxxx"
437 * where xxx is number of largest font
439 char short_name[7]; /* Resource name */
440 int used_on_this_page;
442 char *tex_name; /* String identifier of this font */
443 spt_t sptsize; /* Point size */
445 /* Returned values from font/encoding layer:
447 * The font_id and enc_id is font and encoding (CMap) identifier
448 * used in pdf_font or encoding/cmap layer.
449 * The PDF object "resource" is an indirect reference object
450 * pointing font resource of this font. The used_chars is somewhat
451 * misleading, this is actually used_glyphs in CIDFont for Type0
452 * and is 65536/8 bytes binary data with each bits representing
453 * whether the glyph is in-use or not. It is 256 char array for
463 * simple, composite or bitmap.
468 * Non-zero for vertical. Duplicated from CMap.
474 * We use text matrix for creating extended or slanted font,
475 * but not with font's FontMatrix since TrueType and Type0
476 * font don't support them.
480 double bold; /* Boldness prameter */
483 int mapc; /* Nasty workaround for Omega */
485 /* There are no font metric format supporting four-bytes
486 * charcter code. So we should provide an option to specify
487 * UCS group and plane.
494 static struct dev_font *dev_fonts = NULL;
496 static int num_dev_fonts = 0;
497 static int max_dev_fonts = 0;
498 static int num_phys_fonts = 0;
500 #define CURRENTFONT() ((text_state.font_id < 0) ? NULL : &(dev_fonts[text_state.font_id]))
501 #define GET_FONT(n) (&(dev_fonts[(n)]))
505 dev_set_text_matrix (spt_t xpos, spt_t ypos, double slant, double extend, int rotate)
510 /* slant is negated for vertical font so that right-side
511 * is always lower. */
515 tm.a = slant ; tm.b = 1.0;
516 tm.c = -extend; tm.d = 0.0 ;
519 /* Horizontal font */
520 tm.a = 0.0; tm.b = -extend;
521 tm.c = 1.0; tm.d = -slant ;
524 /* Horizontal font */
525 tm.a = extend; tm.b = 0.0;
526 tm.c = slant ; tm.d = 1.0;
530 tm.a = 1.0; tm.b = -slant;
531 tm.c = 0.0; tm.d = extend;
534 /* Horizontal font */
535 tm.a = 0.0; tm.b = extend;
536 tm.c = -1.0; tm.d = slant ;
540 tm.a = -1.0; tm.b = slant;
541 tm.c = 0.0; tm.d = -extend;
544 tm.e = xpos * dev_unit.dvi2pts;
545 tm.f = ypos * dev_unit.dvi2pts;
547 format_buffer[len++] = ' ';
548 len += pdf_sprint_matrix(format_buffer+len, &tm);
549 format_buffer[len++] = ' ';
550 format_buffer[len++] = 'T';
551 format_buffer[len++] = 'm';
553 pdf_doc_add_page_content(format_buffer, len); /* op: Tm */
555 text_state.ref_x = xpos;
556 text_state.ref_y = ypos;
557 text_state.matrix.slant = slant;
558 text_state.matrix.extend = extend;
559 text_state.matrix.rotate = rotate;
563 * reset_text_state() outputs a BT and does any necessary coordinate
564 * transformations to get ready to ship out text.
568 reset_text_state (void)
571 * We need to reset the line matrix to handle slanted fonts.
573 pdf_doc_add_page_content(" BT", 3); /* op: BT */
575 * text_state.matrix is identity at top of page.
576 * This sometimes write unnecessary "Tm"s when transition from
577 * GRAPHICS_MODE to TEXT_MODE occurs.
579 if (text_state.force_reset ||
580 text_state.matrix.slant != 0.0 ||
581 text_state.matrix.extend != 1.0 ||
582 ROTATE_TEXT(text_state.matrix.rotate)) {
583 dev_set_text_matrix(0, 0,
584 text_state.matrix.slant,
585 text_state.matrix.extend,
586 text_state.matrix.rotate);
588 text_state.ref_x = 0;
589 text_state.ref_y = 0;
590 text_state.offset = 0;
591 text_state.force_reset = 0;
597 switch (motion_state) {
601 pdf_doc_add_page_content(text_state.is_mb ? ">]TJ" : ")]TJ", 4); /* op: TJ */
607 motion_state = TEXT_MODE;
608 text_state.offset = 0;
614 switch (motion_state) {
618 pdf_doc_add_page_content(text_state.is_mb ? ">]TJ" : ")]TJ", 4); /* op: TJ */
621 pdf_doc_add_page_content(" ET", 3); /* op: ET */
622 text_state.force_reset = 0;
623 text_state.font_id = -1;
626 motion_state = GRAPHICS_MODE;
630 start_string (spt_t xpos, spt_t ypos, double slant, double extend, int rotate)
632 spt_t delx, dely, error_delx, error_dely;
633 spt_t desired_delx, desired_dely;
636 delx = xpos - text_state.ref_x;
637 dely = ypos - text_state.ref_y;
639 * Precompensating for line transformation matrix.
641 * Line transformation matrix L for horizontal font in horizontal
642 * mode and it's inverse I is
645 * L_hh = | | , I_hh = | |
648 * For vertical font in vertical mode,
651 * L_vv = | | , I_vv = | |
654 * For vertical font in horizontal mode,
657 * L_vh = | | = L_vv x | |
664 * For horizontal font in vertical mode,
667 * L_hv = | | = L_hh x | |
677 /* Vertical font in horizontal mode: rot = +90
679 * d_user = d x I_vh = d x | |
683 desired_dely = (spt_t) (-(delx - dely*slant)/extend);
685 /* error_del is in device space
688 * e = e_user x | | = (-e_user_y, e_user_x)
691 * We must care about rotation here but not extend/slant...
692 * The extend and slant actually is font matrix.
694 format_buffer[len++] = ' ';
695 len += dev_sprint_bp(format_buffer+len, desired_delx, &error_dely);
696 format_buffer[len++] = ' ';
697 len += dev_sprint_bp(format_buffer+len, desired_dely, &error_delx);
698 error_delx = -error_delx;
701 /* Horizontal font in vertical mode: rot = -90
704 * d_user = d x I_hv = d x | |
707 desired_delx = (spt_t)(-(dely + delx*slant)/extend);
711 * e = (e_user_y, -e_user_x)
713 format_buffer[len++] = ' ';
714 len += dev_sprint_bp(format_buffer+len, desired_delx, &error_dely);
715 format_buffer[len++] = ' ';
716 len += dev_sprint_bp(format_buffer+len, desired_dely, &error_delx);
717 error_dely = -error_dely;
720 /* Horizontal font in horizontal mode:
722 * d_user = d x I_hh = d x | |
725 desired_delx = (spt_t)((delx - dely*slant)/extend);
728 format_buffer[len++] = ' ';
729 len += dev_sprint_bp(format_buffer+len, desired_delx, &error_delx);
730 format_buffer[len++] = ' ';
731 len += dev_sprint_bp(format_buffer+len, desired_dely, &error_dely);
734 /* Vertical font in vertical mode:
736 * d_user = d x I_vv = d x | |
740 desired_dely = (spt_t)((dely + delx*slant)/extend);
742 format_buffer[len++] = ' ';
743 len += dev_sprint_bp(format_buffer+len, desired_delx, &error_delx);
744 format_buffer[len++] = ' ';
745 len += dev_sprint_bp(format_buffer+len, desired_dely, &error_dely);
748 /* Horizontal font in down-to-up mode: rot = +90
751 * d_user = d x -I_hv = d x | |
754 desired_delx = -(spt_t)(-(dely + delx*slant)/extend);
755 desired_dely = -delx;
757 format_buffer[len++] = ' ';
758 len += dev_sprint_bp(format_buffer+len, desired_delx, &error_dely);
759 format_buffer[len++] = ' ';
760 len += dev_sprint_bp(format_buffer+len, desired_dely, &error_delx);
761 error_delx = -error_delx;
762 error_dely = -error_dely;
765 /* Vertical font in down-to-up mode: rot = 180
767 * d_user = d x -I_vv = d x | |
770 desired_delx = -delx;
771 desired_dely = -(spt_t)((dely + delx*slant)/extend);
773 format_buffer[len++] = ' ';
774 len += dev_sprint_bp(format_buffer+len, desired_delx, &error_delx);
775 format_buffer[len++] = ' ';
776 len += dev_sprint_bp(format_buffer+len, desired_dely, &error_dely);
777 error_delx = -error_delx;
778 error_dely = -error_dely;
781 pdf_doc_add_page_content(format_buffer, len); /* op: */
783 * dvipdfm wrongly using "TD" in place of "Td".
784 * The TD operator set leading, but we are not using T* etc.
786 pdf_doc_add_page_content(text_state.is_mb ? " Td[<" : " Td[(", 5); /* op: Td */
788 /* Error correction */
789 text_state.ref_x = xpos - error_delx;
790 text_state.ref_y = ypos - error_dely;
792 text_state.offset = 0;
796 string_mode (spt_t xpos, spt_t ypos, double slant, double extend, int rotate)
798 switch (motion_state) {
805 if (text_state.force_reset) {
806 dev_set_text_matrix(xpos, ypos, slant, extend, rotate);
807 pdf_doc_add_page_content(text_state.is_mb ? "[<" : "[(", 2); /* op: */
808 text_state.force_reset = 0;
810 start_string(xpos, ypos, slant, extend, rotate);
814 motion_state = STRING_MODE;
818 * The purpose of the following routine is to force a Tf only
819 * when it's actually necessary. This became a problem when the
820 * VF code was added. The VF spec says to instantiate the
821 * first font contained in the VF file before drawing a virtual
822 * character. However, that font may not be used for
823 * many characters (e.g. small caps fonts). For this reason,
824 * dev_select_font() should not force a "physical" font selection.
825 * This routine prevents a PDF Tf font selection until there's
826 * really a character in that font.
830 dev_set_font (int font_id)
832 struct dev_font *font;
836 int vert_dir, vert_font;
838 /* text_mode() must come before text_state.is_mb is changed. */
841 font = GET_FONT(font_id);
842 ASSERT(font); /* Caller should check font_id. */
844 text_state.is_mb = (font->format == PDF_FONTTYPE_COMPOSITE) ? 1 : 0;
846 vert_font = font->wmode ? 1 : 0;
847 if (dev_param.autorotate) {
848 vert_dir = text_state.dir_mode;
850 vert_dir = vert_font;
852 text_rotate = (vert_font << 2)|vert_dir;
854 if (font->slant != text_state.matrix.slant ||
855 font->extend != text_state.matrix.extend ||
856 ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) {
857 text_state.force_reset = 1;
859 text_state.matrix.slant = font->slant;
860 text_state.matrix.extend = font->extend;
861 text_state.matrix.rotate = text_rotate;
863 if (!font->resource) {
864 font->resource = pdf_get_font_reference(font->font_id);
865 font->used_chars = pdf_get_font_usedchars(font->font_id);
868 if (!font->used_on_this_page) {
869 pdf_doc_add_page_resource("Font",
871 pdf_link_obj(font->resource));
872 font->used_on_this_page = 1;
875 font_scale = (double) font->sptsize * dev_unit.dvi2pts;
876 len = sprintf(format_buffer, " /%s", font->short_name); /* space not necessary. */
877 format_buffer[len++] = ' ';
878 len += p_dtoa(font_scale, MIN(dev_unit.precision+1, DEV_PRECISION_MAX), format_buffer+len);
879 format_buffer[len++] = ' ';
880 format_buffer[len++] = 'T';
881 format_buffer[len++] = 'f';
882 pdf_doc_add_page_content(format_buffer, len); /* op: Tf */
884 if (font->bold > 0.0 || font->bold != text_state.bold_param) {
885 if (font->bold <= 0.0)
886 len = sprintf(format_buffer, " 0 Tr");
888 len = sprintf(format_buffer, " 2 Tr %.2f w", font->bold); /* _FIXME_ */
889 pdf_doc_add_page_content(format_buffer, len); /* op: Tr w */
891 text_state.bold_param = font->bold;
893 text_state.font_id = font_id;
899 /* Access text state parameters.
903 pdf_dev_currentfont (void)
905 return text_state.font_id;
909 pdf_dev_get_font_ptsize (int font_id)
911 struct dev_font *font;
913 font = GET_FONT(font_id);
915 return font->sptsize * dev_unit.dvi2pts;
923 pdf_dev_get_font_wmode (int font_id)
925 struct dev_font *font;
927 font = GET_FONT(font_id);
935 static unsigned char sbuf0[FORMAT_BUF_SIZE];
936 static unsigned char sbuf1[FORMAT_BUF_SIZE];
939 handle_multibyte_string (struct dev_font *font,
940 const unsigned char **str_ptr, int *str_len, int ctype)
942 const unsigned char *p;
949 if (font->is_unicode) { /* UCS-4 */
951 if (length * 4 >= FORMAT_BUF_SIZE) {
952 WARN("Too long string...");
955 for (i = 0; i < length; i++) {
956 sbuf1[i*4 ] = font->ucs_group;
957 sbuf1[i*4+1] = font->ucs_plane;
962 } else if (ctype == 2) {
965 if (length * 2 >= FORMAT_BUF_SIZE) {
966 WARN("Too long string...");
969 for (i = 0; i < length; i += 2, len += 4) {
970 sbuf1[len ] = font->ucs_group;
971 if ((p[i] & 0xf8) == 0xd8) {
973 /* Check for valid surrogate pair. */
974 if ((p[i] & 0xfc) != 0xd8 || i + 2 >= length || (p[i+2] & 0xfc) != 0xdc) {
975 WARN("Invalid surrogate p[%d]=%02X...", i, p[i]);
978 c = (((p[i] & 0x03) << 10) | (p[i+1] << 2) | (p[i+2] & 0x03)) + 0x100;
979 sbuf1[len+1] = (c >> 8) & 0xff;
980 sbuf1[len+2] = c & 0xff;
983 sbuf1[len+1] = font->ucs_plane;
986 sbuf1[len+3] = p[i+1];
991 } else if (ctype == 1 && font->mapc >= 0) {
992 /* Omega workaround...
993 * Translate single-byte chars to double byte code space.
995 if (length * 2 >= FORMAT_BUF_SIZE) {
996 WARN("Too long string...");
999 for (i = 0; i < length; i++) {
1000 sbuf1[i*2 ] = (font->mapc & 0xff);
1001 sbuf1[i*2+1] = p[i];
1008 * Font is double-byte font. Output is assumed to be 16-bit fixed length
1010 * TODO: A character decomposed to multiple characters.
1012 if (font->enc_id >= 0) {
1013 const unsigned char *inbuf;
1014 unsigned char *outbuf;
1015 long inbytesleft, outbytesleft;
1018 cmap = CMap_cache_get(font->enc_id);
1021 inbytesleft = length;
1022 outbytesleft = FORMAT_BUF_SIZE;
1025 &inbuf, &inbytesleft, &outbuf, &outbytesleft);
1026 if (inbytesleft != 0) {
1027 WARN("CMap conversion failed. (%d bytes remains)", inbytesleft);
1030 length = FORMAT_BUF_SIZE - outbytesleft;
1040 static pdf_coord *dev_coords = NULL;
1041 static int num_dev_coords = 0;
1042 static int max_dev_coords = 0;
1044 void pdf_dev_get_coord(double *xpos, double *ypos)
1046 if (num_dev_coords > 0) {
1047 *xpos = dev_coords[num_dev_coords-1].x;
1048 *ypos = dev_coords[num_dev_coords-1].y;
1050 *xpos = *ypos = 0.0;
1054 void pdf_dev_push_coord(double xpos, double ypos)
1056 if (num_dev_coords >= max_dev_coords) {
1057 max_dev_coords += 4;
1058 dev_coords = RENEW(dev_coords, max_dev_coords, pdf_coord);
1060 dev_coords[num_dev_coords].x = xpos;
1061 dev_coords[num_dev_coords].y = ypos;
1065 void pdf_dev_pop_coord(void)
1067 if (num_dev_coords > 0) num_dev_coords--;
1072 * 0 byte-width of char can be variable and input string
1073 * is properly encoded.
1074 * n Single character cosumes n bytes in input string.
1078 * selectfont(font_name, point_size) and show_string(pos, string)
1081 pdf_dev_set_string (spt_t xpos, spt_t ypos,
1082 const void *instr_ptr, int instr_len,
1084 int font_id, int ctype)
1086 struct dev_font *font;
1087 const unsigned char *str_ptr; /* Pointer to the reencoded string. */
1088 int length, i, len = 0;
1089 spt_t kern, delh, delv;
1093 if (font_id < 0 || font_id >= num_dev_fonts) {
1094 ERROR("Invalid font: %d (%d)", font_id, num_dev_fonts);
1097 if (font_id != text_state.font_id) {
1098 dev_set_font(font_id);
1101 font = CURRENTFONT();
1103 ERROR("Currentfont not set.");
1107 text_xorigin = text_state.ref_x;
1108 text_yorigin = text_state.ref_y;
1110 str_ptr = instr_ptr;
1113 if (font->format == PDF_FONTTYPE_COMPOSITE) {
1114 if (handle_multibyte_string(font, &str_ptr, &length, ctype) < 0) {
1115 ERROR("Error in converting input string...");
1118 if (font->used_chars != NULL) {
1119 for (i = 0; i < length; i += 2)
1120 add_to_used_chars2(font->used_chars,
1121 (unsigned short) (str_ptr[i] << 8)|str_ptr[i+1]);
1124 if (font->used_chars != NULL) {
1125 for (i = 0; i < length; i++)
1126 font->used_chars[str_ptr[i]] = 1;
1130 if (num_dev_coords > 0) {
1131 xpos -= bpt2spt(dev_coords[num_dev_coords-1].x);
1132 ypos -= bpt2spt(dev_coords[num_dev_coords-1].y);
1136 * Kern is in units of character units, i.e., 1000 = 1 em.
1138 * Positive kern means kerning (reduce excess white space).
1140 * The following formula is of the form a*x/b where a, x, and b are signed long
1141 * integers. Since in integer arithmetic (a*x) could overflow and a*(x/b) would
1142 * not be accurate, we use floating point arithmetic rather than trying to do
1143 * this all with integer arithmetic.
1145 * 1000.0 / (font->extend * font->sptsize) is caluculated each times...
1146 * Is accuracy really a matter? Character widths are always rounded to integer
1147 * (in 1000 units per em) but dvipdfmx does not take into account of this...
1150 if (text_state.dir_mode==0) {
1152 delh = text_xorigin + text_state.offset - xpos;
1153 delv = ypos - text_yorigin;
1154 } else if (text_state.dir_mode==1) {
1156 delh = ypos - text_yorigin + text_state.offset;
1157 delv = xpos - text_xorigin;
1160 delh = ypos + text_yorigin + text_state.offset;
1161 delv = xpos + text_xorigin;
1164 /* White-space more than 3em is not considered as a part of single text.
1165 * So we will break string mode in that case.
1166 * Dvipdfmx spend most of time processing strings with kern = 0 (but far
1167 * more times in font handling).
1168 * You may want to use pre-calculated value for WORD_SPACE_MAX.
1169 * More text compression may be possible by replacing kern with space char
1170 * when -kern is equal to space char width.
1172 #define WORD_SPACE_MAX(f) (spt_t) (3.0 * (f)->extend * (f)->sptsize)
1174 if (text_state.force_reset ||
1175 labs(delv) > dev_unit.min_bp_val ||
1176 labs(delh) > WORD_SPACE_MAX(font)) {
1180 kern = (spt_t) (1000.0 / font->extend * delh / font->sptsize);
1183 /* Inaccucary introduced by rounding of character width appears within
1184 * single text block. There are point_size/1000 rounding error per character.
1185 * If you really care about accuracy, you should compensate this here too.
1187 if (motion_state != STRING_MODE)
1188 string_mode(xpos, ypos,
1189 font->slant, font->extend, text_state.matrix.rotate);
1190 else if (kern != 0) {
1192 * Same issues as earlier. Use floating point for simplicity.
1193 * This routine needs to be fast, so we don't call sprintf() or strcpy().
1195 text_state.offset -=
1196 (spt_t) (kern * font->extend * (font->sptsize / 1000.0));
1197 format_buffer[len++] = text_state.is_mb ? '>' : ')';
1199 len += p_itoa(-kern, format_buffer + len);
1201 len += p_itoa( kern, format_buffer + len);
1203 format_buffer[len++] = text_state.is_mb ? '<' : '(';
1204 pdf_doc_add_page_content(format_buffer, len); /* op: */
1208 if (text_state.is_mb) {
1209 if (FORMAT_BUF_SIZE - len < 2 * length)
1210 ERROR("Buffer overflow...");
1211 for (i = 0; i < length; i++) {
1214 first = (str_ptr[i] >> 4) & 0x0f;
1215 second = str_ptr[i] & 0x0f;
1216 format_buffer[len++] = ((first >= 10) ? first + 'W' : first + '0');
1217 format_buffer[len++] = ((second >= 10) ? second + 'W' : second + '0');
1220 len += pdfobj_escape_str(format_buffer + len,
1221 FORMAT_BUF_SIZE - len, str_ptr, length);
1223 /* I think if you really care about speed, you should avoid memcopy here. */
1224 pdf_doc_add_page_content(format_buffer, len); /* op: */
1226 text_state.offset += width;
1230 pdf_init_device (double dvi2pts, int precision, int black_and_white)
1232 if (precision < 0 ||
1233 precision > DEV_PRECISION_MAX)
1234 WARN("Number of decimal digits out of range [0-%d].",
1237 if (precision < 0) {
1238 dev_unit.precision = 0;
1239 } else if (precision > DEV_PRECISION_MAX) {
1240 dev_unit.precision = DEV_PRECISION_MAX;
1242 dev_unit.precision = precision;
1244 dev_unit.dvi2pts = dvi2pts;
1245 dev_unit.min_bp_val = (long) ROUND(1.0/(ten_pow[dev_unit.precision]*dvi2pts), 1);
1246 if (dev_unit.min_bp_val < 0)
1247 dev_unit.min_bp_val = -dev_unit.min_bp_val;
1249 dev_param.colormode = (black_and_white ? 0 : 1);
1252 pdf_color_clear_stack();
1253 pdf_dev_init_gstates();
1255 num_dev_fonts = max_dev_fonts = 0;
1257 num_dev_coords = max_dev_coords = 0;
1262 pdf_close_device (void)
1267 for (i = 0; i < num_dev_fonts; i++) {
1268 if (dev_fonts[i].tex_name)
1269 RELEASE(dev_fonts[i].tex_name);
1270 if (dev_fonts[i].resource)
1271 pdf_release_obj(dev_fonts[i].resource);
1272 dev_fonts[i].tex_name = NULL;
1273 dev_fonts[i].resource = NULL;
1277 if (dev_coords) RELEASE(dev_coords);
1278 pdf_dev_clear_gstates();
1282 * BOP, EOP, and FONT section.
1283 * BOP and EOP manipulate some of the same data structures
1284 * as the font stuff.
1287 pdf_dev_reset_fonts (void)
1291 for (i = 0; i < num_dev_fonts; i++) {
1292 dev_fonts[i].used_on_this_page = 0;
1295 text_state.font_id = -1;
1297 text_state.matrix.slant = 0.0;
1298 text_state.matrix.extend = 1.0;
1299 text_state.matrix.rotate = TEXT_WMODE_HH;
1301 text_state.bold_param = 0.0;
1303 text_state.is_mb = 0;
1309 pdf_dev_set_origin (double phys_x, double phys_y)
1313 pdf_dev_currentmatrix(&M0);
1314 pdf_dev_currentmatrix(&M1);
1315 pdf_invertmatrix(&M1);
1316 M0.e = phys_x; M0.f = phys_y;
1317 pdf_concatmatrix(&M1, &M0);
1319 pdf_dev_concat(&M1);
1324 pdf_dev_bop (const pdf_tmatrix *M)
1328 text_state.force_reset = 0;
1333 pdf_dev_reset_fonts();
1334 pdf_dev_reset_color(0);
1344 depth = pdf_dev_current_depth();
1346 WARN("Unbalenced q/Q nesting...: %d", depth);
1347 pdf_dev_grestore_to(0);
1354 print_fontmap (const char *font_name, fontmap_rec *mrec)
1361 MESG("fontmap: %s -> %s", font_name, mrec->font_name);
1363 MESG("(%s)", mrec->enc_name);
1364 if (mrec->opt.extend != 1.0)
1365 MESG("[extend:%g]", mrec->opt.extend);
1366 if (mrec->opt.slant != 0.0)
1367 MESG("[slant:%g]", mrec->opt.slant);
1368 if (mrec->opt.bold != 0.0)
1369 MESG("[bold:%g]", mrec->opt.bold);
1370 if (mrec->opt.flags & FONTMAP_OPT_NOEMBED)
1372 if (mrec->opt.mapc >= 0)
1373 MESG("[map:<%02x>]", mrec->opt.mapc);
1374 if (mrec->opt.charcoll)
1375 MESG("[csi:%s]", mrec->opt.charcoll);
1376 if (mrec->opt.index)
1377 MESG("[index:%d]", mrec->opt.index);
1379 switch (mrec->opt.style) {
1380 case FONTMAP_STYLE_BOLD:
1381 MESG("[style:bold]");
1383 case FONTMAP_STYLE_ITALIC:
1384 MESG("[style:italic]");
1386 case FONTMAP_STYLE_BOLDITALIC:
1387 MESG("[style:bolditalic]");
1395 * Font is identified with font_name and point_size as in DVI here.
1396 * This may assign different resource name for same font at different
1397 * point size even for scalable fonts.
1400 pdf_dev_locate_font (const char *font_name, spt_t ptsize)
1404 struct dev_font *font;
1410 ERROR("pdf_dev_locate_font() called with the zero ptsize.");
1414 for (i = 0; i < num_dev_fonts; i++) {
1415 if (!strcmp(font_name, dev_fonts[i].tex_name) && ptsize == dev_fonts[i].sptsize) {
1421 * Make sure we have room for a new one, even though we may not
1422 * actually create one.
1424 if (num_dev_fonts >= max_dev_fonts) {
1425 max_dev_fonts += 16;
1426 dev_fonts = RENEW(dev_fonts, max_dev_fonts, struct dev_font);
1429 font = &dev_fonts[num_dev_fonts];
1432 mrec = pdf_lookup_fontmap_record(font_name);
1435 print_fontmap(font_name, mrec);
1437 font->font_id = pdf_font_findresource(font_name, ptsize * dev_unit.dvi2pts, mrec);
1438 if (font->font_id < 0)
1441 /* We found device font here. */
1442 font->short_name[0] = 'F';
1443 p_itoa(num_phys_fonts + 1, &font->short_name[1]); /* NULL terminated here */
1446 font->used_on_this_page = 0;
1448 font->tex_name = NEW(strlen(font_name) + 1, char);
1449 strcpy(font->tex_name, font_name);
1450 font->sptsize = ptsize;
1452 switch (pdf_get_font_subtype(font->font_id)) {
1453 case PDF_FONT_FONTTYPE_TYPE3:
1454 font->format = PDF_FONTTYPE_BITMAP;
1456 case PDF_FONT_FONTTYPE_TYPE0:
1457 font->format = PDF_FONTTYPE_COMPOSITE;
1460 font->format = PDF_FONTTYPE_SIMPLE;
1464 font->wmode = pdf_get_font_wmode (font->font_id);
1465 font->enc_id = pdf_get_font_encoding(font->font_id);
1467 font->resource = NULL; /* Don't ref obj until font is actually used. */
1468 font->used_chars = NULL;
1474 font->is_unicode = 0;
1475 font->ucs_group = 0;
1476 font->ucs_plane = 0;
1479 font->extend = mrec->opt.extend;
1480 font->slant = mrec->opt.slant;
1481 font->bold = mrec->opt.bold;
1482 if (mrec->opt.mapc >= 0)
1483 font->mapc = (mrec->opt.mapc >> 8) & 0xff;
1487 if (mrec->enc_name &&
1488 !strcmp(mrec->enc_name, "unicode")) {
1489 font->is_unicode = 1;
1490 if (mrec->opt.mapc >= 0) {
1491 font->ucs_group = (mrec->opt.mapc >> 24) & 0xff;
1492 font->ucs_plane = (mrec->opt.mapc >> 16) & 0xff;
1494 font->ucs_group = 0;
1495 font->ucs_plane = 0;
1498 font->is_unicode = 0;
1502 return num_dev_fonts++;
1506 /* This does not remember current stroking width. */
1508 dev_sprint_line (char *buf, spt_t width,
1509 spt_t p0_x, spt_t p0_y, spt_t p1_x, spt_t p1_y)
1514 w = width * dev_unit.dvi2pts;
1516 len += p_dtoa(w, MIN(dev_unit.precision+1, DEV_PRECISION_MAX), buf+len);
1520 len += dev_sprint_bp(buf+len, p0_x, NULL);
1522 len += dev_sprint_bp(buf+len, p0_y, NULL);
1526 len += dev_sprint_bp(buf+len, p1_x, NULL);
1528 len += dev_sprint_bp(buf+len, p1_y, NULL);
1537 /* Not optimized. */
1538 #define PDF_LINE_THICKNESS_MAX 5.0
1540 pdf_dev_set_rule (spt_t xpos, spt_t ypos, spt_t width, spt_t height)
1545 if (num_dev_coords > 0) {
1546 xpos -= bpt2spt(dev_coords[num_dev_coords-1].x);
1547 ypos -= bpt2spt(dev_coords[num_dev_coords-1].y);
1552 format_buffer[len++] = ' ';
1553 format_buffer[len++] = 'q';
1554 format_buffer[len++] = ' ';
1555 /* Don't use too thick line. */
1556 width_in_bp = ((width < height) ? width : height) * dev_unit.dvi2pts;
1557 if (width_in_bp < 0.0 || /* Shouldn't happen */
1558 width_in_bp > PDF_LINE_THICKNESS_MAX) {
1561 rect.llx = dev_unit.dvi2pts * xpos;
1562 rect.lly = dev_unit.dvi2pts * ypos;
1563 rect.urx = dev_unit.dvi2pts * width;
1564 rect.ury = dev_unit.dvi2pts * height;
1565 len += pdf_sprint_rect(format_buffer+len, &rect);
1566 format_buffer[len++] = ' ';
1567 format_buffer[len++] = 'r';
1568 format_buffer[len++] = 'e';
1569 format_buffer[len++] = ' ';
1570 format_buffer[len++] = 'f';
1572 if (width > height) {
1574 * A line width of 0 denotes the thinnest line that can be rendered at
1575 * device resolution. See, PDF Reference Manual 4th ed., sec. 4.3.2,
1576 * "Details of Graphics State Parameters", p. 185.
1578 if (height < dev_unit.min_bp_val) {
1579 WARN("Too thin line: height=%ld (%g bp)", height, width_in_bp);
1580 WARN("Please consider using \"-d\" option.");
1582 len += dev_sprint_line(format_buffer+len,
1589 if (width < dev_unit.min_bp_val) {
1590 WARN("Too thin line: width=%ld (%g bp)", width, width_in_bp);
1591 WARN("Please consider using \"-d\" option.");
1593 len += dev_sprint_line(format_buffer+len,
1601 format_buffer[len++] = ' ';
1602 format_buffer[len++] = 'Q';
1603 pdf_doc_add_page_content(format_buffer, len); /* op: q re f Q */
1606 /* Rectangle in device space coordinate. */
1608 pdf_dev_set_rect (pdf_rect *rect,
1609 spt_t x_user, spt_t y_user,
1610 spt_t width, spt_t height, spt_t depth)
1612 double dev_x, dev_y;
1613 pdf_coord p0, p1, p2, p3;
1614 double min_x, min_y, max_x, max_y;
1616 dev_x = x_user * dev_unit.dvi2pts;
1617 dev_y = y_user * dev_unit.dvi2pts;
1618 if (text_state.dir_mode) {
1619 p0.x = dev_x - dev_unit.dvi2pts * depth;
1620 p0.y = dev_y - dev_unit.dvi2pts * width;
1621 p1.x = dev_x + dev_unit.dvi2pts * height;
1629 p0.y = dev_y - dev_unit.dvi2pts * depth;
1630 p1.x = dev_x + dev_unit.dvi2pts * width;
1633 p2.y = dev_y + dev_unit.dvi2pts * height;
1638 pdf_dev_transform(&p0, NULL); /* currentmatrix */
1639 pdf_dev_transform(&p1, NULL);
1640 pdf_dev_transform(&p2, NULL);
1641 pdf_dev_transform(&p3, NULL);
1643 min_x = MIN(p0.x , p1.x);
1644 min_x = MIN(min_x, p2.x);
1645 min_x = MIN(min_x, p3.x);
1647 max_x = MAX(p0.x , p1.x);
1648 max_x = MAX(max_x, p2.x);
1649 max_x = MAX(max_x, p3.x);
1651 min_y = MIN(p0.y , p1.y);
1652 min_y = MIN(min_y, p2.y);
1653 min_y = MIN(min_y, p3.y);
1655 max_y = MAX(p0.y , p1.y);
1656 max_y = MAX(max_y, p2.y);
1657 max_y = MAX(max_y, p3.y);
1668 pdf_dev_get_dirmode (void)
1670 return text_state.dir_mode;
1674 pdf_dev_set_dirmode (int text_dir)
1676 struct dev_font *font;
1678 int vert_dir, vert_font;
1680 font = CURRENTFONT();
1682 vert_font = (font && font->wmode) ? 1 : 0;
1683 if (dev_param.autorotate) {
1684 vert_dir = text_dir;
1686 vert_dir = vert_font;
1688 text_rotate = (vert_font << 2)|vert_dir;
1691 ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) {
1692 text_state.force_reset = 1;
1695 text_state.matrix.rotate = text_rotate;
1696 text_state.dir_mode = text_dir;
1700 dev_set_param_autorotate (int auto_rotate)
1702 struct dev_font *font;
1703 int text_rotate, vert_font, vert_dir;
1705 font = CURRENTFONT();
1707 vert_font = (font && font->wmode) ? 1 : 0;
1709 vert_dir = text_state.dir_mode;
1711 vert_dir = vert_font;
1713 text_rotate = (vert_font << 2)|vert_dir;
1715 if (ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) {
1716 text_state.force_reset = 1;
1718 text_state.matrix.rotate = text_rotate;
1719 dev_param.autorotate = auto_rotate;
1723 pdf_dev_get_param (int param_type)
1727 switch (param_type) {
1728 case PDF_DEV_PARAM_AUTOROTATE:
1729 value = dev_param.autorotate;
1731 case PDF_DEV_PARAM_COLORMODE:
1732 value = dev_param.colormode;
1735 ERROR("Unknown device parameter: %d", param_type);
1742 pdf_dev_set_param (int param_type, int value)
1744 switch (param_type) {
1745 case PDF_DEV_PARAM_AUTOROTATE:
1746 dev_set_param_autorotate(value);
1748 case PDF_DEV_PARAM_COLORMODE:
1749 dev_param.colormode = value; /* 0 for B&W */
1752 ERROR("Unknown device parameter: %d", param_type);
1760 pdf_dev_put_image (int id,
1770 if (num_dev_coords > 0) {
1771 ref_x -= dev_coords[num_dev_coords-1].x;
1772 ref_y -= dev_coords[num_dev_coords-1].y;
1775 pdf_copymatrix(&M, &(p->matrix));
1776 M.e += ref_x; M.f += ref_y;
1777 /* Just rotate by -90, but not tested yet. Any problem if M has scaling? */
1778 if (dev_param.autorotate &&
1779 text_state.dir_mode) {
1781 tmp = -M.a; M.a = M.b; M.b = tmp;
1782 tmp = -M.c; M.c = M.d; M.d = tmp;
1788 pdf_ximage_scale_image(id, &M1, &r, p);
1789 pdf_concatmatrix(&M, &M1);
1793 if (p->flags & INFO_DO_CLIP) {
1796 pdf_dev_moveto(r.llx, r.lly);
1797 pdf_dev_lineto(r.urx, r.lly);
1798 pdf_dev_lineto(r.urx, r.ury);
1799 pdf_dev_lineto(r.llx, r.ury);
1800 pdf_dev_closepath();
1804 pdf_dev_rectclip(r.llx, r.lly, r.urx - r.llx, r.ury - r.lly);
1808 res_name = pdf_ximage_get_resname(id);
1809 len = sprintf(work_buffer, " /%s Do", res_name);
1810 pdf_doc_add_page_content(work_buffer, len); /* op: Do */
1814 pdf_doc_add_page_resource("XObject",
1816 pdf_ximage_get_reference(id));
1823 transform_info_clear (transform_info *info)
1825 /* Physical dimensions */
1830 info->bbox.llx = 0.0;
1831 info->bbox.lly = 0.0;
1832 info->bbox.urx = 0.0;
1833 info->bbox.ury = 0.0;
1835 /* Transformation matrix */
1836 pdf_setmatrix(&(info->matrix), 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);