Files correlati : Ricompilazione Demo : [ ] Commento : Riportata la versione 3.1 patch 650 git-svn-id: svn://10.65.10.50/trunk@14148 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			2296 lines
		
	
	
		
			65 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2296 lines
		
	
	
		
			65 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /*---------------------------------------------------------------------------*
 | |
|  |              PDFlib - A library for generating PDF on the fly             |
 | |
|  +---------------------------------------------------------------------------+
 | |
|  | Copyright (c) 1997-2005 Thomas Merz and PDFlib GmbH. All rights reserved. |
 | |
|  +---------------------------------------------------------------------------+
 | |
|  |                                                                           |
 | |
|  |    This software is subject to the PDFlib license. It is NOT in the       |
 | |
|  |    public domain. Extended versions and commercial licenses are           |
 | |
|  |    available, please check http://www.pdflib.com.                         |
 | |
|  |                                                                           |
 | |
|  *---------------------------------------------------------------------------*/
 | |
| 
 | |
| /* $Id: p_text.c,v 1.2 2006-07-11 13:10:33 alex Exp $
 | |
|  *
 | |
|  * PDFlib text routines
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #define P_TEXT_C
 | |
| 
 | |
| #include "p_intern.h"
 | |
| #include "p_color.h"
 | |
| #include "p_defopt.h"
 | |
| #include "p_font.h"
 | |
| #include "p_layer.h"
 | |
| #include "p_tagged.h"
 | |
| 
 | |
| 
 | |
| /* --------------------- Text state and options functions ------------------- */
 | |
| 
 | |
| struct pdf_tstate_s
 | |
| {
 | |
|     pdc_bool    glyphinit;      /* glyph description initialized */
 | |
|     pdc_bool    hsinit;         /* horizontal scaling initialized */
 | |
|     int         mask;           /* bit mask for text options */
 | |
|     int         font;           /* slot number of the current font */
 | |
|     int         trm;            /* text rendering mode */
 | |
|     pdc_scalar  fs;             /* font size */
 | |
|     pdc_scalar  ld;             /* leading */
 | |
|     pdc_scalar  cs;             /* character spacing */
 | |
|     pdc_scalar  ws;             /* word spacing */
 | |
|     pdc_scalar  hs;             /* horizontal scaling */
 | |
|     pdc_scalar  ia;             /* italic angle */
 | |
|     pdc_scalar  rise;           /* text rise */
 | |
|     pdc_scalar  ulw;            /* underline width */
 | |
|     pdc_scalar  ulp;            /* underline position */
 | |
| 
 | |
|     pdc_bool    newpos;         /* new text position */
 | |
|     pdc_scalar  currtx;         /* x coordinate of current text position */
 | |
|     pdc_scalar  currty;         /* y coordinate of current text position */
 | |
|     pdc_scalar  prevtx;         /* x coordinate of previous text position */
 | |
|     pdc_scalar  prevty;         /* y coordinate of previous text position */
 | |
|     pdc_scalar  linetx;         /* x coordinate of text line start position */
 | |
|     pdc_scalar  refptx;         /* x and y coordinate of reference position */
 | |
|     pdc_scalar  refpty;         /* for moving to next text line start position*/
 | |
| };
 | |
| 
 | |
| /* Initialize the text state at the beginning of each page */
 | |
| void
 | |
| pdf_init_tstate(PDF *p)
 | |
