1/*---------------------------------------------------------------------------* 2 | PDFlib - A library for generating PDF on the fly | 3 +---------------------------------------------------------------------------+ 4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. | 5 +---------------------------------------------------------------------------+ 6 | | 7 | This software is subject to the PDFlib license. It is NOT in the | 8 | public domain. Extended versions and commercial licenses are | 9 | available, please check http://www.pdflib.com. | 10 | | 11 *---------------------------------------------------------------------------*/ 12 13/* $Id: p_text.c 14574 2005-10-29 16:27:43Z bonefish $ 14 * 15 * PDFlib text routines 16 * 17 */ 18 19#define P_TEXT_C 20 21#include "p_intern.h" 22#include "p_font.h" 23 24/* ------------------------ Text object operators ------------------------ */ 25 26static void 27pdf_begin_text(PDF *p) 28{ 29 if (p->contents != c_text) 30 { 31 p->contents = c_text; 32 p->textparams_done = pdc_false; 33 34 pdc_puts(p->out, "BT\n"); 35 36 /* BT resets the current point, text matrix, and line matrix */ 37 p->gstate[p->sl].x = (float) 0.0; 38 p->gstate[p->sl].y = (float) 0.0; 39 } 40} 41 42static void 43pdf_put_textmatrix(PDF *p) 44{ 45 pdc_matrix *m = &p->tstate[p->sl].m; 46 47 pdc_printf(p->out, "%f %f %f %f %f %f Tm\n", 48 m->a, m->b, m->c, m->d, m->e, m->f); 49 p->tstate[p->sl].me = p->tstate[p->sl].m.e; 50 p->tstate[p->sl].potm = pdc_false; 51} 52 53void 54pdf_end_text(PDF *p) 55{ 56 if (p->contents != c_text) 57 return; 58 59 p->contents = c_page; 60 61 pdc_puts(p->out, "ET\n"); 62 p->tstate[p->sl].potm = pdc_true; 63} 64 65/* ------------------------ Text state operators ------------------------ */ 66 67/* Initialize the text state at the beginning of each page */ 68void 69pdf_init_tstate(PDF *p) 70{ 71 pdf_tstate *ts; 72 73 ts = &p->tstate[p->sl]; 74 75 ts->c = (float) 0; 76 ts->w = (float) 0; 77 ts->h = (float) 1; 78 ts->l = (float) 0; 79 ts->f = -1; 80 ts->fs = (float) 0; 81 82 ts->m.a = (float) 1; 83 ts->m.b = (float) 0; 84 ts->m.c = (float) 0; 85 ts->m.d = (float) 1; 86 ts->m.e = (float) 0; 87 ts->m.f = (float) 0; 88 ts->me = (float) 0; 89 90 ts->mode = 0; 91 ts->rise = (float) 0; 92 93 ts->lm.a = (float) 1; 94 ts->lm.b = (float) 0; 95 ts->lm.c = (float) 0; 96 ts->lm.d = (float) 1; 97 ts->lm.e = (float) 0; 98 ts->lm.f = (float) 0; 99 100 ts->potm = pdc_false; 101 102 p->underline = pdc_false; 103 p->overline = pdc_false; 104 p->strikeout = pdc_false; 105 p->textparams_done = pdc_false; 106} 107 108/* reset the text state */ 109void 110pdf_reset_tstate(PDF *p) 111{ 112 float ydirection = p->ydirection; 113 p->ydirection = (float) 1.0; 114 115 pdf_set_horiz_scaling(p, 100); 116 pdf_set_leading(p, 0); 117 pdf_set_text_rise(p, 0); 118 pdf_end_text(p); 119 120 p->ydirection = ydirection; 121} 122 123/* character spacing for justified lines */ 124void 125pdf_set_char_spacing(PDF *p, float spacing) 126{ 127 spacing *= p->ydirection; 128 if (PDF_GET_STATE(p) == pdf_state_document) 129 { 130 p->tstate[p->sl].c = spacing; 131 return; 132 } 133 134 /* 135 * We take care of spacing values != 0 in the text output functions, 136 * but must explicitly reset here. 137 */ 138 if (spacing == (float) 0) { 139 pdf_begin_text(p); 140 pdc_printf(p->out, "%f Tc\n", spacing); 141 } 142 143 p->tstate[p->sl].c = spacing; 144 p->textparams_done = pdc_false; 145} 146 147/* word spacing for justified lines */ 148void 149pdf_set_word_spacing(PDF *p, float spacing) 150{ 151 spacing *= p->ydirection; 152 if (PDF_GET_STATE(p) == pdf_state_document) 153 { 154 p->tstate[p->sl].w = spacing; 155 return; 156 } 157 158 /* 159 * We take care of spacing values != 0 in the text output functions, 160 * but must explicitly reset here. 161 */ 162 if (spacing == (float) 0) { 163 pdf_begin_text(p); 164 pdc_printf(p->out, "%f Tw\n", spacing); 165 } 166 167 p->tstate[p->sl].w = spacing; 168 p->textparams_done = pdc_false; 169} 170 171void 172pdf_set_horiz_scaling(PDF *p, float scale) 173{ 174 if (scale == (float) 0.0) 175 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 176 "horizscaling", pdc_errprintf(p->pdc, "%f", scale), 0, 0); 177 178 scale *= p->ydirection; 179 if (PDF_GET_STATE(p) == pdf_state_document) 180 { 181 p->tstate[p->sl].h = scale / (float) 100.0; 182 return; 183 } 184 185 if (scale == 100 * p->tstate[p->sl].h && !PDF_FORCE_OUTPUT()) 186 return; 187 188 pdf_begin_text(p); 189 pdc_printf(p->out, "%f Tz\n", scale); 190 191 p->tstate[p->sl].h = scale / (float) 100.0; 192} 193 194float 195pdf_get_horiz_scaling(PDF *p) 196{ 197 return (float) (p->ydirection * p->tstate[p->sl].h * 100); 198} 199 200void 201pdf_set_leading(PDF *p, float l) 202{ 203 l *= p->ydirection; 204 if (l == p->tstate[p->sl].l && !PDF_FORCE_OUTPUT()) 205 return; 206 207 p->tstate[p->sl].l = l; 208 p->textparams_done = pdc_false; 209} 210 211void 212pdf_set_text_rendering(PDF *p, int mode) 213{ 214 if (mode < 0 || mode > PDF_LAST_TRMODE) 215 pdc_error(p->pdc, PDC_E_ILLARG_INT, 216 "textrendering", pdc_errprintf(p->pdc, "%d", mode), 0, 0); 217 218 if (mode == p->tstate[p->sl].mode && !PDF_FORCE_OUTPUT()) 219 return; 220 221 pdf_begin_text(p); 222 pdc_printf(p->out, "%d Tr\n", mode); 223 224 p->tstate[p->sl].mode = mode; 225} 226 227void 228pdf_set_text_rise(PDF *p, float rise) 229{ 230 rise *= p->ydirection; 231 if (PDF_GET_STATE(p) == pdf_state_document) 232 { 233 p->tstate[p->sl].rise = rise; 234 return; 235 } 236 237 if (rise == p->tstate[p->sl].rise && !PDF_FORCE_OUTPUT()) 238 return; 239 240 pdf_begin_text(p); 241 pdc_printf(p->out, "%f Ts\n", rise); 242 243 p->tstate[p->sl].rise = rise; 244} 245 246/* Text positioning operators */ 247 248PDFLIB_API void PDFLIB_CALL 249PDF_set_text_matrix(PDF *p, 250 float a, float b, float c, float d, float e, float f) 251{ 252 static const char fn[] = "PDF_set_text_matrix"; 253 254 if (!pdf_enter_api(p, fn, 255 (pdf_state) (pdf_state_content | pdf_state_document), 256 "(p[%p], %g, %g, %g, %g, %g, %g)\n", (void *) p, a, b, c, d, e, f)) 257 { 258 return; 259 } 260 261 p->tstate[p->sl].m.a = a; 262 p->tstate[p->sl].m.b = b; 263 p->tstate[p->sl].m.c = c; 264 p->tstate[p->sl].m.d = d; 265 p->tstate[p->sl].m.e = e; 266 p->tstate[p->sl].m.f = f; 267 268 if (PDF_GET_STATE(p) != pdf_state_document) 269 { 270 pdf_begin_text(p); 271 pdf_put_textmatrix(p); 272 } 273} 274 275PDFLIB_API void PDFLIB_CALL 276PDF_set_text_pos(PDF *p, float x, float y) 277{ 278 static const char fn[] = "PDF_set_text_pos"; 279 280 if (!pdf_enter_api(p, fn, pdf_state_content, "(p[%p], %g, %g)\n", 281 (void *) p, x, y)) 282 return; 283 284 p->tstate[p->sl].m.e = x; 285 p->tstate[p->sl].m.f = y; 286 287 p->tstate[p->sl].lm.e = x; 288 p->tstate[p->sl].lm.f = y; 289 290 pdf_begin_text(p); 291 pdf_put_textmatrix(p); 292} 293 294/* String width calculations */ 295 296static float 297pdf_str_width(PDF *p, pdc_byte *text, int len, int charlen, 298 int font, float fontsize) 299{ 300 int i; 301 pdc_font *currfont = &p->fonts[font]; 302 pdc_ushort uv; 303 pdc_ushort *ustext = (pdc_ushort *) text; 304 float chwidth = (float) 0.0, width = (float) 0.0; 305 pdc_bool haswidths = (currfont->widths != NULL); 306 307 /* We cannot handle empty strings and fonts with unknown 308 * code size - especially CID fonts with no UCS-2 CMap */ 309 if (!len || !currfont->codeSize) 310 return width; 311 312 for (i = 0; i < len/charlen; i++) 313 { 314 if (charlen == 1) 315 uv = (pdc_ushort) text[i]; 316 else 317 uv = ustext[i]; 318 319 /* take word spacing parameter into account at each blank */ 320 if (currfont->codeSize == 1 && uv == (pdc_ushort) PDF_SPACE) 321 width += p->tstate[p->sl].w; 322 323 /* start by adding in the width of the character */ 324 if (currfont->monospace) 325 { 326 chwidth = (float) currfont->monospace; 327 } 328 else if (haswidths) 329 { 330 chwidth = (float) currfont->widths[uv]; 331 } 332 width += fontsize * chwidth / ((float) 1000); 333 334 335 /* now add the character spacing parameter */ 336 width += p->tstate[p->sl].c; 337 } 338 339 /* take current text matrix and horizontal scaling factor into account */ 340 width = width * p->tstate[p->sl].m.a * p->tstate[p->sl].h; 341 342 return width; 343} 344 345/* Convert and check input text string. 346 * The function returns a pointer to an allocated buffer 347 * containing the converted string. 348 * The caller is responsible for freeing this buffer. 349 * If return value is NULL error was occurred. 350 */ 351static pdc_byte * 352pdf_check_textstring(PDF *p, const char *text, int len, int font, 353 pdc_bool textflow, pdc_bool calcwidth, 354 int *outlen, int *outcharlen) 355{ 356 pdc_font *currfont = &p->fonts[font]; 357 pdc_byte *outtext; 358 pdc_text_format textformat, targettextformt; 359 int maxlen, charlen = 1; 360 int codesize = abs(currfont->codeSize); 361 362 (void) textflow; 363 364 /* Convert to 8-bit or UTF-16 text string */ 365 textformat = p->textformat; 366 if (textformat == pdc_auto && codesize <= 1) 367 textformat = pdc_bytes; 368 else if (textformat == pdc_auto2 && codesize <= 1) 369 textformat = pdc_bytes2; 370 targettextformt = pdc_utf16; 371 pdc_convert_string(p->pdc, textformat, NULL, (pdc_byte *)text, len, 372 &targettextformt, NULL, &outtext, outlen, 373 PDC_CONV_NOBOM | PDC_CONV_KEEPBYTES, pdc_true); 374 textformat = targettextformt; 375 376 if (outtext && *outlen) 377 { 378 /* 2 byte storage length of a character */ 379 if (textformat == pdc_utf16) 380 { 381 if (codesize <= 1 && currfont->encoding == pdc_builtin) 382 pdc_error(p->pdc, PDF_E_FONT_BADTEXTFORM, 0, 0, 0, 0); 383 charlen = 2; 384 } 385 386 /* Maximal text string length - found out emprirically! */ 387 maxlen = (codesize == 1) ? PDF_MAXARRAYSIZE : PDF_MAXDICTSIZE; 388 if (!calcwidth && *outlen > maxlen) 389 { 390 pdc_warning(p->pdc, PDF_E_TEXT_TOOLONG, 391 pdc_errprintf(p->pdc, "%d", maxlen), 0, 0, 0); 392 *outlen = maxlen; 393 } 394 395 } 396 *outcharlen = charlen; 397 398 return outtext; 399} 400 401float 402pdf__stringwidth(PDF *p, const char *text, int len, int font, float fontsize) 403{ 404 pdc_byte *utext; 405 int charlen; 406 float result = (float) 0.0; 407 408 if (text && len == 0) 409 len = (int) strlen(text); 410 if (text == NULL || len <= 0) 411 return result; 412 413 pdf_check_handle(p, font, pdc_fonthandle); 414 415 if (fontsize == (float) 0.0) 416 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, "fontsize", "0", 0, 0); 417 418 /* convert text string */ 419 fontsize *= p->ydirection; 420 utext = pdf_check_textstring(p, text, len, font, pdc_false, pdc_true, 421 &len, &charlen); 422 if (utext) 423 { 424 p->currtext = utext; 425 result = pdf_str_width(p, utext, len, charlen, font, fontsize); 426 p->currtext = NULL; 427 pdc_free(p->pdc, utext); 428 } 429 return result; 430} 431 432PDFLIB_API float PDFLIB_CALL 433PDF_stringwidth(PDF *p, const char *text, int font, float fontsize) 434{ 435 static const char fn[] = "PDF_stringwidth"; 436 float result = (float) 0.0; 437 438 if (pdf_enter_api(p, fn, 439 (pdf_state) (pdf_state_document | pdf_state_content | pdf_state_path), 440 "(p[%p], \"%s\", %d, %g)", 441 (void *) p, pdc_strprint(p->pdc, text, 0), font, fontsize)) 442 { 443 int len = text ? (int) strlen(text) : 0; 444 PDF_INPUT_HANDLE(p, font) 445 result = pdf__stringwidth(p, text, len, font, fontsize); 446 } 447 pdc_trace(p->pdc, "[%g]\n", result); 448 return result; 449} 450 451PDFLIB_API float PDFLIB_CALL 452PDF_stringwidth2(PDF *p, const char *text, int len, int font, float fontsize) 453{ 454 static const char fn[] = "PDF_stringwidth2"; 455 float result = (float) 0.0; 456 457 if (pdf_enter_api(p, fn, 458 (pdf_state) (pdf_state_document | pdf_state_content | pdf_state_path), 459 "(p[%p], \"%s\", %d, %d, %g)", 460 (void *) p, pdc_strprint(p->pdc, text, len), len, font, fontsize)) 461 { 462 PDF_INPUT_HANDLE(p, font) 463 result = pdf__stringwidth(p, text, len, font, fontsize); 464 } 465 pdc_trace(p->pdc, "[%g]\n", result); 466 return result; 467} 468 469 470/* ------------------------ Text control functions ------------------------ */ 471 472static void 473pdf_underline(PDF *p, float x, float y, float length) 474{ 475 float delta_y, xscale, yscale; 476 double linewidth; 477 pdf_tstate *ts; 478 479 ts = &p->tstate[p->sl]; 480 481 xscale = (float) fabs((double) ts->m.a); 482 yscale = (float) fabs((double) ts->m.d); 483 484 linewidth = fabs(ts->fs * p->fonts[ts->f].underlineThickness / 1000.0 * 485 ts->h * (xscale > yscale ? xscale : yscale)); 486 487 delta_y = (ts->fs * p->fonts[ts->f].underlinePosition / 1000 + ts->rise) * 488 (float) fabs((double) ts->h) * (xscale > yscale ? xscale : yscale); 489 490 pdf__save(p); 491 492 pdf__setlinewidth(p, (float) linewidth); 493 pdf__setlinecap(p, 0); 494 pdf__setdash(p, 0, 0); 495 pdf__moveto(p, x, y + delta_y); 496 pdf__lineto(p, x + length, y + delta_y); 497 pdf__stroke(p); 498 499 pdf__restore(p); 500} 501 502static void 503pdf_overline(PDF *p, float x, float y, float length) 504{ 505 float delta_y, xscale, yscale, lineheight; 506 double linewidth; 507 pdf_tstate *ts; 508 509 ts = &p->tstate[p->sl]; 510 511 xscale = (float) fabs((double) ts->m.a); 512 yscale = (float) fabs((double) ts->m.d); 513 514 linewidth = fabs(ts->fs * p->fonts[ts->f].underlineThickness / 1000.0 * 515 ts->h * (xscale > yscale ? xscale : yscale)); 516 517 lineheight = ((float) p->fonts[ts->f].ascender/1000) * ts->fs; 518 519 delta_y = (ts->fs * p->fonts[ts->f].underlinePosition / 1000 - ts->rise) * 520 (float) fabs((double) ts->h) * (xscale > yscale ? xscale : yscale); 521 522 pdf__save(p); 523 524 pdf__setlinewidth(p, (float)linewidth); 525 pdf__setlinecap(p, 0); 526 pdf__setdash(p, 0, 0); 527 pdf__moveto(p, x, y + lineheight - delta_y); 528 pdf__lineto(p, x + length, y + lineheight - delta_y); 529 pdf__stroke(p); 530 531 pdf__restore(p); 532} 533 534static void 535pdf_strikeout(PDF *p, float x, float y, float length) 536{ 537 float delta_y, xscale, yscale, lineheight; 538 double linewidth; 539 pdf_tstate *ts; 540 541 ts = &p->tstate[p->sl]; 542 543 xscale = (float) fabs((double) ts->m.a); 544 yscale = (float) fabs((double) ts->m.d); 545 546 linewidth = fabs(ts->fs * p->fonts[ts->f].underlineThickness / 1000.0 * 547 ts->h * (xscale > yscale ? xscale : yscale)); 548 549 lineheight = ((float) p->fonts[ts->f].ascender/1000) * ts->fs; 550 551 delta_y = (ts->fs * p->fonts[ts->f].underlinePosition / 1000 + ts->rise) * 552 (float) fabs((double) ts->h) * (xscale > yscale ? xscale : yscale); 553 pdf__save(p); 554 555 pdf__setlinewidth(p, (float)linewidth); 556 pdf__setlinecap(p, 0); 557 pdf__setdash(p, 0, 0); 558 pdf__moveto(p, x, y + lineheight/2 + delta_y); 559 pdf__lineto(p, x + length, y + lineheight/2 + delta_y); 560 pdf__stroke(p); 561 562 pdf__restore(p); 563} 564 565/* ------------------------ font operator ------------------------ */ 566 567void 568pdf__setfont(PDF *p, int font, float fontsize) 569{ 570 /* make font the current font */ 571 p->fonts[font].used_on_current_page = pdc_true; 572 p->tstate[p->sl].fs = p->ydirection * fontsize; 573 p->tstate[p->sl].f = font; 574 575 pdf_begin_text(p); 576 pdc_printf(p->out, "/F%d %f Tf\n", font, p->tstate[p->sl].fs); 577 pdf_set_leading(p, fontsize); 578} 579 580PDFLIB_API void PDFLIB_CALL 581PDF_setfont(PDF *p, int font, float fontsize) 582{ 583 static const char fn[] = "PDF_setfont"; 584 585 if (!pdf_enter_api(p, fn, pdf_state_content, "(p[%p], %d, %g)\n", 586 (void *) p, font, fontsize)) 587 return; 588 589 /* Check parameters */ 590 PDF_INPUT_HANDLE(p, font) 591 pdf_check_handle(p, font, pdc_fonthandle); 592 593 if (fontsize == (float) 0.0) 594 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, "fontsize", "0", 0, 0); 595 596 pdf__setfont(p, font, fontsize); 597} 598 599float 600pdf_get_fontsize(PDF *p) 601{ 602 if (p->fonts_number == 0 || p->tstate[p->sl].f == -1) /* no font set */ 603 pdc_error(p->pdc, PDF_E_TEXT_NOFONT_PAR, "fontsize", 0, 0, 0); 604 605 606 return p->ydirection * p->tstate[p->sl].fs; 607} 608 609/* ------------------------ Text rendering operators ------------------------ */ 610 611 612void 613pdf_put_textstring(PDF *p, pdc_byte *text, int len, int charlen) 614{ 615 (void) charlen; 616 617 pdc_put_pdfstring(p->out, (const char *) text, len); 618} 619 620 621static void 622pdf_output_text(PDF *p, pdc_byte *text, int len, int charlen) 623{ 624 { 625 pdf_put_textstring(p, text, len, charlen); 626 pdc_puts(p->out, "Tj\n"); 627 } 628} 629 630#define PDF_RENDERMODE_FILLCLIP 4 631 632static void 633pdf_place_text(PDF *p, pdc_byte *utext, int len, int charlen, 634 float x, float y, float width, pdc_bool cont) 635{ 636 pdf_tstate *ts = &p->tstate[p->sl]; 637 638 if (width) 639 { 640 if (p->underline) 641 pdf_underline(p, x, y, width); 642 if (p->overline) 643 pdf_overline(p, x, y, width); 644 if (p->strikeout) 645 pdf_strikeout(p, x, y, width); 646 } 647 648 pdf_begin_text(p); 649 if (ts->potm) 650 pdf_put_textmatrix(p); 651 652 /* set leading, word, and character spacing if required */ 653 if (!p->textparams_done) 654 { 655 pdc_printf(p->out, "%f TL\n", ts->l); 656 657 if (ts->w != (float) 0) 658 pdc_printf(p->out,"%f Tw\n", ts->w); 659 660 if (ts->c != (float) 0) 661 pdc_printf(p->out,"%f Tc\n", ts->c); 662 663 p->textparams_done = pdc_true; 664 } 665 666 /* text output */ 667 if (!cont) 668 { 669 pdf_output_text(p, utext, len, charlen); 670 } 671 else 672 { 673 { 674 pdf_put_textstring(p, utext, len, charlen); 675 pdc_puts(p->out, "'\n"); 676 } 677 } 678 679 if (ts->mode >= PDF_RENDERMODE_FILLCLIP) 680 pdf_end_text(p); 681 682 ts->m.e += width; 683 if (cont) ts->m.f -= ts->l; 684} 685 686void 687pdf_show_text( 688 PDF *p, 689 const char *text, 690 int len, 691 const float *x_p, 692 const float *y_p, 693 pdc_bool cont) 694{ 695 static const char *fn = "pdf_show_text"; 696 pdf_tstate *ts = &p->tstate[p->sl]; 697 pdc_byte *utext = NULL; 698 int charlen = 1; 699 float x, y, width; 700 701 if (x_p != NULL) 702 { 703 x = *x_p; 704 y = *y_p; 705 ts->m.e = x; 706 ts->m.f = y; 707 ts->lm.e = x; 708 ts->lm.f = y; 709 ts->potm = pdc_true; 710 } 711 else if (cont) 712 { 713 ts->m.e = ts->lm.e; 714 x = ts->m.e; 715 y = ts->m.f - ts->l; 716 717 /* we must output line begin if necessary */ 718 if (fabs((double) (ts->me - ts->lm.e)) > PDC_FLOAT_PREC) 719 ts->potm = pdc_true; 720 } 721 else 722 { 723 x = ts->m.e; 724 y = ts->m.f; 725 } 726 727 if (text && len == 0) 728 len = (int) strlen(text); 729 if (text == NULL || len <= 0) 730 { 731 if (cont) 732 len = 0; 733 else 734 return; 735 } 736 737 /* no font set */ 738 if (ts->f == -1) 739 pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0); 740 741 width = 0; 742 if (len) 743 { 744 /* convert text string */ 745 utext = pdf_check_textstring(p, text, len, ts->f, pdc_false, pdc_false, 746 &len, &charlen); 747 if (!utext) 748 return; 749 750 p->currtext = utext; 751 752 /* length of text */ 753 width = pdf_str_width(p, utext, len, charlen, ts->f, ts->fs); 754 } 755 else 756 { 757 utext = (pdc_byte *) pdc_calloc(p->pdc, 2, fn); 758 p->currtext = utext; 759 } 760 761 /* place text */ 762 pdf_place_text(p, utext, len, charlen, x, y, width, cont); 763 764 p->currtext = NULL; 765 if (utext) 766 pdc_free(p->pdc, utext); 767} 768 769PDFLIB_API void PDFLIB_CALL 770PDF_show(PDF *p, const char *text) 771{ 772 static const char fn[] = "PDF_show"; 773 if (pdf_enter_api(p, fn, pdf_state_content, "(p[%p], \"%s\")\n", 774 (void *) p, pdc_strprint(p->pdc, text, 0))) 775 { 776 int len = text ? (int) strlen(text) : 0; 777 pdf_show_text(p, text, len, NULL, NULL, pdc_false); 778 } 779} 780 781PDFLIB_API void PDFLIB_CALL 782PDF_show2(PDF *p, const char *text, int len) 783{ 784 static const char fn[] = "PDF_show2"; 785 if (pdf_enter_api(p, fn, pdf_state_content, 786 "(p[%p], \"%s\", %d)\n", 787 (void *) p, pdc_strprint(p->pdc, text, len), len)) 788 { 789 pdf_show_text(p, text, len, NULL, NULL, pdc_false); 790 } 791} 792 793PDFLIB_API void PDFLIB_CALL 794PDF_show_xy(PDF *p, const char *text, float x, float y) 795{ 796 static const char fn[] = "PDF_show_xy"; 797 if (pdf_enter_api(p, fn, pdf_state_content, "(p[%p], \"%s\", %g, %g)\n", 798 (void *) p, pdc_strprint(p->pdc, text, 0), x, y)) 799 { 800 int len = text ? (int) strlen(text) : 0; 801 pdf_show_text(p, text, len, &x, &y, pdc_false); 802 } 803} 804 805PDFLIB_API void PDFLIB_CALL 806PDF_show_xy2(PDF *p, const char *text, int len, float x, float y) 807{ 808 static const char fn[] = "PDF_show_xy2"; 809 if (pdf_enter_api(p, fn, pdf_state_content, "(p[%p], \"%s\", %d, %g, %g)\n", 810 (void *) p, pdc_strprint(p->pdc, text, len), len, x, y)) 811 { 812 pdf_show_text(p, text, len, &x, &y, pdc_false); 813 } 814} 815 816PDFLIB_API void PDFLIB_CALL 817PDF_continue_text(PDF *p, const char *text) 818{ 819 static const char fn[] = "PDF_continue_text"; 820 if (pdf_enter_api(p, fn, pdf_state_content, "(p[%p], \"%s\")\n", 821 (void *) p, pdc_strprint(p->pdc, text, 0))) 822 { 823 int len = text ? (int) strlen(text) : 0; 824 pdf_show_text(p, text, len, NULL, NULL, pdc_true); 825 } 826} 827 828PDFLIB_API void PDFLIB_CALL 829PDF_continue_text2(PDF *p, const char *text, int len) 830{ 831 static const char fn[] = "PDF_continue_text2"; 832 if (pdf_enter_api(p, fn, pdf_state_content, 833 "(p[%p], \"%s\", %d)\n", 834 (void *) p, pdc_strprint(p->pdc, text, len), len)) 835 { 836 pdf_show_text(p, text, len, NULL, NULL, pdc_true); 837 } 838} 839 840 841/* ----------------------- Text fitting routines ------------------------ */ 842 843#define PDF_KERNING_FLAG PDC_OPT_UNSUPP 844 845/* definitions of fit text options */ 846static const pdc_defopt pdf_fit_textline_options[] = 847{ 848 {"font", pdc_fonthandle, PDC_OPT_NONE, 1, 1, 849 0, 0, NULL}, 850 851 {"fontsize", pdc_floatlist, PDC_OPT_REQUIRIF1 | PDC_OPT_NOZERO, 1, 1, 852 PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, 853 854 {"textrendering", pdc_integerlist, PDC_OPT_NONE, 1, 1, 855 0, PDF_LAST_TRMODE, NULL}, 856 857 {"wordspacing", pdc_floatlist, PDC_OPT_NONE, 1, 1, 858 PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, 859 860 {"charspacing", pdc_floatlist, PDC_OPT_NONE, 1, 1, 861 PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, 862 863 {"horizscaling", pdc_floatlist, PDC_OPT_NOZERO, 1, 1, 864 PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, 865 866 {"textrise", pdc_floatlist, PDC_OPT_NONE, 1, 1, 867 PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, 868 869 {"underline", pdc_booleanlist, PDC_OPT_NONE, 1, 1, 870 0.0, 0.0, NULL}, 871 872 {"overline", pdc_booleanlist, PDC_OPT_NONE, 1, 1, 873 0.0, 0.0, NULL}, 874 875 {"strikeout", pdc_booleanlist, PDC_OPT_NONE, 1, 1, 876 0.0, 0.0, NULL}, 877 878 {"kerning", pdc_booleanlist, PDF_KERNING_FLAG, 1, 1, 879 0.0, 0.0, NULL}, 880 881 {"textformat", pdc_keywordlist, PDC_OPT_NONE, 1, 1, 882 0.0, 0.0, pdf_textformat_keylist}, 883 884 {"margin", pdc_floatlist, PDC_OPT_NONE, 1, 2, 885 PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, 886 887 {"orientate", pdc_keywordlist, PDC_OPT_NONE, 1, 1, 888 0.0, 0.0, pdf_orientate_keylist}, 889 890 {"boxsize", pdc_floatlist, PDC_OPT_NONE, 2, 2, 891 PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, 892 893 {"rotate", pdc_floatlist, PDC_OPT_NONE, 1, 1, 894 PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, 895 896 {"position", pdc_floatlist, PDC_OPT_NONE, 1, 2, 897 PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL}, 898 899 {"fitmethod", pdc_keywordlist, PDC_OPT_NONE, 1, 1, 900 0.0, 0.0, pdf_fitmethod_keylist}, 901 902 {"distortionlimit", pdc_floatlist, PDC_OPT_NONE, 1, 1, 903 0.0, 100.0, NULL}, 904 905 PDC_OPT_TERMINATE 906}; 907 908void 909pdf__fit_textline(PDF *p, const char *text, int len, float x, float y, 910 const char *optlist) 911{ 912 pdc_byte *utext = (pdc_byte *) ""; 913 pdc_resopt *results; 914 pdc_clientdata data; 915 pdc_text_format textformat_save = p->textformat; 916 pdc_bool underline_save = p->underline; 917 pdc_bool overline_save = p->overline; 918 pdc_bool strikeout_save = p->strikeout; 919 int charlen; 920 921 int font; 922 float fontsize; 923 int textrendering, ntextrendering; 924 float textrise, wordspacing, charspacing, horizscaling; 925 int nfontsize, ntextrise, nwordspacing, ncharspacing, nhorizscaling; 926 float margin[2], boxsize[2], position[2], angle, distortionlimit; 927 pdc_fitmethod method; 928 int inum, orientangle, indangle; 929 930 if (text && len == 0) 931 len = (int) strlen(text); 932 if (text == NULL || len <= 0) 933 return; 934 935 /* defaults */ 936 font = p->tstate[p->sl].f; 937 fontsize = p->tstate[p->sl].fs; 938 orientangle = 0; 939 margin[0] = margin[1] = (float) 0.0; 940 boxsize[0] = boxsize[1] = (float) 0.0; 941 position[0] = position[1] = (float) 0.0; 942 angle = (float) 0.0; 943 method = pdc_nofit; 944 distortionlimit = (float) 75.0; 945 946 /* parsing optlist */ 947 data.compatibility = p->compatibility; 948 data.maxfont = p->fonts_number - 1; 949 data.hastobepos = p->hastobepos; 950 results = pdc_parse_optionlist(p->pdc, optlist, pdf_fit_textline_options, 951 &data, pdc_true); 952 953 /* save options */ 954 pdc_get_optvalues(p->pdc, "font", results, &font, NULL); 955 956 nfontsize = pdc_get_optvalues(p->pdc, "fontsize", results, 957 &fontsize, NULL); 958 959 ntextrendering = pdc_get_optvalues(p->pdc, "textrendering", results, 960 &textrendering, NULL); 961 962 nwordspacing = pdc_get_optvalues(p->pdc, "wordspacing", results, 963 &wordspacing, NULL); 964 965 ncharspacing = pdc_get_optvalues(p->pdc, "charspacing", results, 966 &charspacing, NULL); 967 968 nhorizscaling = pdc_get_optvalues(p->pdc, "horizscaling", results, 969 &horizscaling, NULL); 970 971 ntextrise = pdc_get_optvalues(p->pdc, "textrise", results, 972 &textrise, NULL); 973 974 pdc_get_optvalues(p->pdc, "underline", results, &p->underline, NULL); 975 976 pdc_get_optvalues(p->pdc, "overline", results, &p->overline, NULL); 977 978 pdc_get_optvalues(p->pdc, "strikeout", results, &p->strikeout, NULL); 979 980 981 if (pdc_get_optvalues(p->pdc, "textformat", results, &inum, NULL)) 982 p->textformat = (pdc_text_format) inum; 983 984 if (1 == pdc_get_optvalues(p->pdc, "margin", results, margin, NULL)) 985 margin[1] = margin[0]; 986 987 pdc_get_optvalues(p->pdc, "orientate", results, &orientangle, NULL); 988 989 pdc_get_optvalues(p->pdc, "boxsize", results, boxsize, NULL); 990 991 pdc_get_optvalues(p->pdc, "rotate", results, &angle, NULL); 992 993 pdc_get_optvalues(p->pdc, "distortionlimit", results, 994 &distortionlimit, NULL); 995 996 if (1 == pdc_get_optvalues(p->pdc, "position", results, position, NULL)) 997 position[1] = position[0]; 998 999 if (pdc_get_optvalues(p->pdc, "fitmethod", results, &inum, NULL)) 1000 method = (pdc_fitmethod) inum; 1001 1002 pdc_cleanup_optionlist(p->pdc, results); 1003 1004 /* save graphic state */ 1005 pdf__save(p); 1006 1007 while (1) 1008 { 1009 pdf_tstate *ts = &p->tstate[p->sl]; 1010 pdc_matrix m; 1011 pdc_vector elemsize, elemscale, elemmargin, relpos, polyline[5]; 1012 pdc_box fitbox, elembox; 1013 pdc_scalar ss, minfscale; 1014 float width, height, tx = 0, ty = 0; 1015 1016 /* font size */ 1017 if (nfontsize) 1018 { 1019 pdf__setfont(p, font, fontsize); 1020 fontsize = p->tstate[p->sl].fs; 1021 } 1022 1023 /* no font set */ 1024 if (p->tstate[p->sl].f == -1) 1025 pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0); 1026 1027 /* convert text string */ 1028 utext = pdf_check_textstring(p, text, len, font, pdc_false, pdc_false, 1029 &len, &charlen); 1030 if (utext == NULL || len == 0) 1031 break; 1032 p->currtext = utext; 1033 1034 /* text rendering */ 1035 if (ntextrendering) 1036 pdf_set_text_rendering(p, textrendering); 1037 1038 /* options for text width and height */ 1039 if (nwordspacing) 1040 pdf_set_word_spacing(p, wordspacing); 1041 if (ncharspacing) 1042 pdf_set_char_spacing(p, charspacing); 1043 if (nhorizscaling) 1044 pdf_set_horiz_scaling(p, horizscaling); 1045 if (ntextrise) 1046 pdf_set_text_rise(p, textrise); 1047 1048 /* minimal horizontal scaling factor */ 1049 minfscale = distortionlimit / 100.0; 1050 1051 /* text width */ 1052 width = pdf_str_width(p, utext, len, charlen, font, fontsize); 1053 if (width < PDF_SMALLREAL) 1054 break; 1055 elemmargin.x = margin[0]; 1056 elemsize.x = width + 2 * elemmargin.x; 1057 1058 /* text height */ 1059 height = (float) fabs((p->fonts[ts->f].capHeight / 1000.0f) * ts->fs); 1060 elemmargin.y = margin[1]; 1061 elemsize.y = height + 2 * elemmargin.y; 1062 1063 /* orientation */ 1064 indangle = orientangle / 90; 1065 if (indangle % 2) 1066 { 1067 ss = elemsize.x; 1068 elemsize.x = elemsize.y; 1069 elemsize.y = ss; 1070 } 1071 1072 /* box for fitting */ 1073 fitbox.ll.x = 0; 1074 fitbox.ll.y = 0; 1075 fitbox.ur.x = boxsize[0]; 1076 fitbox.ur.y = boxsize[1]; 1077 1078 /* relative position */ 1079 relpos.x = position[0] / 100.0; 1080 relpos.y = position[1] / 100.0; 1081 1082 /* calculate image box */ 1083 pdc_place_element(method, minfscale, &fitbox, &relpos, 1084 &elemsize, &elembox, &elemscale); 1085 1086 /* reference point */ 1087 pdc_translation_matrix(x, y, &m); 1088 pdf_concat_raw(p, &m); 1089 1090 /* clipping */ 1091 if (method == pdc_clip || method == pdc_slice) 1092 { 1093 pdf__rect(p, 0, 0, boxsize[0], boxsize[1]); 1094 pdf__clip(p); 1095 } 1096 1097 /* optional rotation */ 1098 if (fabs((double)(angle)) > PDC_FLOAT_PREC) 1099 { 1100 pdc_rotation_matrix(p->ydirection * angle, &m); 1101 pdf_concat_raw(p, &m); 1102 } 1103 1104 /* translation of element box */ 1105 elembox.ll.y *= p->ydirection; 1106 elembox.ur.y *= p->ydirection; 1107 pdc_box2polyline(&elembox, polyline); 1108 tx = (float) polyline[indangle].x; 1109 ty = (float) polyline[indangle].y; 1110 pdc_translation_matrix(tx, ty, &m); 1111 pdf_concat_raw(p, &m); 1112 1113 /* orientation of text */ 1114 if (orientangle != 0) 1115 { 1116 pdc_rotation_matrix(p->ydirection * orientangle, &m); 1117 pdf_concat_raw(p, &m); 1118 if (indangle % 2) 1119 { 1120 ss = elemscale.x; 1121 elemscale.x = elemscale.y; 1122 elemscale.y = ss; 1123 } 1124 } 1125 1126 if (elemscale.x != 1 || elemscale.y != 1) 1127 { 1128 pdc_scale_matrix((float) elemscale.x, (float) elemscale.y, &m); 1129 pdf_concat_raw(p, &m); 1130 } 1131 1132 /* place text */ 1133 x = (float) elemmargin.x; 1134 y = (float) elemmargin.y; 1135 p->tstate[p->sl].m.e = x; 1136 p->tstate[p->sl].m.f = y; 1137 p->tstate[p->sl].lm.e = x; 1138 p->tstate[p->sl].lm.f = y; 1139 p->tstate[p->sl].potm = pdc_true; 1140 pdf_place_text(p, utext, len, charlen, x, y, width, pdc_false); 1141 1142 break; 1143 } 1144 1145 /* restore graphic state */ 1146 pdf__restore(p); 1147 p->underline = underline_save; 1148 p->overline = overline_save; 1149 p->strikeout = strikeout_save; 1150 p->textformat = textformat_save; 1151 p->currtext = NULL; 1152 if (utext) 1153 pdc_free(p->pdc, utext); 1154} 1155 1156PDFLIB_API void PDFLIB_CALL 1157PDF_fit_textline(PDF *p, const char *text, int len, float x, float y, 1158 const char *optlist) 1159{ 1160 static const char fn[] = "PDF_fit_textline"; 1161 1162 if (pdf_enter_api(p, fn, pdf_state_content, 1163 "(p[%p], \"%s\", %d, %g, %g, \"%s\")\n", 1164 (void *) p, pdc_strprint(p->pdc, text, len), len, x, y, optlist)) 1165 { 1166 pdf__fit_textline(p, text, len, x, y, optlist); 1167 } 1168} 1169 1170/* ----------------------- Text formatting routines ------------------------ */ 1171 1172/* text alignment modes */ 1173typedef enum { pdf_align_left, pdf_align_right, pdf_align_center, 1174 pdf_align_justify, pdf_align_fulljustify 1175} pdf_alignment; 1176 1177/* this helper function returns the width of the null-terminated string 1178** 'text' for the current font and size EXCLUDING the last character's 1179** additional charspacing. 1180*/ 1181static float 1182pdf_swidth(PDF *p, const char *text) 1183{ 1184 pdf_tstate *ts = &p->tstate[p->sl]; 1185 1186 return pdf_str_width(p, (pdc_byte *)text, (int) strlen(text), 1, 1187 ts->f, ts->fs) - ts->c * ts->m.a * ts->h; 1188} 1189 1190static void 1191pdf_show_aligned(PDF *p, const char *text, float x, float y, pdf_alignment mode) 1192{ 1193 if (!text) 1194 return; 1195 1196 switch (mode) { 1197 case pdf_align_left: 1198 case pdf_align_justify: 1199 case pdf_align_fulljustify: 1200 /* nothing extra here... */ 1201 break; 1202 1203 case pdf_align_right: 1204 x -= pdf_swidth(p, text); 1205 break; 1206 1207 case pdf_align_center: 1208 x -= pdf_swidth(p, text) / 2; 1209 break; 1210 } 1211 1212 pdf_show_text(p, text, (int) strlen(text), &x, &y, pdc_false); 1213} 1214 1215static int 1216pdf__show_boxed( 1217 PDF *p, 1218 const char *text, 1219 int totallen, 1220 float left, 1221 float bottom, 1222 float width, 1223 float height, 1224 const char *hmode, 1225 const char *feature) 1226{ 1227 float textwidth, old_word_spacing, curx, cury; 1228 pdc_bool prematureexit; /* return because box is too small */ 1229 int curTextPos; /* character currently processed */ 1230 int lastdone; /* last input character processed */ 1231 int toconv = totallen; 1232 pdf_tstate *ts = &p->tstate[p->sl]; 1233 pdc_byte *utext = NULL; 1234 pdc_text_format textformat = p->textformat; 1235 pdf_alignment mode = pdf_align_left; 1236 pdc_bool blind = pdc_false; 1237 1238 if (hmode == NULL || *hmode == '\0') 1239 pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "hmode", 0, 0, 0); 1240 1241 if (!strcmp(hmode, "left")) 1242 mode = pdf_align_left; 1243 else if (!strcmp(hmode, "right")) 1244 mode = pdf_align_right; 1245 else if (!strcmp(hmode, "center")) 1246 mode = pdf_align_center; 1247 else if (!strcmp(hmode, "justify")) 1248 mode = pdf_align_justify; 1249 else if (!strcmp(hmode, "fulljustify")) 1250 mode = pdf_align_fulljustify; 1251 else 1252 pdc_error(p->pdc, PDC_E_ILLARG_STRING, "hmode", hmode, 0, 0); 1253 1254 if (feature != NULL && *feature != '\0') 1255 { 1256 if (!strcmp(feature, "blind")) 1257 blind = pdc_true; 1258 else 1259 pdc_error(p->pdc, PDC_E_ILLARG_STRING, "feature", feature, 0, 0); 1260 } 1261 1262 /* no font set */ 1263 if (ts->f == -1) 1264 pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0); 1265 1266 if (width == 0 && height != 0) 1267 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 1268 "width", pdc_errprintf(p->pdc, "%f", width), 0, 0); 1269 1270 if (width != 0 && height == 0) 1271 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 1272 "height", pdc_errprintf(p->pdc, "%f", height), 0, 0); 1273 1274 /* we cannot handle several encodings */ 1275 if (p->fonts[ts->f].encoding == pdc_unicode) 1276 { 1277 pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "Unicode", 0, 0, 0); 1278 } 1279 1280 if (p->fonts[ts->f].encoding == pdc_glyphid) 1281 { 1282 pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "glyphid", 0, 0, 0); 1283 } 1284 1285 if (p->fonts[ts->f].encoding == pdc_cid) 1286 { 1287 pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "CID", 0, 0, 0); 1288 } 1289 1290 if (p->fonts[ts->f].encoding == pdc_ebcdic) 1291 { 1292 pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "EBCDIC", 0, 0, 0); 1293 } 1294 1295 /* convert text string */ 1296 if (toconv) 1297 { 1298 int charlen; 1299 utext = pdf_check_textstring(p, text, totallen, ts->f, pdc_true, 1300 pdc_true, &totallen, &charlen); 1301 if (!utext) 1302 return 0; 1303 1304 utext[totallen] = 0; 1305 text = (const char *) utext; 1306 p->textformat = pdc_bytes; 1307 } 1308 1309 /* text length */ 1310 if (!totallen) 1311 totallen = (int) strlen(text); 1312 1313 /* special case for a single aligned line */ 1314 if (width == 0 && height == 0) 1315 { 1316 if (!blind) 1317 pdf_show_aligned(p, text, left, bottom, mode); 1318 1319 if (toconv) 1320 { 1321 pdc_free(p->pdc, utext); 1322 p->textformat = textformat; 1323 } 1324 return 0; 1325 } 1326 1327 old_word_spacing = ts->w; 1328 1329 curx = left; 1330 cury = bottom + p->ydirection * height; 1331 prematureexit = pdc_false; 1332 curTextPos = 0; 1333 lastdone = 0; 1334 1335 /* switch curx for right and center justification */ 1336 if (mode == pdf_align_right) 1337 curx += width; 1338 else if (mode == pdf_align_center) 1339 curx += (width / 2); 1340 1341#define MAX_CHARS_IN_LINE 2048 1342 1343 /* loop until all characters processed, or box full */ 1344 1345 while ((curTextPos < totallen) && !prematureexit) { 1346 /* buffer for constructing the line */ 1347 char linebuf[MAX_CHARS_IN_LINE]; 1348 int curCharsInLine = 0; /* # of chars in constructed line */ 1349 int lastWordBreak = 0; /* the last seen space char */ 1350 int wordBreakCount = 0; /* # of blanks in this line */ 1351 1352 /* loop over the input string */ 1353 while (curTextPos < totallen) { 1354 if (curCharsInLine >= MAX_CHARS_IN_LINE) 1355 pdc_error(p->pdc, PDC_E_ILLARG_TOOLONG, "(text line)", 1356 pdc_errprintf(p->pdc, "%d", MAX_CHARS_IN_LINE-1), 0, 0); 1357 1358 /* abandon DOS line-ends */ 1359 if (text[curTextPos] == PDF_RETURN && 1360 text[curTextPos+1] == PDF_NEWLINE) 1361 curTextPos++; 1362 1363 /* if it's a forced line break draw the line */ 1364 if (text[curTextPos] == PDF_NEWLINE || 1365 text[curTextPos] == PDF_RETURN) { 1366 1367 cury -= ts->l; /* adjust cury by leading */ 1368 1369 if (p->ydirection * (cury - bottom) < 0) { 1370 prematureexit = pdc_true; /* box full */ 1371 break; 1372 } 1373 1374 linebuf[curCharsInLine] = 0; /* terminate the line */ 1375 1376 /* check whether the line is too long */ 1377 ts->w = (float) 0.0; 1378 textwidth = pdf_swidth(p, linebuf); 1379 1380 /* the forced break occurs too late for this line */ 1381 if (textwidth > width) { 1382 if (wordBreakCount == 0) { /* no blank found */ 1383 prematureexit = pdc_true; 1384 break; 1385 } 1386 linebuf[lastWordBreak] = 0; /* terminate at last blank */ 1387 if (curTextPos > 0 && text[curTextPos-1] == PDF_RETURN) 1388 --curTextPos; 1389 curTextPos -= (curCharsInLine - lastWordBreak); 1390 1391 if (!blind) { 1392 textwidth = pdf_swidth(p, linebuf); 1393 if (wordBreakCount != 1 && 1394 (mode == pdf_align_justify || 1395 mode == pdf_align_fulljustify)) { 1396 pdf_set_word_spacing(p, 1397 p->ydirection * (width - textwidth) / 1398 ((wordBreakCount - 1) * ts->h * ts->m.a)); 1399 } 1400 else 1401 pdf_set_word_spacing(p, (float) 0.0); 1402 pdf_show_aligned(p, linebuf, curx, cury, mode); 1403 } 1404 1405 } else if (!blind) { 1406 1407 if (mode == pdf_align_fulljustify && wordBreakCount > 0) { 1408 pdf_set_word_spacing(p, 1409 p->ydirection * (width - textwidth) / 1410 (wordBreakCount * ts->h * ts->m.a)); 1411 } else { 1412 pdf_set_word_spacing(p, (float) 0.0); 1413 } 1414 1415 pdf_show_aligned(p, linebuf, curx, cury, mode); 1416 } 1417 1418 lastdone = curTextPos; 1419 curCharsInLine = lastWordBreak = wordBreakCount = 0; 1420 curTextPos++; 1421 1422 } else if (text[curTextPos] == PDF_SPACE) { 1423 linebuf[curCharsInLine] = 0; /* terminate the line */ 1424 ts->w = (float) 0.0; 1425 1426 /* line too long ==> break at last blank */ 1427 if (pdf_swidth(p, linebuf) > width) { 1428 cury -= ts->l; /* adjust cury by leading */ 1429 1430 if (p->ydirection * (cury - bottom) < 0) { 1431 prematureexit = pdc_true; /* box full */ 1432 break; 1433 } 1434 1435 linebuf[lastWordBreak] = 0; /* terminate at last blank */ 1436 curTextPos -= (curCharsInLine - lastWordBreak - 1); 1437 1438 if (lastWordBreak == 0) 1439 curTextPos--; 1440 1441 /* LATER: * force break if wordBreakCount == 1, 1442 * i.e., no blank 1443 */ 1444 if (wordBreakCount == 0) { 1445 prematureexit = pdc_true; 1446 break; 1447 } 1448 1449 /* adjust word spacing for full justify */ 1450 if (wordBreakCount != 1 && (mode == pdf_align_justify || 1451 mode == pdf_align_fulljustify)) { 1452 ts->w = (float) 0.0; 1453 textwidth = pdf_swidth(p, linebuf); 1454 if (!blind) { 1455 pdf_set_word_spacing(p, 1456 p->ydirection * (width - textwidth) / 1457 ((wordBreakCount - 1) * ts->h * ts->m.a)); 1458 } 1459 } 1460 else if (!blind) { 1461 pdf_set_word_spacing(p, (float) 0.0); 1462 } 1463 1464 1465 lastdone = curTextPos; 1466 if (!blind) 1467 pdf_show_aligned(p, linebuf, curx, cury, mode); 1468 curCharsInLine = lastWordBreak = wordBreakCount = 0; 1469 1470 } else { 1471 /* blank found, and line still fits */ 1472 wordBreakCount++; 1473 lastWordBreak = curCharsInLine; 1474 linebuf[curCharsInLine++] = text[curTextPos++]; 1475 } 1476 1477 } else { 1478 /* regular character ==> store in buffer */ 1479 linebuf[curCharsInLine++] = text[curTextPos++]; 1480 } 1481 } 1482 1483 if (prematureexit) { 1484 break; /* box full */ 1485 } 1486 1487 /* if there is anything left in the buffer, draw it */ 1488 if (curTextPos >= totallen && curCharsInLine != 0) { 1489 cury -= ts->l; /* adjust cury for line height */ 1490 1491 if (p->ydirection * (cury - bottom) < 0) { 1492 prematureexit = pdc_true; /* box full */ 1493 break; 1494 } 1495 1496 linebuf[curCharsInLine] = 0; /* terminate the line */ 1497 1498 /* check if the last line is too long */ 1499 ts->w = (float) 0.0; 1500 textwidth = pdf_swidth(p, linebuf); 1501 1502 if (textwidth > width) { 1503 if (wordBreakCount == 0) 1504 { 1505 prematureexit = pdc_true; 1506 break; 1507 } 1508 1509 linebuf[lastWordBreak] = 0; /* terminate at last blank */ 1510 curTextPos -= (curCharsInLine - lastWordBreak - 1); 1511 1512 /* recalculate the width */ 1513 textwidth = pdf_swidth(p, linebuf); 1514 1515 /* adjust word spacing for full justify */ 1516 if (wordBreakCount != 1 && (mode == pdf_align_justify || 1517 mode == pdf_align_fulljustify)) { 1518 if (!blind) { 1519 pdf_set_word_spacing(p, 1520 p->ydirection * (width - textwidth) / 1521 ((wordBreakCount - 1) * ts->h * ts->m.a)); 1522 } 1523 } 1524 1525 } else if (!blind) { 1526 1527 if (mode == pdf_align_fulljustify && wordBreakCount) { 1528 pdf_set_word_spacing(p, 1529 p->ydirection * (width - textwidth) / 1530 (wordBreakCount * ts->h * ts->m.a)); 1531 } else { 1532 pdf_set_word_spacing(p, (float) 0.0); 1533 } 1534 } 1535 1536 lastdone = curTextPos; 1537 if (!blind) 1538 pdf_show_aligned(p, linebuf, curx, cury, mode); 1539 curCharsInLine = lastWordBreak = wordBreakCount = 0; 1540 } 1541 } 1542 1543 if (!blind) 1544 pdf_set_word_spacing(p, old_word_spacing); 1545 1546 /* return number of remaining characters */ 1547 1548 while (text[lastdone] == PDF_SPACE) 1549 ++lastdone; 1550 1551 if ((text[lastdone] == PDF_RETURN || 1552 text[lastdone] == PDF_NEWLINE) && text[lastdone+1] == 0) 1553 ++lastdone; 1554 1555 if (toconv) 1556 { 1557 pdc_free(p->pdc, utext); 1558 p->textformat = textformat; 1559 } 1560 1561 return (int) (totallen - lastdone); 1562} 1563 1564PDFLIB_API int PDFLIB_CALL 1565PDF_show_boxed( 1566 PDF *p, 1567 const char *text, 1568 float left, 1569 float bottom, 1570 float width, 1571 float height, 1572 const char *hmode, 1573 const char *feature) 1574{ 1575 static const char fn[] = "PDF_show_boxed"; 1576 int remchars; 1577 1578 if (!pdf_enter_api(p, fn, pdf_state_content, 1579 "(p[%p], \"%s\", %g, %g, %g, %g, \"%s\", \"%s\")", 1580 (void *) p, pdc_strprint(p->pdc, text, 0), 1581 left, bottom, width, height, hmode, feature)) 1582 { 1583 return 0; 1584 } 1585 1586 if (text == NULL || *text == '\0') { 1587 pdc_trace(p->pdc, "[%d]\n", 0); 1588 return 0; 1589 } 1590 1591 remchars = pdf__show_boxed(p, text, 0, left, bottom, 1592 width, height, hmode, feature); 1593 1594 pdc_trace(p->pdc, "[%d]\n", remchars); 1595 return remchars; 1596} 1597 1598PDFLIB_API int PDFLIB_CALL 1599PDF_show_boxed2( 1600 PDF *p, 1601 const char *text, 1602 int len, 1603 float left, 1604 float bottom, 1605 float width, 1606 float height, 1607 const char *hmode, 1608 const char *feature) 1609{ 1610 static const char fn[] = "PDF_show_boxed2"; 1611 int remchars; 1612 1613 if (!pdf_enter_api(p, fn, pdf_state_content, 1614 "(p[%p], \"%s\", %d, %g, %g, %g, %g, \"%s\", \"%s\")", 1615 (void *) p, pdc_strprint(p->pdc, text, len), len, 1616 left, bottom, width, height, hmode, feature)) 1617 { 1618 return 0; 1619 } 1620 1621 if (text == NULL || len == 0) { 1622 pdc_trace(p->pdc, "[%d]\n", 0); 1623 return 0; 1624 } 1625 1626 remchars = pdf__show_boxed(p, text, len, left, bottom, 1627 width, height, hmode, feature); 1628 1629 pdc_trace(p->pdc, "[%d]\n", remchars); 1630 return remchars; 1631} 1632 1633