| {
 | |
|     static const char fn[] = "pdf_init_tstate";
 | |
| 
 | |
|     /* text state */
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     pdf_tstate *ts;
 | |
| 
 | |
|     if (!p->curr_ppt->tstate)
 | |
|     {
 | |
| 	p->curr_ppt->tstate = (pdf_tstate *) pdc_malloc(p->pdc,
 | |
|                                    PDF_MAX_SAVE_LEVEL * sizeof(pdf_tstate), fn);
 | |
| 	ppt->currto = (pdf_text_options *) pdc_malloc(p->pdc,
 | |
|                           sizeof(pdf_text_options), fn);
 | |
|     }
 | |
| 
 | |
|     ts = &ppt->tstate[ppt->sl];
 | |
| 
 | |
|     ts->glyphinit = pdc_undef;
 | |
|     ts->hsinit = (p->ydirection == -1) ? pdc_false : pdc_true;
 | |
| 
 | |
|     ts->mask = 0;
 | |
|     ts->font = -1;
 | |
|     ts->trm = 0;
 | |
|     ts->fs = 0;
 | |
|     ts->ld = 0;
 | |
|     ts->cs = 0;
 | |
|     ts->ws = 0;
 | |
|     ts->hs = 1;
 | |
|     ts->ia = 0;
 | |
|     ts->rise = 0;
 | |
|     ts->ulw = PDF_UNDERLINEWIDTH_AUTO;
 | |
|     ts->ulp = PDF_UNDERLINEPOSITION_AUTO;
 | |
| 
 | |
|     ts->newpos = pdc_false;
 | |
|     ts->currtx = 0;
 | |
|     ts->currty = 0;
 | |
|     ts->prevtx = 0;
 | |
|     ts->prevty = 0;
 | |
|     ts->linetx = 0;
 | |
|     ts->refptx = 0;
 | |
|     ts->refpty = 0;
 | |
| 
 | |
|     /* current text options */
 | |
|     pdf_init_text_options(p, ppt->currto);
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_cleanup_page_tstate(PDF *p, pdf_ppt *ppt)
 | |
| {
 | |
|     if (ppt->tstate != NULL)
 | |
|     {
 | |
|         pdc_free(p->pdc, ppt->tstate);
 | |
|         pdc_free(p->pdc, ppt->currto);
 | |
| 	ppt->tstate = NULL;
 | |
| 	ppt->currto = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_save_tstate(PDF *p)
 | |
| {
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     int sl = ppt->sl;
 | |
| 
 | |
|     memcpy(&ppt->tstate[sl + 1], &ppt->tstate[sl], sizeof(pdf_tstate));
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_restore_currto(PDF *p)
 | |
| {
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     pdf_text_options *currto = ppt->currto;
 | |
|     pdf_tstate *ts = &ppt->tstate[ppt->sl];
 | |
| 
 | |
|     currto->mask = ts->mask;
 | |
|     currto->font = ts->font;
 | |
|     currto->textrendering = ts->trm;
 | |
|     currto->fontsize = ts->fs;
 | |
|     currto->leading = ts->ld;
 | |
|     currto->charspacing = ts->cs;
 | |
|     currto->wordspacing = ts->ws;
 | |
|     currto->horizscaling = ts->hs;
 | |
|     currto->italicangle = ts->ia;
 | |
|     currto->textrise = ts->rise;
 | |
|     currto->underlinewidth = ts->ulw;
 | |
|     currto->underlineposition = ts->ulp;
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_set_tstate(PDF *p, pdc_scalar value, pdf_text_optflags tflag)
 | |
| {
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     pdf_tstate *ts = &ppt->tstate[ppt->sl];
 | |
|     pdf_text_options *currto = ppt->currto;
 | |
|     int ivalue = (int) value;
 | |
|     pdc_scalar prevvalue;
 | |
| 
 | |
|     /* text state parameter values can never be percentages */
 | |
| 
 | |
|     switch (tflag)
 | |
|     {
 | |
|         case to_font:
 | |
|         pdf_check_handle(p, ivalue, pdc_fonthandle);
 | |
|         prevvalue = ts->font;
 | |
|         ts->font = currto->font = ivalue;
 | |
|         break;
 | |
| 
 | |
|         case to_textrendering:
 | |
|         if (ivalue < 0 || ivalue > PDF_LAST_TRMODE)
 | |
|             pdc_error(p->pdc, PDC_E_ILLARG_INT,
 | |
|                 "textrendering", pdc_errprintf(p->pdc, "%d", ivalue),
 | |
|                 0, 0);
 | |
|         prevvalue = ts->trm;
 | |
|         ts->trm = currto->textrendering = ivalue;
 | |
|         break;
 | |
| 
 | |
|         case to_fontsize:
 | |
|         pdc_check_number_zero(p->pdc, "fontsize", value);
 | |
|         prevvalue = ts->fs;
 | |
|         ts->ld = currto->leading = value;
 | |
|         if (!PDC_FLOAT_ISNULL(value - prevvalue))
 | |
|             currto->mask |= (1 << to_leading);
 | |
|         prevvalue = ts->fs;
 | |
|         ts->fs = currto->fontsize = value;
 | |
|         break;
 | |
| 
 | |
|         case to_leading:
 | |
|         prevvalue = ts->ld;
 | |
|         ts->ld = currto->leading = value;
 | |
|         break;
 | |
| 
 | |
|         case to_charspacing:
 | |
|         prevvalue = ts->cs;
 | |
|         ts->cs = currto->charspacing = value;
 | |
|         break;
 | |
| 
 | |
|         case to_wordspacing:
 | |
|         prevvalue = ts->ws;
 | |
|         ts->ws = currto->wordspacing = value;
 | |
|         break;
 | |
| 
 | |
|         case to_underlinewidth:
 | |
|         prevvalue = ts->ulw;
 | |
|         ts->ulw = currto->underlinewidth = value;
 | |
|         break;
 | |
| 
 | |
|         case to_underlineposition:
 | |
|         prevvalue = ts->ulp;
 | |
|         ts->ulp = currto->underlineposition = value;
 | |
|         break;
 | |
| 
 | |
|         case to_horizscaling:
 | |
|         pdc_check_number_zero(p->pdc, "horizscaling", value);
 | |
|         prevvalue = ts->hs;
 | |
|         ts->hs = currto->horizscaling = value;
 | |
|         break;
 | |
| 
 | |
|         case to_italicangle:
 | |
|         pdc_check_number_limits(p->pdc, "italicangle", value,
 | |
|                                 -90 + PDC_FLOAT_PREC, 90 + PDC_FLOAT_MAX);
 | |
|         prevvalue = ts->ia;
 | |
|         ts->ia = currto->italicangle = value;
 | |
|         break;
 | |
| 
 | |
|         case to_textrise:
 | |
|         prevvalue = ts->rise;
 | |
|         ts->rise = currto->textrise = value;
 | |
|         break;
 | |
| 
 | |
| 
 | |
|         case to_overline:
 | |
|         currto->overline = (pdc_bool) ivalue;
 | |
|         return;
 | |
| 
 | |
|         case to_strikeout:
 | |
|         currto->strikeout = (pdc_bool) ivalue;
 | |
|         return;
 | |
| 
 | |
|         case to_underline:
 | |
|         currto->underline = (pdc_bool) ivalue;
 | |
|         return;
 | |
| 
 | |
|         case to_textformat:
 | |
|         currto->textformat = (pdc_text_format) ivalue;
 | |
|         return;
 | |
| 
 | |
|         case to_charref:
 | |
|         currto->charref = (pdc_bool) ivalue;
 | |
|         return;
 | |
| 
 | |
|         case to_glyphwarning:
 | |
|         currto->glyphwarning = (pdc_bool) ivalue;
 | |
|         return;
 | |
| 
 | |
|         default:
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (!PDC_FLOAT_ISNULL(value - prevvalue))
 | |
|         currto->mask |= (1 << tflag);
 | |
|     ts->mask = currto->mask;
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf__setfont(PDF *p, int font, pdc_scalar fontsize)
 | |
| {
 | |
|     pdf_set_tstate(p, (pdc_scalar) font, to_font);
 | |
|     pdf_set_tstate(p, fontsize, to_fontsize);
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf__set_text_pos(PDF *p, pdc_scalar x, pdc_scalar y)
 | |
| {
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     pdf_tstate *ts = &ppt->tstate[ppt->sl];
 | |
| 
 | |
|     pdc_check_number(p->pdc, "x", x);
 | |
|     pdc_check_number(p->pdc, "y", y);
 | |
| 
 | |
|     ts->newpos = pdc_true;
 | |
|     ts->currtx = x;
 | |
|     ts->currty = y;
 | |
|     ts->prevtx = ts->refptx;
 | |
|     ts->prevty = ts->refpty;
 | |
|     ts->linetx = x;
 | |
| }
 | |
| 
 | |
| double
 | |
| pdf_get_tstate(PDF *p, pdf_text_optflags tflag)
 | |
| {
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     pdf_text_options *currto = ppt->currto;
 | |
| 
 | |
|     switch (tflag)
 | |
|     {
 | |
|         case to_font:
 | |
|         return (double) currto->font;
 | |
| 
 | |
|         case to_textrendering:
 | |
|         return (double) currto->textrendering;
 | |
| 
 | |
|         case to_fontsize:
 | |
|         return (double) currto->fontsize;
 | |
| 
 | |
|         case to_leading:
 | |
|         return (double) currto->leading;
 | |
| 
 | |
|         case to_charspacing:
 | |
|         return (double) currto->charspacing;
 | |
| 
 | |
|         case to_wordspacing:
 | |
|         return (double) currto->wordspacing;
 | |
| 
 | |
|         case to_horizscaling:
 | |
|         return (double) currto->horizscaling;
 | |
| 
 | |
|         case to_italicangle:
 | |
|         return (double) currto->italicangle;
 | |
| 
 | |
|         case to_textrise:
 | |
|         return (double) currto->textrise;
 | |
| 
 | |
|         case to_underlinewidth:
 | |
|         return (double) currto->underlinewidth;
 | |
| 
 | |
|         case to_underlineposition:
 | |
|         return (double) currto->underlineposition;
 | |
| 
 | |
| 
 | |
|         case to_overline:
 | |
|         return (double) currto->overline;
 | |
| 
 | |
|         case to_strikeout:
 | |
|         return (double) currto->strikeout;
 | |
| 
 | |
|         case to_underline:
 | |
|         return (double) currto->underline;
 | |
| 
 | |
|         case to_textx:
 | |
|         return (double) ppt->tstate[ppt->sl].currtx;
 | |
| 
 | |
|         case to_texty:
 | |
|         return (double) ppt->tstate[ppt->sl].currty;
 | |
| 
 | |
|         default:
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| pdf_get_font(PDF *p)
 | |
| {
 | |
|     if (p->curr_ppt)
 | |
|         return (int) pdf_get_tstate(p, to_font);
 | |
|     return -1;
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_init_text_options(PDF *p, pdf_text_options *to)
 | |
| {
 | |
|     to->mask = 0;
 | |
|     to->pcmask = 0;
 | |
|     to->font = -1;
 | |
|     to->fontsize = 0;
 | |
|     to->fontset = 0;
 | |
|     to->leading = 0;
 | |
|     to->leading_pc = 0;
 | |
|     to->textrendering = 0;
 | |
|     to->charspacing = 0;
 | |
|     to->charspacing_pc = 0;
 | |
|     to->horizscaling = 1;
 | |
|     to->italicangle = 0;
 | |
|     to->textrise = 0;
 | |
|     to->textrise_pc = 0;
 | |
|     to->wordspacing = 0;
 | |
|     to->wordspacing_pc = 0;
 | |
|     to->underlinewidth = PDF_UNDERLINEWIDTH_AUTO;
 | |
|     to->underlineposition = PDF_UNDERLINEPOSITION_AUTO;
 | |
|     to->overline = pdc_false;
 | |
|     to->strikeout = pdc_false;
 | |
|     to->underline = pdc_false;
 | |
|     to->text = NULL;
 | |
|     to->textlen = 0;
 | |
|     to->textformat = p->textformat;
 | |
|     to->charref = p->charref;
 | |
|     to->glyphwarning = p->debug[(int) 'g'];
 | |
|     pdf_init_coloropt(&to->fillcolor);
 | |
|     pdf_init_coloropt(&to->strokecolor);
 | |
|     to->strokewidth = PDF_UNDERLINEWIDTH_AUTO;
 | |
|     to->dasharray[0] = 0;
 | |
|     to->dasharray[1] = 0;
 | |
|     to->xadvancelist = NULL;
 | |
|     to->nglyphs = 0;
 | |
|     to->link = NULL;
 | |
| }
 | |
| 
 | |
| static pdf_text_optflags pdf_toptflags[] =
 | |
| {
 | |
|     to_font, to_fontsize, to_textrendering, to_charspacing,
 | |
|     to_horizscaling, to_italicangle, to_wordspacing, to_textrise
 | |
| };
 | |
| 
 | |
| void
 | |
| pdf_calculate_text_options(pdf_text_options *to, pdc_bool force,
 | |
|                            pdc_scalar fontscale)
 | |
| {
 | |
|     if (to->mask & (1 << to_fontsize) || force)
 | |
|     {
 | |
|         to->fontsize *= fontscale;
 | |
|     }
 | |
| 
 | |
|     if ((to->mask & (1 << to_charspacing) || force) &&
 | |
|         (to->pcmask & (1 << to_charspacing)))
 | |
|     {
 | |
|         to->charspacing = to->charspacing_pc * to->fontsize;
 | |
|     }
 | |
| 
 | |
|     if ((to->mask & (1 << to_wordspacing) || force) &&
 | |
|         (to->pcmask & (1 << to_wordspacing)))
 | |
|     {
 | |
|         to->wordspacing = to->wordspacing_pc * to->fontsize;
 | |
|     }
 | |
| 
 | |
|     if ((to->mask & (1 << to_textrise) || force) &&
 | |
|         (to->pcmask & (1 << to_textrise)))
 | |
|     {
 | |
|         to->textrise = to->textrise_pc * to->fontsize;
 | |
|     }
 | |
| 
 | |
|     /* maybe used in a future version */
 | |
|     if ((to->mask & (1 << to_leading) || force) &&
 | |
|         (to->pcmask & (1 << to_leading)))
 | |
|     {
 | |
|         to->leading = to->leading_pc * to->fontsize;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_set_text_options(PDF *p, pdf_text_options *to)
 | |
| {
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     pdf_text_options *currto = p->curr_ppt->currto;
 | |
|     pdf_tstate *ts = &ppt->tstate[ppt->sl];
 | |
|     pdf_text_optflags tflag;
 | |
|     int i, n;
 | |
| 
 | |
|     /* we synchronize both text state and text options */
 | |
| 
 | |
|     n = sizeof(pdf_toptflags) / sizeof(pdf_text_optflags);
 | |
|     for (i = 0; i < n; i++)
 | |
|     {
 | |
|         tflag = pdf_toptflags[i];
 | |
|         if (to->mask & (1 << tflag))
 | |
|         {
 | |
|             switch (tflag)
 | |
|             {
 | |
|                 case to_font:
 | |
|                 if (!(currto->mask & (1 << tflag)) &&
 | |
|                     to->font == currto->font)
 | |
|                     break;
 | |
|                 ts->font = currto->font = to->font;
 | |
|                 continue;
 | |
| 
 | |
|                 case to_fontsize:
 | |
|                 if (!(currto->mask & (1 << tflag)) &&
 | |
|                     PDC_FLOAT_ISNULL(to->fontsize - currto->fontsize))
 | |
|                     break;
 | |
|                 ts->fs = currto->fontsize = to->fontsize;
 | |
|                 continue;
 | |
| 
 | |
|                 case to_textrendering:
 | |
|                 if (!(currto->mask & (1 << tflag)) &&
 | |
|                     to->textrendering == currto->textrendering)
 | |
|                     break;
 | |
|                 ts->trm = currto->textrendering = to->textrendering;
 | |
|                 continue;
 | |
| 
 | |
|                 /* to->leading is never used */
 | |
| 
 | |
|                 case to_charspacing:
 | |
|                 if (!(currto->mask & (1 << tflag)) &&
 | |
|                     PDC_FLOAT_ISNULL(to->charspacing - currto->charspacing))
 | |
|                     break;
 | |
|                 ts->cs = currto->charspacing = to->charspacing;
 | |
|                 continue;
 | |
| 
 | |
|                 case to_horizscaling:
 | |
|                 if (!(currto->mask & (1 << tflag)) &&
 | |
|                     PDC_FLOAT_ISNULL(to->horizscaling - currto->horizscaling))
 | |
|                     break;
 | |
|                 ts->hs = currto->horizscaling = to->horizscaling;
 | |
|                 continue;
 | |
| 
 | |
|                 case to_italicangle:
 | |
|                 if (!(currto->mask & (1 << tflag)) &&
 | |
|                     PDC_FLOAT_ISNULL(to->italicangle - currto->italicangle))
 | |
|                     break;
 | |
|                 ts->ia = currto->italicangle = to->italicangle;
 | |
|                 continue;
 | |
| 
 | |
|                 case to_wordspacing:
 | |
|                 if (!(currto->mask & (1 << tflag)) &&
 | |
|                     PDC_FLOAT_ISNULL(to->wordspacing - currto->wordspacing))
 | |
|                     break;
 | |
|                 ts->ws = currto->wordspacing = to->wordspacing;
 | |
|                 continue;
 | |
| 
 | |
|                 case to_textrise:
 | |
|                 if (!(currto->mask & (1 << tflag)) &&
 | |
|                     PDC_FLOAT_ISNULL(to->textrise - currto->textrise))
 | |
|                     break;
 | |
|                 ts->rise = currto->textrise = to->textrise;
 | |
|                 continue;
 | |
| 
 | |
|                 case to_underlinewidth:
 | |
|                 if (!(currto->mask & (1 << tflag)) &&
 | |
|                     PDC_FLOAT_ISNULL(to->underlinewidth -
 | |
|                                      currto->underlinewidth))
 | |
|                     break;
 | |
|                 ts->ulw = currto->underlinewidth = to->underlinewidth;
 | |
|                 continue;
 | |
| 
 | |
|                 case to_underlineposition:
 | |
|                 if (!(currto->mask & (1 << tflag)) &&
 | |
|                     PDC_FLOAT_ISNULL(to->underlineposition -
 | |
|                                      currto->underlineposition))
 | |
|                     break;
 | |
|                 ts->ulp = currto->underlineposition = to->underlineposition;
 | |
|                 continue;
 | |
| 
 | |
|                 default:
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             to->mask &= ~(1 << tflag);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     ts->mask = currto->mask = to->mask;
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_get_text_options(PDF *p, pdf_text_options *to, pdc_resopt *resopts)
 | |
| {
 | |
|     char **strlist;
 | |
|     int inum;
 | |
| 
 | |
|     if (pdc_get_optvalues("font", resopts, &to->font, NULL))
 | |
|     {
 | |
|         to->mask |= (1L << to_font);
 | |
|         to->fontset |= (1L << to_font);
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("fontsize", resopts, &to->fontsize, NULL))
 | |
|     {
 | |
|         to->mask |= (1L << to_fontsize);
 | |
|         to->fontset |= (1L << to_fontsize);
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("charref", resopts, &to->charref, NULL))
 | |
|         to->mask |= (1L << to_charref);
 | |
| 
 | |
|     if (pdc_get_optvalues("glyphwarning", resopts, &to->glyphwarning, NULL))
 | |
|         to->mask |= (1L << to_glyphwarning);
 | |
| 
 | |
|     if (pdc_get_optvalues("charspacing", resopts, &to->charspacing, NULL))
 | |
|     {
 | |
|         if (pdc_is_lastopt_percent(resopts, 0))
 | |
|         {
 | |
|             to->pcmask |= (1 << to_charspacing);
 | |
|             to->charspacing_pc = to->charspacing;
 | |
|         }
 | |
|         else
 | |
|             to->pcmask &= ~(1 << to_charspacing);
 | |
|         to->mask |= (1L << to_charspacing);
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("horizscaling", resopts, &to->horizscaling, NULL))
 | |
|     {
 | |
|         if (!pdc_is_lastopt_percent(resopts, 0))
 | |
|             to->horizscaling /= 100.0;
 | |
|         to->mask |= (1L << to_horizscaling);
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("italicangle", resopts, &to->italicangle, NULL))
 | |
|         to->mask |= (1L << to_italicangle);
 | |
| 
 | |
| 
 | |
|     if (pdc_get_optvalues("overline", resopts, &to->overline, NULL))
 | |
|         to->mask |= (1L << to_overline);
 | |
| 
 | |
|     if (pdc_get_optvalues("strikeout", resopts, &to->strikeout, NULL))
 | |
|         to->mask |= (1L << to_strikeout);
 | |
| 
 | |
|     if (pdc_get_optvalues("textformat", resopts, &inum, NULL))
 | |
|     {
 | |
|         to->textformat = (pdc_text_format) inum;
 | |
|         to->mask |= (1L << to_textformat);
 | |
|         pdf_check_textformat(p, to->textformat);
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("textrendering", resopts, &to->textrendering, NULL))
 | |
|         to->mask |= (1L << to_textrendering);
 | |
| 
 | |
|     if (pdc_get_optvalues("textrise", resopts, &to->textrise, NULL))
 | |
|     {
 | |
|         if (pdc_is_lastopt_percent(resopts, 0))
 | |
|         {
 | |
|             to->pcmask |= (1 << to_textrise);
 | |
|             to->textrise_pc = to->textrise;
 | |
|         }
 | |
|         else
 | |
|             to->pcmask &= ~(1 << to_textrise);
 | |
|         to->mask |= (1L << to_textrise);
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("underline", resopts, &to->underline, NULL))
 | |
|         to->mask |= (1L << to_underline);
 | |
| 
 | |
|     if (pdc_get_optvalues("wordspacing", resopts, &to->wordspacing, NULL))
 | |
|     {
 | |
|         if (pdc_is_lastopt_percent(resopts, 0))
 | |
|         {
 | |
|             to->pcmask |= (1 << to_wordspacing);
 | |
|             to->wordspacing_pc = to->wordspacing;
 | |
|         }
 | |
|         else
 | |
|             to->pcmask &= ~(1 << to_wordspacing);
 | |
|         to->mask |= (1L << to_wordspacing);
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("underlinewidth", resopts, &to->underlinewidth, NULL))
 | |
|     {
 | |
|         if (pdc_is_lastopt_percent(resopts, 0))
 | |
|         {
 | |
|             to->pcmask |= (1 << to_underlinewidth);
 | |
|         }
 | |
|         else
 | |
|             to->pcmask &= ~(1 << to_underlinewidth);
 | |
|         to->mask |= (1L << to_underlinewidth);
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("underlineposition", resopts,
 | |
|                           &to->underlineposition, NULL))
 | |
|     {
 | |
|         if (pdc_is_lastopt_percent(resopts, 0))
 | |
|         {
 | |
|             to->pcmask |= (1 << to_underlineposition);
 | |
|         }
 | |
|         else
 | |
|             to->pcmask &= ~(1 << to_underlineposition);
 | |
|         to->mask |= (1L << to_underlineposition);
 | |
|     }
 | |
| 
 | |
|     inum = pdc_get_optvalues("fillcolor", resopts, NULL, &strlist);
 | |
|     if (inum)
 | |
|     {
 | |
|         pdf_parse_coloropt(p, "fillcolor", strlist, inum, (int) color_lab,
 | |
|                            &to->fillcolor);
 | |
|         to->mask |= (1L << to_fillcolor);
 | |
|     }
 | |
| 
 | |
|     inum = pdc_get_optvalues("strokecolor", resopts, NULL, &strlist);
 | |
|     if (inum)
 | |
|     {
 | |
|         pdf_parse_coloropt(p, "strokecolor", strlist, inum, (int) color_lab,
 | |
|                            &to->strokecolor);
 | |
|         to->mask |= (1L << to_strokecolor);
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("strokewidth", resopts, &to->strokewidth, NULL))
 | |
|     {
 | |
|         if (pdc_is_lastopt_percent(resopts, 0))
 | |
|         {
 | |
|             to->pcmask |= (1 << to_strokewidth);
 | |
|         }
 | |
|         else
 | |
|             to->pcmask &= ~(1 << to_strokewidth);
 | |
|         to->mask |= (1L << to_strokewidth);
 | |
|     }
 | |
| 
 | |
|     inum = pdc_get_optvalues("dasharray", resopts, to->dasharray, NULL);
 | |
|     if (inum)
 | |
|     {
 | |
|         if (inum == 1)
 | |
|             to->dasharray[1] = to->dasharray[0];
 | |
|         to->mask |= (1L << to_dasharray);
 | |
|     }
 | |
| 
 | |
|     inum = pdc_get_optvalues("xadvancelist", resopts, NULL, &strlist);
 | |
|     if (inum)
 | |
|     {
 | |
|         to->xadvancelist = (pdc_scalar *) strlist;
 | |
|         to->nglyphs = inum;
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("weblink", resopts, NULL, &strlist))
 | |
|     {
 | |
|         to->link = strlist[0];
 | |
|         to->linktype = "URI";
 | |
|     }
 | |
|     else if (pdc_get_optvalues("locallink", resopts, NULL, &strlist))
 | |
|     {
 | |
|         to->link = strlist[0];
 | |
|         to->linktype = "GoTo";
 | |
|     }
 | |
|     else if (pdc_get_optvalues("pdflink", resopts, NULL, &strlist))
 | |
|     {
 | |
|         to->link = strlist[0];
 | |
|         to->linktype = "GoToR";
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* ------------------------ Text object functions -------------------------- */
 | |
| 
 | |
| static void
 | |
| pdf_begin_text(PDF *p)
 | |
| {
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     pdf_tstate *ts = &ppt->tstate[ppt->sl];
 | |
|     pdf_text_options *currto = ppt->currto;
 | |
| 
 | |
|     /* end text object if italicangle changed */
 | |
|     if (currto->mask & (1L << to_italicangle))
 | |
|         pdf_end_text(p);
 | |
| 
 | |
|     /* begin text object */
 | |
|     if (!p->in_text)
 | |
|     {
 | |
|         p->in_text = pdc_true;
 | |
|         pdc_puts(p->out, "BT\n");
 | |
|     }
 | |
| 
 | |
|     if (PDF_FORCE_OUTPUT() && ts->glyphinit == pdc_undef)
 | |
|         ts->glyphinit = pdc_false;
 | |
| 
 | |
|     if ((currto->mask & (1L << to_font)) ||
 | |
|         (currto->mask & (1L << to_fontsize)) || !ts->glyphinit)
 | |
|     {
 | |
|         pdc_printf(p->out, "/F%d %f Tf\n",
 | |
|             currto->font, p->ydirection * currto->fontsize);
 | |
| 
 | |
|         p->fonts[currto->font].used_in_current_doc = pdc_true;
 | |
|         p->fonts[currto->font].used_on_current_page = pdc_true;
 | |
|     }
 | |
| 
 | |
|     if (currto->mask & (1L << to_textrendering) || !ts->glyphinit)
 | |
|         pdc_printf(p->out, "%d Tr\n", currto->textrendering);
 | |
| 
 | |
|     if (currto->mask & (1L << to_leading) || !ts->glyphinit)
 | |
|         pdc_printf(p->out, "%f TL\n", p->ydirection * currto->leading);
 | |
| 
 | |
|     if (currto->mask & (1L << to_charspacing) || !ts->glyphinit)
 | |
|         pdc_printf(p->out, "%f Tc\n", p->ydirection * currto->charspacing);
 | |
| 
 | |
|     if (!ts->hsinit || currto->mask & (1L << to_horizscaling) || !ts->glyphinit)
 | |
|         pdc_printf(p->out, "%f Tz\n",
 | |
|                    100 * p->ydirection * currto->horizscaling);
 | |
| 
 | |
|     if (currto->mask & (1L << to_textrise) || !ts->glyphinit)
 | |
|        pdc_printf(p->out, "%f Ts\n", p->ydirection * currto->textrise);
 | |
| 
 | |
|     /* initialize */
 | |
|     if (!ts->glyphinit)
 | |
|         ts->glyphinit = pdc_true;
 | |
|     ts->hsinit = pdc_true;
 | |
|     ts->mask = currto->mask = 0;
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_end_text(PDF *p)
 | |
| {
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     pdf_tstate *ts = &ppt->tstate[ppt->sl];
 | |
| 
 | |
|     if (p->in_text)
 | |
|     {
 | |
|         p->in_text = pdc_false;
 | |
|         pdc_puts(p->out, "ET\n");
 | |
| 
 | |
|         ts->newpos = pdc_false;
 | |
|         ts->prevtx = 0;
 | |
|         ts->prevty = 0;
 | |
|         ts->refptx = 0;
 | |
|         ts->refpty = 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_reset_tstate(PDF *p)
 | |
| {
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     pdf_tstate *ts = &ppt->tstate[ppt->sl];
 | |
| 
 | |
|     pdf_set_tstate(p, 0, to_textrendering);
 | |
|     pdf_set_tstate(p, 0, to_leading);
 | |
|     pdf_set_tstate(p, 0, to_charspacing);
 | |
|     pdf_set_tstate(p, 0, to_wordspacing);
 | |
|     pdf_set_tstate(p, 1, to_horizscaling);
 | |
|     pdf_set_tstate(p, 0, to_italicangle);
 | |
|     pdf_set_tstate(p, 0, to_textrise);
 | |
|     pdf_set_tstate(p, PDF_UNDERLINEWIDTH_AUTO, to_underlinewidth);
 | |
|     pdf_set_tstate(p, PDF_UNDERLINEPOSITION_AUTO, to_underlineposition);
 | |
| 
 | |
|     ts->hsinit = (p->ydirection == -1) ? pdc_false : pdc_true;
 | |
|     if (ts->mask || !ts->hsinit)
 | |
|     {
 | |
|         pdc_scalar ydirection = p->ydirection;
 | |
|         p->ydirection = 1;
 | |
|         pdf_begin_text(p);
 | |
|         pdf_end_text(p);
 | |
|         p->ydirection = ydirection;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ------------------- Text string checking function ---------------------- */
 | |
| 
 | |
| pdc_bool
 | |
| pdf_check_textchar(PDF *p, pdc_ushort *o_uv, int flags, pdf_text_options *to)
 | |
| {
 | |
|     pdc_font *currfont = &p->fonts[to->font];
 | |
|     pdc_ushort uv = *o_uv;
 | |
|     pdc_bool isnew = pdc_false;
 | |
| 
 | |
|     switch(currfont->encoding)
 | |
|     {
 | |
|         case pdc_builtin:
 | |
|         {
 | |
|             if (uv > 0x00FF)
 | |
|             {
 | |
|                 if (to->glyphwarning == pdc_true && !(flags & PDF_KEEP_UNICODE))
 | |
|                     pdc_warning(p->pdc, PDF_E_TEXT_BUILTINNOTSHOW,
 | |
|                                 pdc_errprintf(p->pdc, "0x%04X", uv), 0, 0, 0);
 | |
|                 uv = 0;
 | |
|                 isnew = pdc_true;
 | |
|             }
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|         case pdc_unicode:
 | |
|         {
 | |
|             pdc_ushort gid;
 | |
| 
 | |
|             /* check Glyph-ID */
 | |
|             gid = currfont->code2GID[uv];
 | |
|             if (!gid)
 | |
|             {
 | |
|                 pdc_ushort uvm =
 | |
|                     pdc_get_alter_glyphname(uv, currfont->missingglyphs, NULL);
 | |
|                 if (uvm != uv)
 | |
|                 {
 | |
|                     gid = currfont->code2GID[uvm];
 | |
|                     if (!(flags & PDF_KEEP_UNICODE))
 | |
|                         uv = uvm;
 | |
|                 }
 | |
|                 if (!gid)
 | |
|                 {
 | |
|                     if (to->glyphwarning == pdc_true &&
 | |
|                         !(flags & PDF_KEEP_UNICODE))
 | |
|                         pdc_warning(p->pdc, PDF_E_TEXT_UNICODENOTSHOW,
 | |
|                             pdc_errprintf(p->pdc, "%04X", uv), 0, 0, 0);
 | |
|                     uv = pdc_get_equi_unicode(uv);
 | |
|                     if (!uv) uv = PDC_UNICODE_NBSP;
 | |
|                     gid = currfont->code2GID[(int)uv];
 | |
|                 }
 | |
|                 isnew = (flags & PDF_KEEP_UNICODE) ? pdc_false : pdc_true;
 | |
|             }
 | |
| 
 | |
|             /* generate 8-bit code */
 | |
|             if (currfont->lastCode > -1 && !currfont->GID2code[gid])
 | |
|             {
 | |
|                 if (currfont->lastCode == 255)
 | |
|                 {
 | |
|                     if (to->glyphwarning == pdc_true)
 | |
|                         pdc_warning(p->pdc, PDF_E_TEXT_TOOMANYCODES,
 | |
|                                     0, 0, 0, 0);
 | |
|                     uv = PDC_UNICODE_SPACE;
 | |
|                     isnew = pdc_true;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     currfont->lastCode++;
 | |
|                     currfont->GID2code[gid] = (pdc_ushort) currfont->lastCode;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|         case pdc_glyphid:
 | |
|         {
 | |
|             if (uv >= (pdc_ushort) currfont->numOfCodes)
 | |
|             {
 | |
|                 if (to->glyphwarning == pdc_true)
 | |
|                     pdc_warning(p->pdc, PDF_E_TEXT_GLYPHIDNOTSHOW,
 | |
|                             pdc_errprintf(p->pdc, "%d", uv), 0, 0, 0);
 | |
|                 uv = 0;
 | |
|                 isnew = pdc_true;
 | |
|             }
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|         default:
 | |
|         {
 | |
|             if (currfont->encoding >= 0)
 | |
|             {
 | |
|                 pdc_encodingvector *ev =
 | |
|                     pdf_get_encoding_vector(p, currfont->encoding);
 | |
| 
 | |
|                 int i = pdc_get_encoding_bytecode(p->pdc, ev, uv);
 | |
|                 if (i < 0 ||
 | |
|                     (currfont->code2GID != NULL && !currfont->code2GID[i]))
 | |
|                 {
 | |
|                     if (to->glyphwarning == pdc_true)
 | |
|                         pdc_warning(p->pdc, PDF_E_TEXT_UNICODENOTSHOW,
 | |
|                             pdc_errprintf(p->pdc, "%04X", uv), 0, 0, 0);
 | |
|                     i = pdc_get_encoding_bytecode(p->pdc, ev, PDC_UNICODE_NBSP);
 | |
|                     if (i < 0)
 | |
|                         i = currfont->spacechar;
 | |
|                 }
 | |
|                 uv = (pdc_ushort) i;
 | |
|                 isnew = pdc_true;
 | |
|             }
 | |
|         }
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     *o_uv = uv;
 | |
|     return isnew;
 | |
| }
 | |
| 
 | |
| pdc_text_format
 | |
| pdf_get_autotextformat(pdc_font *font, pdf_text_options *to)
 | |
| {
 | |
|     pdc_bool sizebyte = (font->codeSize <= 1 && !font->unibyte);
 | |
| 
 | |
|     if (to->textformat == pdc_auto && sizebyte)
 | |
|         return pdc_bytes;
 | |
|     else if (to->textformat == pdc_auto2 && sizebyte)
 | |
|         return pdc_bytes2;
 | |
|     return to->textformat;
 | |
| }
 | |
| 
 | |
| /* Converts and checks input text string.
 | |
|  *
 | |
|  * The function returns a pointer to an allocated temporary memory
 | |
|  * (pdc_malloc_tmp, pdc_free_tmp) containing the converted string
 | |
|  * if flag PDF_USE_TMPALLOC is set.
 | |
|  *
 | |
|  * If return value is NULL error was occurred.
 | |
|  */
 | |
| 
 | |
| pdc_byte *
 | |
| pdf_check_textstring(PDF *p, const char *text, int len, int flags,
 | |
|                      pdf_text_options *to, int *outlen, int *outcharlen)
 | |
| {
 | |
| 
 | |
|     pdc_font *currfont = &p->fonts[to->font];
 | |
|     pdc_encoding enc = currfont->encoding;
 | |
|     pdc_encodingvector *ev = pdf_get_encoding_vector(p, enc);
 | |
|     pdc_encodingvector *inev = NULL;
 | |
|     pdc_encodingvector *outev = NULL;
 | |
| 
 | |
|     pdc_byte *outtext;
 | |
|     pdc_text_format textformat, targettextformat;
 | |
|     int convflags = PDC_CONV_NOBOM;
 | |
|     int maxlen, charlen = 1;
 | |
| 
 | |
|     textformat = pdf_get_autotextformat(currfont, to);
 | |
|     targettextformat = pdc_utf16;
 | |
| 
 | |
|     if (flags & PDF_KEEP_UNICODE)
 | |
|         convflags |= PDC_CONV_NEWALLOC;
 | |
| 
 | |
|     if (flags & PDF_KEEP_UNICODE)
 | |
|         inev = ev;
 | |
|     else
 | |
|         convflags |= PDC_CONV_KEEPBYTES;
 | |
| 
 | |
|     if (flags & PDF_USE_TMPALLOC)
 | |
|         convflags |= PDC_CONV_TMPALLOC;
 | |
| 
 | |
| 
 | |
|     /* convert to 8-bit or UTF-16 text string */
 | |
|     pdc_convert_string(p->pdc, textformat, currfont->codepage, inev,
 | |
|                        (pdc_byte *)text, len,
 | |
|                        &targettextformat, outev, &outtext, outlen,
 | |
|                        convflags, to->glyphwarning);
 | |
| 
 | |
|     /* check text string */
 | |
|     if (outtext && *outlen)
 | |
|     {
 | |
| 
 | |
|         /* 2 byte storage length of a character */
 | |
|         if (targettextformat == pdc_utf16)
 | |
|             charlen = 2;
 | |
| 
 | |
|         /* Maximal text string length - found out emprirically! */
 | |
|         maxlen = (currfont->codeSize == 1) ? PDF_MAXARRAYSIZE : PDF_MAXDICTSIZE;
 | |
|         if (!(flags & PDF_KEEP_TEXTLEN) && *outlen > maxlen)
 | |
|         {
 | |
|             if (to->glyphwarning)
 | |
|                 pdc_warning(p->pdc, PDF_E_TEXT_TOOLONG,
 | |
|                     pdc_errprintf(p->pdc, "%d", maxlen), 0, 0, 0);
 | |
|             *outlen = maxlen;
 | |
|         }
 | |
| 
 | |
|     }
 | |
|     *outcharlen = charlen;
 | |
| 
 | |
|     return outtext;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ------------------------ Text widths functions ------------------------ */
 | |
| 
 | |
| /* Calculates the geometrical width of input text string depending on
 | |
|  *
 | |
|  *      to->font, to->fontsize, to->kerning,
 | |
|  *      to->charspacing, to->horizscaling, to->wordspacing,
 | |
|  *      to->xadvancelist
 | |
|  */
 | |
| 
 | |
| pdc_scalar
 | |
| pdf_calculate_textwidth(PDF *p, const pdc_byte *text, int len, int charlen,
 | |
|                         pdf_text_options *to)
 | |
| {
 | |
|     pdc_font *currfont = &p->fonts[to->font];
 | |
|     pdc_ushort uv;
 | |
|     pdc_ushort *ustext = (pdc_ushort *) text;
 | |
|     pdc_scalar glwidth = 0, width = 0;
 | |
|     pdc_scalar font2user = to->fontsize / 1000.0;
 | |
|     pdc_scalar charspacing = to->charspacing / font2user;
 | |
|     pdc_scalar wordspacing = to->wordspacing / font2user;
 | |
|     pdc_bool haswidths = (currfont->widths != NULL);
 | |
|     int i;
 | |
| 
 | |
|     /* We cannot handle empty strings and fonts with unknown
 | |
|      * code size - especially CID fonts with no UCS-2 CMap */
 | |
|     if (!len || !currfont->codeSize)
 | |
|         return width;
 | |
| 
 | |
|     for (i = 0; i < len/charlen; i++)
 | |
|     {
 | |
|         if (charlen == 1)
 | |
|             uv = (pdc_ushort) text[i];
 | |
|         else
 | |
|             uv = ustext[i];
 | |
| 
 | |
|         /* start by adding in the width of the character */
 | |
|         if (currfont->monospace)
 | |
|         {
 | |
|             glwidth = (pdc_scalar) currfont->monospace;
 | |
|         }
 | |
|         else if (haswidths)
 | |
|         {
 | |
|             glwidth = (pdc_scalar) currfont->widths[uv];
 | |
|         }
 | |
|         width += glwidth;
 | |
| 
 | |
| 
 | |
|         /* supplied glyph widths */
 | |
|         if (i < to->nglyphs)
 | |
|         {
 | |
|             pdc_scalar shift = to->xadvancelist[i] / font2user - glwidth;
 | |
|             width += shift;
 | |
|             if (p->ptfrun)
 | |
|                 shift = PDC_ROUND(1e10 * shift) / 1e10;
 | |
|             shift = PDC_ROUND(1e1 * shift) / 1e1;
 | |
|             to->xadvancelist[i] = shift;
 | |
|         }
 | |
| 
 | |
|         /* now add the character spacing parameter */
 | |
|         width += charspacing;
 | |
| 
 | |
|         /* take word spacing parameter into account at each blank */
 | |
|         if (wordspacing != 0 && uv == currfont->spacechar)
 | |
|             width += wordspacing;
 | |
|     }
 | |
| 
 | |
|     /* take horizontal scaling factor and font scaling factor into account */
 | |
|     width *= font2user * to->horizscaling;
 | |
| 
 | |
|     return width;
 | |
| }
 | |
| 
 | |
| 
 | |
| pdc_scalar
 | |
| pdf__stringwidth(PDF *p, const char *text, int len, int font,
 | |
|                  pdc_scalar fontsize)
 | |
| {
 | |
|     pdc_byte *utext;
 | |
|     int charlen;
 | |
|     pdc_scalar width = 0;
 | |
|     pdf_text_options to = *p->curr_ppt->currto;
 | |
| 
 | |
|     if (text && len == 0)
 | |
|         len = (int) strlen(text);
 | |
|     if (text == NULL || len <= 0)
 | |
|         return width;
 | |
| 
 | |
|     pdf_check_handle(p, font, pdc_fonthandle);
 | |
| 
 | |
|     pdc_check_number_zero(p->pdc, "fontsize", fontsize);
 | |
| 
 | |
|     /* convert text string */
 | |
|     to.font = font;
 | |
|     to.fontsize = fontsize;
 | |
|     utext = pdf_check_textstring(p, text, len,
 | |
|                                  PDF_KEEP_TEXTLEN | PDF_USE_TMPALLOC,
 | |
|                                  &to, &len, &charlen);
 | |
|     if (utext)
 | |
|         width = pdf_calculate_textwidth(p, utext, len, charlen, &to);
 | |
| 
 | |
|     return width;
 | |
| }
 | |
| 
 | |
| /* ------------------------ Text output functions ------------------------ */
 | |
| 
 | |
| static void
 | |
| pdf_convert_text_towinansi(PDF *p, const pdc_byte *fromtext, int len,
 | |
|                            pdc_byte *totext, pdc_font *currfont)
 | |
| {
 | |
|     pdc_encodingvector *evfrom = pdf_get_encoding_vector(p, currfont->encoding);
 | |
|     pdc_encodingvector *evto = pdf_get_encoding_vector(p, currfont->towinansi);
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < len; i++)
 | |
|         totext[i] = pdc_transform_bytecode(p->pdc, evto, evfrom, fromtext[i]);
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_put_fieldtext(PDF *p, const char *text, int font)
 | |
| {
 | |
|     if (pdc_is_utf8_bytecode(text))
 | |
|     {
 | |
|         pdf_put_hypertext(p, text);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         static const char fn[] = "pdf_put_fieldtext";
 | |
|         pdc_font *currfont = &p->fonts[font];
 | |
|         char *tmpstring = (char *) text;
 | |
|         int len = (int) pdc_strlen(text);
 | |
| 
 | |
|         if (len && currfont->towinansi != pdc_invalidenc &&
 | |
|             !pdc_is_utf16be_unicode(text))
 | |
|         {
 | |
|             /* Convert 8-bit code string to winansi */
 | |
|             tmpstring = (char *) pdc_malloc_tmp(p->pdc,
 | |
|                                                 (size_t) len, fn, NULL, NULL);
 | |
|             pdf_convert_text_towinansi(p, (pdc_byte *) text, len,
 | |
|                                        (pdc_byte *) tmpstring, currfont);
 | |
|         }
 | |
| 
 | |
|         pdc_put_pdfstring(p->out, tmpstring, len);
 | |
|         if (tmpstring != text)
 | |
|             pdc_free_tmp(p->pdc, tmpstring);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| pdf_put_textstring(PDF *p, const pdc_byte *text, int len, int charlen,
 | |
|                    pdc_font *currfont)
 | |
| {
 | |
|     static const char fn[] = "pdf_put_textstring";
 | |
|     pdc_byte *tmpstring = (pdc_byte *) text;
 | |
| 
 | |
|     (void) charlen;
 | |
| 
 | |
|     if (len)
 | |
|     {
 | |
|         if (currfont->towinansi != pdc_invalidenc)
 | |
|         {
 | |
|             /* Convert 8-bit code string to winansi */
 | |
|             tmpstring = (pdc_byte *) pdc_malloc_tmp(p->pdc,
 | |
|                                          (size_t) len, fn, NULL, NULL);
 | |
|             pdf_convert_text_towinansi(p, text, len, tmpstring, currfont);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pdc_put_pdfstring(p->out, (char *) tmpstring, len);
 | |
|     if (tmpstring != text)
 | |
|         pdc_free_tmp(p->pdc, tmpstring);
 | |
| }
 | |
| 
 | |
| static void
 | |
| pdf_put_textstring_shift(PDF *p, pdc_byte *text, int len, int charlen,
 | |
|                          pdf_text_options *to, pdc_scalar spaceshift)
 | |
| {
 | |
|     pdc_font *currfont = &p->fonts[to->font];
 | |
|     pdc_ushort *ustext = (pdc_ushort *) text;
 | |
|     pdc_ushort left, right;
 | |
|     pdc_byte *currtext;
 | |
|     pdc_scalar shift;
 | |
|     int currlen, nchars;
 | |
|     int i;
 | |
| 
 | |
|     currtext = text;
 | |
|     currlen = charlen;
 | |
|     nchars = len/charlen;
 | |
|     for (i = 1; i < nchars; i++)
 | |
|     {
 | |
|         if (charlen == 1)
 | |
|         {
 | |
|             left =  (pdc_ushort) text[i-1];
 | |
|             right = (pdc_ushort) text[i];
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             left =  ustext[i-1];
 | |
|             right = ustext[i];
 | |
|         }
 | |
| 
 | |
|         /* PDF wants the inverse shift amount
 | |
|          * (positive numbers move left, negative move right!) */
 | |
| 
 | |
|         if (spaceshift != 0 && left == currfont->spacechar)
 | |
|             shift = -spaceshift;
 | |
|         else
 | |
|             shift = 0;
 | |
| 
 | |
| 
 | |
|         if (i <= to->nglyphs)
 | |
|             shift -= to->xadvancelist[i-1];
 | |
| 
 | |
|         if (shift)
 | |
|         {
 | |
|             pdf_put_textstring(p, currtext, currlen, charlen, currfont);
 | |
|             pdc_printf(p->out, "%f", shift);
 | |
|             currtext = &text[charlen * i];
 | |
|             currlen = 0;
 | |
|         }
 | |
|         currlen += charlen;
 | |
|     }
 | |
| 
 | |
|     pdf_put_textstring(p, currtext, currlen, charlen, currfont);
 | |
| 
 | |
|     if (to->nglyphs && to->nglyphs >= nchars)
 | |
|         pdc_printf(p->out, "%f", -to->xadvancelist[nchars - 1]);
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /* --------------------- General text placing function --------------------- */
 | |
| 
 | |
| 
 | |
| #define PDF_RENDERMODE_FILLCLIP 4
 | |
| 
 | |
| void
 | |
| pdf_place_text(PDF *p, pdc_byte *text, int len, int charlen,
 | |
|                pdf_text_options *to, pdc_scalar width, pdc_bool cont)
 | |
| {
 | |
|     pdf_tstate *ts = &p->curr_ppt->tstate[p->curr_ppt->sl];
 | |
|     pdc_font *currfont = &p->fonts[to->font];
 | |
|     pdc_scalar dx, dy, tx, ty, spaceshift = 0, leading = 0;
 | |
|     pdc_scalar font2user = to->fontsize / 1000.0;
 | |
|     pdc_scalar linewidth = 0;
 | |
|     pdc_scalar deflinewidth = 0;
 | |
|     pdc_bool hasdeco = to->underline || to->overline || to->strikeout;
 | |
|     pdc_bool takeTJ = pdc_false;
 | |
| 
 | |
|     /* text position */
 | |
|     if (!cont)
 | |
|     {
 | |
|         tx = ts->currtx;
 | |
|         ty = ts->currty;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         leading = p->ydirection * to->leading;
 | |
|         tx = ts->linetx;
 | |
|         ty = ts->currty - leading;
 | |
|     }
 | |
| 
 | |
|     /* default linewidth for underlinewidth and strokewidth */
 | |
|     if (hasdeco || (to->mask & (1 << to_strokewidth)))
 | |
|     {
 | |
|         if (currfont->underlineThickness == 0)
 | |
|             currfont->underlineThickness = 50;
 | |
|         deflinewidth =
 | |
|             fabs(to->horizscaling * font2user * currfont->underlineThickness);
 | |
|     }
 | |
| 
 | |
|     /* fill and stroke color */
 | |
|     if (to->mask & (1 << to_fillcolor))
 | |
|         pdf_set_coloropt(p, (int) pdf_fill, &to->fillcolor);
 | |
|     if (to->mask & (1 << to_strokecolor))
 | |
|         pdf_set_coloropt(p, (int) pdf_stroke, &to->strokecolor);
 | |
| 
 | |
| 
 | |
|     /* stroke width and dasharray for stroked text */
 | |
|     if (to->mask & (1 << to_strokewidth))
 | |
|     {
 | |
|         if (to->strokewidth == PDF_UNDERLINEWIDTH_AUTO)
 | |
|         {
 | |
|             linewidth = deflinewidth;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             linewidth = to->strokewidth;
 | |
|             if ((to->pcmask & (1 << to_strokewidth)))
 | |
|                 linewidth *= fabs(to->fontsize);
 | |
|         }
 | |
|         pdf__setlinewidth(p, linewidth);
 | |
|     }
 | |
|     if (to->mask & (1 << to_dasharray))
 | |
|         pdf__setdash(p, to->dasharray[0], to->dasharray[1]);
 | |
| 
 | |
|     /* text decoration */
 | |
|     if (width && hasdeco)
 | |
|     {
 | |
|         pdc_scalar scale = fabs(to->horizscaling);
 | |
|         pdc_scalar delta_y, fs, trise, lineheight;
 | |
|         pdc_scalar txe = (tx + width);
 | |
|         pdc_scalar lineposition = 0;
 | |
| 
 | |
|         fs = p->ydirection * font2user;
 | |
|         trise = p->ydirection * to->textrise;
 | |
|         lineheight = fs * currfont->ascender;
 | |
|         delta_y = scale * (fs * currfont->underlinePosition + trise);
 | |
| 
 | |
|         pdf__save(p);
 | |
| 
 | |
|         if (to->underlinewidth == PDF_UNDERLINEWIDTH_AUTO)
 | |
|         {
 | |
|             linewidth = deflinewidth;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             linewidth = to->underlinewidth;
 | |
|             if ((to->pcmask & (1 << to_underlinewidth)))
 | |
|                 linewidth *= fabs(to->fontsize);
 | |
|         }
 | |
| 
 | |
|         if (to->underlineposition == PDF_UNDERLINEPOSITION_AUTO)
 | |
|         {
 | |
|             lineposition = delta_y;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             lineposition = p->ydirection * to->underlineposition;
 | |
|             if ((to->pcmask & (1 << to_underlineposition)))
 | |
|                 lineposition *= to->fontsize;
 | |
|         }
 | |
| 
 | |
|         pdf__setlinecap(p, 0);
 | |
|         if (!(to->mask & (1 << to_dasharray)))
 | |
|             pdf__setdash(p, 0, 0);
 | |
| 
 | |
|         if (to->underline)
 | |
|         {
 | |
|             pdf__setlinewidth(p, linewidth);
 | |
|             pdf__moveto(p, tx,  ty + lineposition);
 | |
|             pdf__lineto(p, txe, ty + lineposition);
 | |
|             pdf__stroke(p);
 | |
|         }
 | |
| 
 | |
|         if (to->strikeout)
 | |
|         {
 | |
|             pdf__setlinewidth(p, deflinewidth);
 | |
|             pdf__moveto(p, tx,  ty + lineheight/2 + delta_y);
 | |
|             pdf__lineto(p, txe, ty + lineheight/2 + delta_y);
 | |
|             pdf__stroke(p);
 | |
|         }
 | |
| 
 | |
|         if (to->overline)
 | |
|         {
 | |
|             delta_y = scale * (fs * currfont->underlinePosition - trise);
 | |
| 
 | |
|             pdf__setlinewidth(p, deflinewidth);
 | |
|             pdf__moveto(p, tx,  ty + lineheight - delta_y);
 | |
|             pdf__lineto(p, txe, ty + lineheight - delta_y);
 | |
|             pdf__stroke(p);
 | |
|         }
 | |
| 
 | |
|         pdf__restore(p);
 | |
|     }
 | |
| 
 | |
| 
 | |
| 
 | |
|     /* wordspacing */
 | |
|     if (!PDC_FLOAT_ISNULL(to->wordspacing))
 | |
|     {
 | |
|         spaceshift = to->wordspacing / font2user;
 | |
|         if (p->ptfrun)
 | |
|             spaceshift = PDC_ROUND(1e10 * spaceshift) / 1e10;
 | |
|         spaceshift = PDC_ROUND(1e1 * spaceshift) / 1e1;
 | |
|         takeTJ = PDC_FLOAT_ISNULL(spaceshift) ? pdc_false : pdc_true;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /* supplied glyph widths */
 | |
|     if (!takeTJ)
 | |
|         takeTJ = to->nglyphs;
 | |
| 
 | |
|     /* begin text object */
 | |
|     pdf_begin_text(p);
 | |
| 
 | |
|     /* italic angle - realized by Tm operator */
 | |
|     if (!PDC_FLOAT_ISNULL(to->italicangle))
 | |
|     {
 | |
|         if (!currfont->vertical)
 | |
|         {
 | |
|             pdc_printf(p->out, "1 0 %f 1 %f %f Tm\n",
 | |
|                    tan(-p->ydirection * to->italicangle * PDC_DEG2RAD), tx, ty);
 | |
| 
 | |
|             cont = pdc_false;
 | |
|             ts->newpos = pdc_false;
 | |
|             ts->refptx = tx;
 | |
|             ts->refpty = ty;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             pdc_error(p->pdc, PDF_E_TEXT_ITALUNSUPP, 0, 0, 0, 0);
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         /* components of text displacement vector */
 | |
|         if (!cont)
 | |
|         {
 | |
|             dx = tx - ts->prevtx;
 | |
|             dy = ty - ts->prevty;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             dx = tx - ts->refptx;
 | |
|             dy = ty - ts->refpty + leading;
 | |
|         }
 | |
| 
 | |
|         /* condition for text displacement operator Td */
 | |
|         if (!PDC_FLOAT_ISNULL(dx) || !PDC_FLOAT_ISNULL(dy) ||
 | |
|             ts->newpos || (cont && takeTJ))
 | |
|         {
 | |
|             if (cont)
 | |
|             {
 | |
|                 dy -= leading;
 | |
|                 cont = pdc_false;
 | |
|             }
 | |
|             pdc_printf(p->out, "%f %f Td\n", dx, dy);
 | |
| 
 | |
|             /* new reference position for next line*/
 | |
|             ts->newpos = pdc_false;
 | |
|             ts->refptx = tx;
 | |
|             ts->refpty = ty;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             ts->refpty -= leading;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* show text */
 | |
|     if (!takeTJ)
 | |
|     {
 | |
|         pdf_put_textstring(p, text, len, charlen, currfont);
 | |
|         if (!cont)
 | |
|             pdc_puts(p->out, "Tj\n");
 | |
|         else
 | |
|             pdc_puts(p->out, "'\n");
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         pdc_puts(p->out, "[");
 | |
|         pdf_put_textstring_shift(p, text, len, charlen, to, spaceshift);
 | |
|         pdc_puts(p->out, "]TJ\n");
 | |
|     }
 | |
| 
 | |
|     /* new text position */
 | |
|     ts->currtx = tx + width;
 | |
|     ts->currty = ty;
 | |
|     ts->prevtx = ts->currtx;
 | |
|     ts->prevty = ts->currty;
 | |
| 
 | |
|     if (to->textrendering >= PDF_RENDERMODE_FILLCLIP)
 | |
|         pdf_end_text(p);
 | |
| }
 | |
| 
 | |
| /* --------------------- Simple text showing functions --------------------- */
 | |
| 
 | |
| void
 | |
| pdf__show_text(
 | |
|     PDF *p,
 | |
|     const char *text,
 | |
|     int len,
 | |
|     pdc_bool cont)
 | |
| {
 | |
|     static const char *fn = "pdf__show_text";
 | |
|     pdf_text_options *currto = p->curr_ppt->currto;
 | |
|     pdc_byte *utext = NULL;
 | |
|     int charlen = 1;
 | |
|     pdc_scalar width;
 | |
| 
 | |
|     if (text && len == 0)
 | |
|         len = (int) strlen(text);
 | |
|     if (text == NULL || len <= 0)
 | |
|     {
 | |
|         if (cont)
 | |
|             len = 0;
 | |
|         else
 | |
|             return;
 | |
|     }
 | |
| 
 | |
|     /* no font set */
 | |
|     if (currto->font == -1)
 | |
|         pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0);
 | |
| 
 | |
|     width = 0;
 | |
|     if (len)
 | |
|     {
 | |
|         /* convert text string */
 | |
|         utext = pdf_check_textstring(p, text, len, PDF_USE_TMPALLOC,
 | |
|                                      currto, &len, &charlen);
 | |
| 	if (!utext)
 | |
|             return;
 | |
| 
 | |
|         /* length of text */
 | |
|         width = pdf_calculate_textwidth(p, utext, len, charlen, currto);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         utext = (pdc_byte *) pdc_calloc_tmp(p->pdc, 2, fn, NULL, NULL);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /* place text */
 | |
|     pdf_place_text(p, utext, len, charlen, currto, width, cont);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ---------- Text showing function with explicit glyph widths  ---------- */
 | |
| 
 | |
| void
 | |
| pdf__xshow(PDF *p, const char *text, int len, const pdc_scalar *xadvancelist)
 | |
| {
 | |
|     static const char *fn = "pdf__xshow";
 | |
|     pdf_text_options *currto = p->curr_ppt->currto;
 | |
|     pdc_byte *utext = NULL;
 | |
|     int charlen = 1;
 | |
|     size_t nbytes = 0;
 | |
|     pdc_scalar width;
 | |
| 
 | |
|     if (text && len == 0)
 | |
|         len = (int) strlen(text);
 | |
|     if (text == NULL || !len)
 | |
|         return;
 | |
| 
 | |
|     /* no font set */
 | |
|     if (currto->font == -1)
 | |
|         pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0);
 | |
| 
 | |
|     /* convert text string */
 | |
|     utext = pdf_check_textstring(p, text, len, PDF_USE_TMPALLOC,
 | |
|                                  currto, &len, &charlen);
 | |
|     if (!utext)
 | |
|         return;
 | |
| 
 | |
|     /* allocating glyph widths arrays */
 | |
|     nbytes = (size_t) (len / charlen) * sizeof(pdc_scalar);
 | |
|     currto->xadvancelist = (pdc_scalar *) pdc_malloc_tmp(p->pdc,
 | |
|                                              nbytes, fn, NULL, NULL);
 | |
|     memcpy(currto->xadvancelist, xadvancelist, nbytes);
 | |
|     currto->nglyphs = len / charlen;
 | |
| 
 | |
|     /* length of text */
 | |
|     width = pdf_calculate_textwidth(p, utext, len, charlen, currto);
 | |
| 
 | |
| 
 | |
|     /* place text */
 | |
|     pdf_place_text(p, utext, len, charlen, currto, width, pdc_false);
 | |
| 
 | |
|     currto->xadvancelist = NULL;
 | |
|     currto->nglyphs = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ----------------------- Text fitting function ------------------------ */
 | |
| 
 | |
| void
 | |
| pdf_init_fit_options(PDF *p, pdf_fit_options *fit)
 | |
| {
 | |
|     (void) p;
 | |
| 
 | |
|     fit->boxsize[0] = 0;
 | |
|     fit->boxsize[1] = 0;
 | |
|     fit->flags = 0;
 | |
|     fit->fitmethod = pdc_nofit;
 | |
|     fit->margin[0] = 0;
 | |
|     fit->margin[1] = 0;
 | |
|     fit->mask = 0;
 | |
|     fit->pcmask = 0;
 | |
|     fit->shrinklimit = 0.75;
 | |
|     fit->position[0] = 0;
 | |
|     fit->position[1] = 0;
 | |
|     fit->orientate = 0;
 | |
|     fit->rotate = 0;
 | |
|     fit->refpoint[0] = 0;
 | |
|     fit->refpoint[1] = 0;
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_get_fit_options(PDF *p, pdf_fit_options *fit, pdc_resopt *resopts)
 | |
| {
 | |
|     int inum;
 | |
| 
 | |
|     (void) p;
 | |
| 
 | |
|     if (pdc_get_optvalues("fitmethod", resopts, &inum, NULL))
 | |
|     {
 | |
|         fit->fitmethod = (pdc_fitmethod) inum;
 | |
|         fit->mask |= (1L << fit_fitmethod);
 | |
|     }
 | |
| 
 | |
|     if (pdc_get_optvalues("rotate", resopts, &fit->rotate, NULL))
 | |
|         fit->mask |= (1L << fit_rotate);
 | |
| 
 | |
|     if (pdc_get_optvalues("orientate", resopts, &fit->orientate, NULL))
 | |
|         fit->mask |= (1L << fit_orientate);
 | |
| 
 | |
|     if (fit->flags & is_textline)
 | |
|     {
 | |
|         inum = pdc_get_optvalues("margin", resopts, fit->margin, NULL);
 | |
|         if (inum)
 | |
|         {
 | |
|             if (inum == 1)
 | |
|                 fit->margin[1] = fit->margin[0];
 | |
|             fit->mask |= (1L << fit_margin);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (fit->flags & is_block)
 | |
|     {
 | |
|         if (pdc_get_optvalues("refpoint", resopts, fit->refpoint, NULL))
 | |
|             fit->mask |= (1L << fit_refpoint);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     if (fit->flags & is_block || !(fit->flags & is_textflow))
 | |
|     {
 | |
|         if (pdc_get_optvalues("boxsize", resopts, fit->boxsize, NULL))
 | |
|             fit->mask |= (1L << fit_boxsize);
 | |
| 
 | |
|         if (pdc_get_optvalues("shrinklimit", resopts, &fit->shrinklimit, NULL))
 | |
|             fit->mask |= (1L << fit_shrinklimit);
 | |
| 
 | |
|         inum = pdc_get_optvalues("position", resopts, fit->position, NULL);
 | |
|         if (inum)
 | |
|         {
 | |
|             if (inum == 1)
 | |
|                 fit->position[1] = fit->position[0];
 | |
|             fit->mask |= (1L << fit_position);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* definitions of fit text options */
 | |
| static const pdc_defopt pdf_fit_textline_options[] =
 | |
| {
 | |
|     PDF_TEXT_OPTIONS
 | |
| 
 | |
|     {"xadvancelist", pdc_scalarlist, PDC_OPT_NOZERO, 0, PDC_USHRT_MAX,
 | |
|       PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},
 | |
| 
 | |
|     PDF_FIT_OPTIONS1
 | |
|     PDF_FIT_OPTIONS2
 | |
|     PDC_OPT_TERMINATE
 | |
| };
 | |
| 
 | |
| void
 | |
| pdf__fit_textline(PDF *p, const char *text, int len, pdc_scalar x, pdc_scalar y,
 | |
|                   const char *optlist)
 | |
| {
 | |
|     pdf_ppt *ppt = p->curr_ppt;
 | |
|     pdf_text_options to;
 | |
|     pdf_fit_options fit;
 | |
|     pdc_matrix invm;
 | |
|     pdc_scalar currtx, currty;
 | |
| 
 | |
|     if (text && len == 0)
 | |
|         len = (int) strlen(text);
 | |
|     if (text == NULL || len <= 0)
 | |
|         return;
 | |
| 
 | |
|     pdc_check_number(p->pdc, "x", x);
 | |
|     pdc_check_number(p->pdc, "y", y);
 | |
| 
 | |
|     /* initialize text options */
 | |
|     to = *ppt->currto;
 | |
|     to.text = (char *) text;
 | |
|     to.textlen = len;
 | |
| 
 | |
|     /* initialize fit options */
 | |
|     pdf_init_fit_options(p, &fit);
 | |
|     fit.flags |= is_textline;
 | |
|     fit.refpoint[0] = x;
 | |
|     fit.refpoint[1] = y;
 | |
| 
 | |
|     /* parsing option list */
 | |
|     if (optlist && strlen(optlist))
 | |
|     {
 | |
|         pdc_resopt *resopts;
 | |
|         pdc_clientdata data;
 | |
| 
 | |
|         pdf_set_clientdata(p, &data);
 | |
|         resopts = pdc_parse_optionlist(p->pdc, optlist,
 | |
|                       pdf_fit_textline_options, &data, pdc_true);
 | |
|         if (!resopts)
 | |
|             return;
 | |
| 
 | |
|         pdf_get_text_options(p, &to, resopts);
 | |
|         pdf_get_fit_options(p, &fit, resopts);
 | |
|     }
 | |
| 
 | |
|     /* no font set */
 | |
|     if (to.font == -1)
 | |
|         pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0);
 | |
| 
 | |
|     pdf__save(p);
 | |
| 
 | |
|     /* put out text line */
 | |
|     pdf_fit_textline_internal(p, &to, &fit, &currtx, &currty);
 | |
| 
 | |
|     pdf__restore(p);
 | |
| 
 | |
|     /* calculate current text position*/
 | |
|     pdc_invert_matrix(p->pdc, &invm, &ppt->gstate[ppt->sl].ctm);
 | |
|     pdc_transform_point(&invm, currtx, currty, &currtx, &currty);
 | |
|     pdf__set_text_pos(p, currtx, currty);
 | |
| }
 | |
| 
 | |
| void
 | |
| pdf_fit_textline_internal(PDF *p, pdf_text_options *to, pdf_fit_options *fit,
 | |
|                           pdc_scalar *currtx, pdc_scalar *currty)
 | |
| {
 | |
|     pdc_byte *utext = (pdc_byte *) "";
 | |
|     int len, charlen;
 | |
| 
 | |
|     pdc_matrix m, mm;
 | |
|     pdc_vector elemsize, elemscale, elemmargin, relpos, polyline[5];
 | |
|     pdc_box fitbox, elembox;
 | |
|     pdc_scalar ss, width, height;
 | |
|     pdc_scalar x, y, tx = 0, ty = 0;
 | |
|     pdc_scalar font2user = to->fontsize / 1000.0;
 | |
|     int indangle;
 | |
| 
 | |
|     /* calculate and set text options */
 | |
|     pdf_calculate_text_options(to, pdc_false, 1.0);
 | |
|     pdf_set_text_options(p, to);
 | |
| 
 | |
|     /* convert text string */
 | |
|     utext = pdf_check_textstring(p, to->text, to->textlen, PDF_USE_TMPALLOC,
 | |
|                                  to, &len, &charlen);
 | |
|     if (utext == NULL || len == 0)
 | |
|         return;
 | |
| 
 | |
|     if (to->glyphwarning && to->nglyphs && len/charlen != to->nglyphs)
 | |
|         pdc_warning(p->pdc, PDF_E_TEXT_SIZENOMATCH,
 | |
|                     pdc_errprintf(p->pdc, "%d", to->nglyphs),
 | |
|                     pdc_errprintf(p->pdc, "%d", len/charlen), 0, 0);
 | |
| 
 | |
|     /* width of text */
 | |
|     width = pdf_calculate_textwidth(p, utext, len, charlen, to);
 | |
|     if (width > PDF_SMALLREAL)
 | |
|     {
 | |
|         elemmargin.x = fit->margin[0];
 | |
|         elemsize.x = width + 2 * elemmargin.x;
 | |
| 
 | |
|         /* text height */
 | |
|         height = fabs(font2user * p->fonts[to->font].capHeight);
 | |
|         elemmargin.y = fit->margin[1];
 | |
|         elemsize.y = height + 2 * elemmargin.y;
 | |
| 
 | |
|         /* orientation */
 | |
|         indangle = fit->orientate / 90;
 | |
|         if (indangle % 2)
 | |
|         {
 | |
|             ss = elemsize.x;
 | |
|             elemsize.x = elemsize.y;
 | |
|             elemsize.y = ss;
 | |
|         }
 | |
| 
 | |
|         /* box for fitting */
 | |
|         fitbox.ll.x = 0;
 | |
|         fitbox.ll.y = 0;
 | |
|         fitbox.ur.x = fit->boxsize[0];
 | |
|         fitbox.ur.y = fit->boxsize[1];
 | |
| 
 | |
|         /* relative position */
 | |
|         relpos.x = fit->position[0] / 100.0;
 | |
|         relpos.y = fit->position[1] / 100.0;
 | |
| 
 | |
|         /* calculate image box */
 | |
|         pdc_place_element(fit->fitmethod, fit->shrinklimit, &fitbox, &relpos,
 | |
|                           &elemsize, &elembox, &elemscale);
 | |
| 
 | |
|         /* reference point */
 | |
|         pdc_translation_matrix(fit->refpoint[0], fit->refpoint[1], &m);
 | |
| 
 | |
|         /* clipping */
 | |
|         if (fit->fitmethod == pdc_clip || fit->fitmethod == pdc_slice)
 | |
|         {
 | |
|             pdf_concat_raw(p, &m);
 | |
|             pdf__rect(p, 0, 0, fit->boxsize[0], fit->boxsize[1]);
 | |
|             pdf__clip(p);
 | |
|             pdc_identity_matrix(&m);
 | |
|         }
 | |
| 
 | |
|         /* optional rotation */
 | |
|         if (fabs(fit->rotate) > PDC_FLOAT_PREC)
 | |
|         {
 | |
|             pdc_rotation_matrix(p->ydirection * fit->rotate, &mm);
 | |
|             pdc_multiply_matrix(&mm, &m);
 | |
|         }
 | |
| 
 | |
|         /* translation of element box */
 | |
|         elembox.ll.y *= p->ydirection;
 | |
|         elembox.ur.y *= p->ydirection;
 | |
|         pdc_box2polyline(&elembox, polyline);
 | |
|         tx = polyline[indangle].x;
 | |
|         ty = polyline[indangle].y;
 | |
|         pdc_translation_matrix(tx, ty, &mm);
 | |
|         pdc_multiply_matrix(&mm, &m);
 | |
| 
 | |
|         /* orientation of text */
 | |
|         if (fit->orientate != 0)
 | |
|         {
 | |
|             pdc_rotation_matrix(p->ydirection * fit->orientate, &mm);
 | |
|             pdc_multiply_matrix(&mm, &m);
 | |
|             if (indangle % 2)
 | |
|             {
 | |
|                 ss = elemscale.x;
 | |
|                 elemscale.x = elemscale.y;
 | |
|                 elemscale.y = ss;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (elemscale.x != 1 || elemscale.y != 1)
 | |
|         {
 | |
|             pdc_scale_matrix(elemscale.x, elemscale.y, &mm);
 | |
|             pdc_multiply_matrix(&mm, &m);
 | |
|         }
 | |
| 
 | |
|         /* ctm */
 | |
|         pdf_concat_raw(p, &m);
 | |
| 
 | |
|         /* text position */
 | |
|         x = elemmargin.x;
 | |
|         y = elemmargin.y;
 | |
|         pdf__set_text_pos(p, x, y);
 | |
| 
 | |
| 
 | |
|         /* place text */
 | |
|         pdf_place_text(p, utext, len, charlen, to, width, pdc_false);
 | |
| 
 | |
|         /* create a link */
 | |
|         if (to->link)
 | |
|         {
 | |
|             pdc_scalar desc = fabs(font2user * p->fonts[to->font].descender);
 | |
| 
 | |
|             utext = pdf_check_textstring(p, to->text, to->textlen,
 | |
|                                          PDF_USE_TMPALLOC | PDF_KEEP_UNICODE,
 | |
|                                          to, &len, &charlen);
 | |
|             pdf_create_link(p, to->linktype, x, y - p->ydirection * desc,
 | |
|                             x + width, y + p->ydirection * to->fontsize,
 | |
|                             to->link, (char *) utext, len);
 | |
|             pdc_free_tmp(p->pdc, utext);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* save text position */
 | |
|     if (currtx && currty)
 | |
|     {
 | |
|         pdf_ppt *ppt = p->curr_ppt;
 | |
|         pdf_tstate *ts = &ppt->tstate[ppt->sl];
 | |
| 
 | |
|         pdc_transform_point(&ppt->gstate[ppt->sl].ctm,
 | |
|                             ts->currtx, ts->currty, currtx, currty);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /**         deprecated historical text formatting function                  **/
 | |
| /*****************************************************************************/
 | |
| 
 | |
| /* this helper function returns the width of the null-terminated string
 | |
| ** 'text' for the current font and size EXCLUDING the last character's
 | |
| ** additional charspacing.
 | |
| */
 | |
| static pdc_scalar
 | |
| pdf_swidth(PDF *p, const char *text)
 | |
| {
 | |
|     pdf_text_options *currto = p->curr_ppt->currto;
 | |
| 
 | |
|     pdc_scalar width = pdf_calculate_textwidth(p,
 | |
|                           (pdc_byte *) text, (int)strlen(text), 1, currto);
 | |
|     return (width - currto->horizscaling * currto->charspacing);
 | |
| }
 | |
| 
 | |
| static void
 | |
| pdf_show_aligned(PDF *p, const char *text, pdc_scalar x, pdc_scalar y,
 | |
|                  pdc_scalar wordspacing, pdf_alignment mode)
 | |
| {
 | |
|     if (!text)
 | |
| 	return;
 | |
| 
 | |
|     switch (mode) {
 | |
|         default:
 | |
|         case text_left:
 | |
|         case text_justify:
 | |
|         case text_fulljustify:
 | |
| 	    /* nothing extra here... */
 | |
| 	    break;
 | |
| 
 | |
|         case text_right:
 | |
| 	    x -= pdf_swidth(p, text);
 | |
| 	    break;
 | |
| 
 | |
|         case text_center:
 | |
| 	    x -= pdf_swidth(p, text) / 2;
 | |
| 	    break;
 | |
|     }
 | |
| 
 | |
|     pdf__set_text_pos(p, x, y);
 | |
|     pdf_set_tstate(p, wordspacing, to_wordspacing);
 | |
|     pdf__show_text(p, text, (int) strlen(text), pdc_false);
 | |
| }
 | |
| 
 | |
| int
 | |
| pdf__show_boxed(
 | |
|     PDF *p,
 | |
|     const char *text, int len,
 | |
|     pdc_scalar left,
 | |
|     pdc_scalar bottom,
 | |
|     pdc_scalar width,
 | |
|     pdc_scalar height,
 | |
|     const char *hmode,
 | |
|     const char *feature)
 | |
| {
 | |
|     pdc_scalar  old_wordspacing, wordspacing, textwidth, curx, cury;
 | |
|     pdc_bool	prematureexit;	/* return because box is too small */
 | |
|     int		curTextPos;	/* character currently processed */
 | |
|     int		lastdone;	/* last input character processed */
 | |
|     int         toconv = len;
 | |
|     pdf_text_options *currto = p->curr_ppt->currto;
 | |
|     pdc_font *currfont;
 | |
|     pdc_byte *utext = NULL;
 | |
|     pdc_text_format old_textformat;
 | |
|     pdf_alignment mode = text_left;
 | |
|     pdc_bool blind = pdc_false;
 | |
| 
 | |
|     /* text length */
 | |
|     if (text == NULL)
 | |
|         return 0;
 | |
|     if (!len)
 | |
|         len = (int) strlen(text);
 | |
|     if (!len)
 | |
|         return 0;
 | |
| 
 | |
|     pdc_check_number(p->pdc, "left", left);
 | |
|     pdc_check_number(p->pdc, "bottom", bottom);
 | |
|     pdc_check_number(p->pdc, "width", width);
 | |
|     pdc_check_number(p->pdc, "height", height);
 | |
| 
 | |
|     if (hmode == NULL || *hmode == '\0')
 | |
| 	pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "hmode", 0, 0, 0);
 | |
| 
 | |
|     if (!strcmp(hmode, "left"))
 | |
|         mode = text_left;
 | |
|     else if (!strcmp(hmode, "right"))
 | |
|         mode = text_right;
 | |
|     else if (!strcmp(hmode, "center"))
 | |
|         mode = text_center;
 | |
|     else if (!strcmp(hmode, "justify"))
 | |
|         mode = text_justify;
 | |
|     else if (!strcmp(hmode, "fulljustify"))
 | |
|         mode = text_fulljustify;
 | |
|     else
 | |
| 	pdc_error(p->pdc, PDC_E_ILLARG_STRING, "hmode", hmode, 0, 0);
 | |
| 
 | |
|     if (feature != NULL && *feature != '\0')
 | |
|     {
 | |
| 	if (!strcmp(feature, "blind"))
 | |
| 	    blind = pdc_true;
 | |
| 	else
 | |
| 	    pdc_error(p->pdc, PDC_E_ILLARG_STRING, "feature", feature, 0, 0);
 | |
|     }
 | |
| 
 | |
|     /* no font set */
 | |
|     if (currto->font == -1)
 | |
|         pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0);
 | |
|     currfont = &p->fonts[currto->font];
 | |
| 
 | |
|     if (width == 0 && height != 0)
 | |
|         pdc_error(p->pdc, PDC_E_ILLARG_FLOAT,
 | |
|             "width", pdc_errprintf(p->pdc, "%f", width), 0, 0);
 | |
| 
 | |
|     if (width != 0 && height == 0)
 | |
|         pdc_error(p->pdc, PDC_E_ILLARG_FLOAT,
 | |
|             "height", pdc_errprintf(p->pdc, "%f", height), 0, 0);
 | |
| 
 | |
|     /* we cannot handle several encodings */
 | |
|     if (currfont->encoding == pdc_unicode)
 | |
|     {
 | |
|         pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "Unicode", 0, 0, 0);
 | |
|     }
 | |
| 
 | |
|     if (currfont->encoding == pdc_glyphid)
 | |
|     {
 | |
|         pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "glyphid", 0, 0, 0);
 | |
|     }
 | |
| 
 | |
|     if (currfont->encoding == pdc_cid)
 | |
|     {
 | |
| 	pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "CID", 0, 0, 0);
 | |
|     }
 | |
| 
 | |
|     if (currfont->encoding == pdc_ebcdic || currfont->encoding == pdc_ebcdic_37)
 | |
|     {
 | |
| 	pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "EBCDIC", 0, 0, 0);
 | |
|     }
 | |
| 
 | |
|     /* old wordspacing */
 | |
|     old_textformat = currto->textformat;
 | |
| 
 | |
|     /* convert text string */
 | |
|     if (toconv)
 | |
|     {
 | |
|         int charlen;
 | |
| 
 | |
|         /* convert text string */
 | |
|         utext = pdf_check_textstring(p, text, len,
 | |
|                     PDF_KEEP_CONTROL | PDF_KEEP_TEXTLEN | PDF_USE_TMPALLOC,
 | |
|                     currto, &len, &charlen);
 | |
|         if (!utext)
 | |
|             return 0;
 | |
| 
 | |
|         utext[len] = 0;
 | |
|         text = (const char *) utext;
 | |
|         currto->textformat = pdc_bytes;
 | |
|     }
 | |
| 
 | |
|     /* old wordspacing */
 | |
|     old_wordspacing = currto->wordspacing;
 | |
| 
 | |
|     /* special case for a single aligned line */
 | |
|     if (width == 0 && height == 0)
 | |
|     {
 | |
|         if (!blind)
 | |
|             pdf_show_aligned(p, text, left, bottom, old_wordspacing, mode);
 | |
| 
 | |
|         if (toconv)
 | |
|             currto->textformat = old_textformat;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     curx = left;
 | |
|     cury = bottom + p->ydirection * height;
 | |
|     prematureexit = pdc_false;
 | |
|     curTextPos = 0;
 | |
|     lastdone = 0;
 | |
| 
 | |
|     /* switch curx for right and center justification */
 | |
|     if (mode == text_right)
 | |
| 	curx += width;
 | |
|     else if (mode == text_center)
 | |
| 	curx += (width / 2);
 | |
| 
 | |
| #define	MAX_CHARS_IN_LINE	2048
 | |
| 
 | |
|     /* loop until all characters processed, or box full */
 | |
| 
 | |
|     while ((curTextPos < len) && !prematureexit)
 | |
|     {
 | |
| 	/* buffer for constructing the line */
 | |
| 	char	linebuf[MAX_CHARS_IN_LINE];
 | |
| 	int	curCharsInLine = 0;	/* # of chars in constructed line */
 | |
| 	int	lastWordBreak = 0;	/* the last seen space char */
 | |
| 	int	wordBreakCount = 0;	/* # of blanks in this line */
 | |
| 
 | |
| 	/* loop over the input string */
 | |
|         while (curTextPos < len)
 | |
|         {
 | |
| 	    if (curCharsInLine >= MAX_CHARS_IN_LINE)
 | |
| 		pdc_error(p->pdc, PDC_E_ILLARG_TOOLONG, "(text line)",
 | |
| 		    pdc_errprintf(p->pdc, "%d", MAX_CHARS_IN_LINE-1), 0, 0);
 | |
| 
 | |
| 	    /* abandon DOS line-ends */
 | |
| 	    if (text[curTextPos] == PDF_RETURN &&
 | |
| 		text[curTextPos+1] == PDF_NEWLINE)
 | |
| 		    curTextPos++;
 | |
| 
 | |
| 	    /* if it's a forced line break draw the line */
 | |
| 	    if (text[curTextPos] == PDF_NEWLINE ||
 | |
| 		text[curTextPos] == PDF_RETURN)
 | |
|             {
 | |
|                 cury -= p->ydirection * currto->leading;
 | |
| 
 | |
|                 if (p->ydirection * (cury - bottom) < 0) {
 | |
| 		    prematureexit = pdc_true;	/* box full */
 | |
| 		    break;
 | |
| 		}
 | |
| 
 | |
|                 linebuf[curCharsInLine] = 0;    /* terminate the line */
 | |
| 
 | |
| 		/* check whether the line is too long */
 | |
|                 wordspacing = 0;
 | |
|                 pdf_set_tstate(p, wordspacing, to_wordspacing);
 | |
|                 textwidth = pdf_swidth(p, linebuf);
 | |
| 
 | |
| 		/* the forced break occurs too late for this line */
 | |
| 		if (textwidth > width)
 | |
|                 {
 | |
| 		    if (wordBreakCount == 0) {	/* no blank found */
 | |
| 			prematureexit = pdc_true;
 | |
| 			break;
 | |
| 		    }
 | |
|                     linebuf[lastWordBreak] = 0;   /* terminate at last blank */
 | |
| 		    if (curTextPos > 0 && text[curTextPos-1] == PDF_RETURN)
 | |
| 			--curTextPos;
 | |
| 		    curTextPos -= (curCharsInLine - lastWordBreak);
 | |
| 
 | |
| 		    if (!blind)
 | |
|                     {
 | |
|                         textwidth = pdf_swidth(p, linebuf);
 | |
| 			if (wordBreakCount != 1 &&
 | |
|                                 (mode == text_justify ||
 | |
|                                  mode == text_fulljustify))
 | |
|                         {
 | |
|                             wordspacing = (width - textwidth) /
 | |
|                                 ((wordBreakCount - 1) * currto->horizscaling);
 | |
| 			}
 | |
|                         pdf_show_aligned(p, linebuf, curx, cury, wordspacing,
 | |
|                                          mode);
 | |
| 		    }
 | |
| 		}
 | |
|                 else if (!blind)
 | |
|                 {
 | |
|                     if (mode == text_fulljustify && wordBreakCount > 0)
 | |
|                     {
 | |
|                         wordspacing = (width - textwidth) /
 | |
|                                   (wordBreakCount * currto->horizscaling);
 | |
| 		    }
 | |
|                     pdf_show_aligned(p, linebuf, curx, cury, wordspacing, mode);
 | |
| 		}
 | |
| 
 | |
| 		lastdone = curTextPos;
 | |
| 		curCharsInLine = lastWordBreak = wordBreakCount = 0;
 | |
| 		curTextPos++;
 | |
| 
 | |
| 	    }
 | |
|             else if (text[curTextPos] == PDF_SPACE)
 | |
|             {
 | |
|                 linebuf[curCharsInLine] = 0;    /* terminate the line */
 | |
| 
 | |
| 		/* line too long ==> break at last blank */
 | |
|                 wordspacing = 0;
 | |
|                 pdf_set_tstate(p, wordspacing, to_wordspacing);
 | |
|                 if (pdf_swidth(p, linebuf) > width)
 | |
|                 {
 | |
|                     cury -= p->ydirection * currto->leading;
 | |
| 
 | |
|                     if (p->ydirection * (cury - bottom) < 0)
 | |
|                     {
 | |
| 			prematureexit = pdc_true; 	/* box full */
 | |
| 			break;
 | |
| 		    }
 | |
| 
 | |
|                     linebuf[lastWordBreak] = 0; /* terminate at last blank */
 | |
| 		    curTextPos -= (curCharsInLine - lastWordBreak - 1);
 | |
| 
 | |
| 		    if (lastWordBreak == 0)
 | |
| 			curTextPos--;
 | |
| 
 | |
| 		    /* LATER: * force break if wordBreakCount == 1,
 | |
| 		     * i.e., no blank
 | |
| 		     */
 | |
| 		    if (wordBreakCount == 0)
 | |
|                     {
 | |
| 			prematureexit = pdc_true;
 | |
| 			break;
 | |
| 		    }
 | |
| 
 | |
| 		    /* adjust word spacing for full justify */
 | |
|                     if (wordBreakCount != 1 && (mode == text_justify ||
 | |
|                                                 mode == text_fulljustify))
 | |
|                     {
 | |
|                         textwidth = pdf_swidth(p, linebuf);
 | |
|                         wordspacing = (width - textwidth) /
 | |
|                             ((wordBreakCount - 1) * currto->horizscaling);
 | |
| 		    }
 | |
| 
 | |
| 		    lastdone = curTextPos;
 | |
| 		    if (!blind)
 | |
|                     {
 | |
|                         pdf_show_aligned(p, linebuf, curx, cury, wordspacing,
 | |
|                                          mode);
 | |
|                     }
 | |
| 		    curCharsInLine = lastWordBreak = wordBreakCount = 0;
 | |
| 		}
 | |
|                 else
 | |
|                 {
 | |
| 		    /* blank found, and line still fits */
 | |
| 		    wordBreakCount++;
 | |
| 		    lastWordBreak = curCharsInLine;
 | |
| 		    linebuf[curCharsInLine++] = text[curTextPos++];
 | |
| 		}
 | |
| 	    }
 | |
|             else
 | |
|             {
 | |
| 		/* regular character ==> store in buffer */
 | |
| 		linebuf[curCharsInLine++] = text[curTextPos++];
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	if (prematureexit) {
 | |
| 	    break;		/* box full */
 | |
| 	}
 | |
| 
 | |
| 	/* if there is anything left in the buffer, draw it */
 | |
|         if (curTextPos >= len && curCharsInLine != 0)
 | |
|         {
 | |
|             cury -= p->ydirection * currto->leading;
 | |
| 
 | |
|             if (p->ydirection * (cury - bottom) < 0)
 | |
|             {
 | |
| 		prematureexit = pdc_true; 	/* box full */
 | |
| 		break;
 | |
| 	    }
 | |
| 
 | |
|             linebuf[curCharsInLine] = 0;        /* terminate the line */
 | |
| 
 | |
| 	    /* check if the last line is too long */
 | |
|             wordspacing = 0;
 | |
|             pdf_set_tstate(p, wordspacing, to_wordspacing);
 | |
|             textwidth = pdf_swidth(p, linebuf);
 | |
| 
 | |
| 	    if (textwidth > width)
 | |
|             {
 | |
| 		if (wordBreakCount == 0)
 | |
| 		{
 | |
| 		    prematureexit = pdc_true;
 | |
| 		    break;
 | |
| 		}
 | |
| 
 | |
|                 linebuf[lastWordBreak] = 0;     /* terminate at last blank */
 | |
| 		curTextPos -= (curCharsInLine - lastWordBreak - 1);
 | |
| 
 | |
| 		/* recalculate the width */
 | |
|                 textwidth = pdf_swidth(p, linebuf);
 | |
| 
 | |
| 		/* adjust word spacing for full justify */
 | |
|                 if (wordBreakCount != 1 && (mode == text_justify ||
 | |
|                                             mode == text_fulljustify))
 | |
|                 {
 | |
|                     wordspacing = (width - textwidth) /
 | |
|                         ((wordBreakCount - 1) * currto->horizscaling);
 | |
| 		}
 | |
| 	    }
 | |
|             else if (!blind)
 | |
|             {
 | |
|                 if (mode == text_fulljustify && wordBreakCount)
 | |
|                 {
 | |
|                     wordspacing = (width - textwidth) /
 | |
|                               (wordBreakCount * currto->horizscaling);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
| 	    lastdone = curTextPos;
 | |
| 	    if (!blind)
 | |
|             {
 | |
|                 pdf_show_aligned(p, linebuf, curx, cury, wordspacing, mode);
 | |
|             }
 | |
| 	    curCharsInLine = lastWordBreak = wordBreakCount = 0;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     pdf_set_tstate(p, old_wordspacing, to_wordspacing);
 | |
| 
 | |
|     /* return number of remaining characters  */
 | |
| 
 | |
|     while (text[lastdone] == PDF_SPACE)
 | |
| 	++lastdone;
 | |
| 
 | |
|     if ((text[lastdone] == PDF_RETURN ||
 | |
| 	text[lastdone] == PDF_NEWLINE) && text[lastdone+1] == 0)
 | |
| 	    ++lastdone;
 | |
| 
 | |
|     if (toconv)
 | |
|         currto->textformat = old_textformat;
 | |
| 
 | |
|     return (int) (len - lastdone);
 | |
| }
 |