Files correlati : pdflib Ricompilazione Demo : [ ] Commento : Aggiornata PDFlib git-svn-id: svn://10.65.10.50/trunk@17433 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			3807 lines
		
	
	
		
			108 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			3807 lines
		
	
	
		
			108 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*---------------------------------------------------------------------------*
 | 
						|
 |              PDFlib - A library for generating PDF on the fly             |
 | 
						|
 +---------------------------------------------------------------------------+
 | 
						|
 | Copyright (c) 1997-2006 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.3 2008-10-20 14:34:16 guy 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_bool    fb;              /* fake bold */
 | 
						|
    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 = PDC_FLOAT_MIN;
 | 
						|
    ts->ld = 0;
 | 
						|
    ts->cs = 0;
 | 
						|
    ts->ws = 0;
 | 
						|
    ts->hs = 1;
 | 
						|
    ts->ia = 0;
 | 
						|
    ts->fb = pdc_false;
 | 
						|
    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->fakebold = ts->fb;
 | 
						|
    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;
 | 
						|
        if (prevvalue != -1 &&
 | 
						|
            (p->fonts[(int) prevvalue].metricflags & font_italic) !=
 | 
						|
            (p->fonts[currto->font].metricflags & font_italic))
 | 
						|
            currto->mask |= (1 << to_italicangle);
 | 
						|
        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->ld;
 | 
						|
        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_fakebold:
 | 
						|
        prevvalue = ts->fb;
 | 
						|
        ts->fb = currto->fakebold = (pdc_bool) ivalue;
 | 
						|
        return;
 | 
						|
 | 
						|
        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_escapesequence:
 | 
						|
        currto->escapesequence = (pdc_bool) ivalue;
 | 
						|
        return;
 | 
						|
 | 
						|
        case to_glyphcheck:
 | 
						|
        currto->glyphcheck = (pdc_glyphcheck) 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_fakebold:
 | 
						|
        return (double) currto->fakebold;
 | 
						|
 | 
						|
        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 = PDC_FLOAT_MIN;
 | 
						|
    to->fontsize_pc = 0;
 | 
						|
    to->fontsize_st = (int) text_fontsize;
 | 
						|
    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->fakebold = pdc_false;
 | 
						|
    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->pdc->charref;
 | 
						|
    to->escapesequence = p->pdc->escapesequ;
 | 
						|
    to->glyphcheck = p->glyphcheck;
 | 
						|
    to->glyphwarning = p->debug[(int) 'g'];
 | 
						|
    to->glyphwarning = pdf_get_errorpolicy(p, NULL, to->glyphwarning);
 | 
						|
    pdf_init_coloropt(p, &to->fillcolor);
 | 
						|
    pdf_init_coloropt(p, &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_fakebold, to_wordspacing,
 | 
						|
    to_textrise, to_underlinewidth, to_underlineposition
 | 
						|
};
 | 
						|
 | 
						|
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;
 | 
						|
                if (currto->font != -1 &&
 | 
						|
                    (p->fonts[to->font].metricflags & font_italic) !=
 | 
						|
                    (p->fonts[currto->font].metricflags & font_italic))
 | 
						|
                {
 | 
						|
                    to->mask |= (1 << to_italicangle);
 | 
						|
                    currto->mask = to->mask; /* otherwise order dependent */
 | 
						|
                }
 | 
						|
                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_fakebold:
 | 
						|
                ts->fb = currto->fakebold = to->fakebold;
 | 
						|
                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;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
pdf_get_fontsize_option(PDF *p, int font, pdc_resopt *resopts,
 | 
						|
                        pdc_scalar *fontsize)
 | 
						|
{
 | 
						|
    pdc_scalar fs[2], fm ;
 | 
						|
    int ns;
 | 
						|
 | 
						|
    /* *fontsize is initialized from outside */
 | 
						|
 | 
						|
    fs[0] = 0;   /* see "auto" */
 | 
						|
    fs[1] = 0;
 | 
						|
    ns = pdc_get_optvalues("fontsize", resopts, (pdc_scalar *) fs, NULL);
 | 
						|
    if (ns == 1)
 | 
						|
    {
 | 
						|
        *fontsize = fs[0];
 | 
						|
    }
 | 
						|
    else if (ns == 2)
 | 
						|
    {
 | 
						|
        int kind = (int) fs[0];
 | 
						|
 | 
						|
        pdf_check_handle(p, font, pdc_fonthandle);
 | 
						|
 | 
						|
        switch(kind)
 | 
						|
        {
 | 
						|
            case text_xheight:
 | 
						|
            fm = (pdc_scalar) p->fonts[font].ft.m.xHeight;
 | 
						|
            break;
 | 
						|
 | 
						|
            case text_capheight:
 | 
						|
            fm = (pdc_scalar) p->fonts[font].ft.m.capHeight;
 | 
						|
            break;
 | 
						|
 | 
						|
            case text_ascender:
 | 
						|
            fm = (pdc_scalar) p->fonts[font].ft.m.ascender;
 | 
						|
            break;
 | 
						|
 | 
						|
            default:
 | 
						|
            fm = 1000.0;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        *fontsize = fs[1] * 1000.0 / fm;
 | 
						|
    }
 | 
						|
 | 
						|
    return ns;
 | 
						|
}
 | 
						|
 | 
						|
pdc_bool
 | 
						|
pdf_calculate_text_options(PDF *p, pdf_text_options *to, pdc_bool force,
 | 
						|
                           pdc_scalar fontscale, pdc_scalar minfontsize,
 | 
						|
                           pdc_scalar fontsizeref)
 | 
						|
{
 | 
						|
    pdc_bool kminfs = pdc_false;
 | 
						|
 | 
						|
    if (to->mask & (1 << to_fontsize) || force)
 | 
						|
    {
 | 
						|
        pdc_scalar fontsize;
 | 
						|
 | 
						|
        if (fontsizeref == 0)
 | 
						|
            fontsizeref = to->fontsize;
 | 
						|
 | 
						|
        if (to->pcmask & (1 << to_fontsize))
 | 
						|
            fontsize = to->fontsize_pc * fontsizeref;
 | 
						|
        else
 | 
						|
            fontsize = fontscale * to->fontsize;
 | 
						|
 | 
						|
        if (to->fontsize_st != (int) text_fontsize)
 | 
						|
        {
 | 
						|
            pdf_font *currfont = &p->fonts[to->font];
 | 
						|
            pdc_scalar fm;
 | 
						|
 | 
						|
            switch(to->fontsize_st)
 | 
						|
            {
 | 
						|
                case text_xheight:
 | 
						|
                fm = (pdc_scalar) currfont->ft.m.xHeight;
 | 
						|
                break;
 | 
						|
 | 
						|
                case text_capheight:
 | 
						|
                fm = (pdc_scalar) currfont->ft.m.capHeight;
 | 
						|
                break;
 | 
						|
 | 
						|
                case text_ascender:
 | 
						|
                fm = (pdc_scalar) currfont->ft.m.ascender;
 | 
						|
                break;
 | 
						|
 | 
						|
                default:
 | 
						|
                fm = 1000.0;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            fontsize *= 1000.0 / fm;
 | 
						|
        }
 | 
						|
 | 
						|
        if (fontscale < 1.0 && fabs(fontsize) < minfontsize)
 | 
						|
        {
 | 
						|
            if (fontsize > 0)
 | 
						|
                fontsize = minfontsize;
 | 
						|
            else
 | 
						|
                fontsize = -minfontsize;
 | 
						|
            kminfs = pdc_true;
 | 
						|
        }
 | 
						|
        to->fontsize = fontsize;
 | 
						|
 | 
						|
        /* we reset relative fontsize specifications */
 | 
						|
        if (to->mask & (1L << to_fontsize))
 | 
						|
        {
 | 
						|
            to->pcmask &= ~(1 << to_fontsize);
 | 
						|
            to->fontsize_st = (int) text_fontsize;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    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;
 | 
						|
    }
 | 
						|
 | 
						|
    return kminfs;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdf_get_text_options(PDF *p, pdf_text_options *to, pdc_resopt *resopts)
 | 
						|
{
 | 
						|
    char **strlist;
 | 
						|
    int i, inum;
 | 
						|
    pdc_scalar fs[2];
 | 
						|
 | 
						|
    if (pdc_get_optvalues("glyphwarning", resopts, &to->glyphwarning, NULL))
 | 
						|
        to->mask |= (1L << to_glyphwarning);
 | 
						|
    to->glyphwarning = pdf_get_errorpolicy(p, resopts, to->glyphwarning);
 | 
						|
 | 
						|
    if (pdc_get_optvalues("font", resopts, &to->font, NULL))
 | 
						|
    {
 | 
						|
        pdf_check_handle(p, to->font, pdc_fonthandle);
 | 
						|
        to->mask |= (1L << to_font);
 | 
						|
        to->fontset |= (1L << to_font);
 | 
						|
    }
 | 
						|
 | 
						|
    fs[0] = 0;   /* see "auto" */
 | 
						|
    fs[1] = 0;
 | 
						|
    inum = pdc_get_optvalues("fontsize", resopts, (pdc_scalar *) fs, NULL);
 | 
						|
    if (inum)
 | 
						|
    {
 | 
						|
        i = inum - 1;
 | 
						|
        to->fontsize = fs[i];
 | 
						|
        if (inum == 2)
 | 
						|
            to->fontsize_st = (int) fs[0];
 | 
						|
        else
 | 
						|
            to->fontsize_st = (int) text_fontsize;
 | 
						|
        to->mask |= (1L << to_fontsize);
 | 
						|
        to->mask |= (1L << to_fontsize_st);
 | 
						|
 | 
						|
        if (pdc_is_lastopt_percent(resopts, i))
 | 
						|
        {
 | 
						|
            to->pcmask |= (1 << to_fontsize);
 | 
						|
            to->fontsize_pc = to->fontsize;
 | 
						|
        }
 | 
						|
        else
 | 
						|
            to->pcmask &= ~(1 << 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("escapesequence", resopts, &to->escapesequence, NULL))
 | 
						|
        to->mask |= (1L << to_escapesequence);
 | 
						|
 | 
						|
    if (pdc_get_optvalues("glyphcheck", resopts, &inum, NULL))
 | 
						|
    {
 | 
						|
        to->glyphcheck = (pdc_glyphcheck) inum;
 | 
						|
        to->mask |= (1L << to_glyphcheck);
 | 
						|
    }
 | 
						|
 | 
						|
    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("fakebold", resopts, &to->fakebold, NULL))
 | 
						|
        to->mask |= (1L << to_fakebold);
 | 
						|
 | 
						|
 | 
						|
    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_max,
 | 
						|
                           &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_max,
 | 
						|
                           &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;
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * deprecated
 | 
						|
     */
 | 
						|
    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;
 | 
						|
    pdf_font *currfont = NULL;
 | 
						|
 | 
						|
    if (currto->font > -1)
 | 
						|
        currfont = &p->fonts[currto->font];
 | 
						|
 | 
						|
    /* 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 (currfont &&
 | 
						|
        ((currto->mask & (1L << to_font)) ||
 | 
						|
         (currto->mask & (1L << to_fontsize)) || !ts->glyphinit))
 | 
						|
    {
 | 
						|
        pdc_printf(p->out, "/F%d %f Tf\n",
 | 
						|
            ppt->fn_bias + currto->font, p->ydirection * currto->fontsize);
 | 
						|
 | 
						|
        currfont->used_in_current_doc = pdc_true;
 | 
						|
        currfont->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_fakebold);
 | 
						|
    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 ---------------------- */
 | 
						|
 | 
						|
struct pdf_fitres_s
 | 
						|
{
 | 
						|
    pdc_bool verbose;
 | 
						|
    pdc_vector start;           /* text start position */
 | 
						|
    pdc_vector end;             /* text end position */
 | 
						|
    pdc_vector writingdir;      /* unit vector of text writing direction */
 | 
						|
    pdc_vector perpendiculardir;/* unit vector perpendicular to writing dir. */
 | 
						|
    pdc_vector scale;           /* x/y scaling */
 | 
						|
    pdc_scalar angle;           /* rotation angle of writingdir in degree */
 | 
						|
    pdc_scalar width;           /* textline width */
 | 
						|
    pdc_scalar height;          /* textline height */
 | 
						|
    pdc_scalar mwidth;          /* textline width with margins */
 | 
						|
    pdc_scalar mheight;         /* textline height with margins */
 | 
						|
    pdc_scalar ascender;        /* textline ascender */
 | 
						|
    pdc_scalar capheight;       /* textline capheight */
 | 
						|
    pdc_scalar xheight;         /* textline xheight */
 | 
						|
    pdc_scalar descender;       /* textline descender */
 | 
						|
    int unmappedchars;          /* number of characters not contained
 | 
						|
                                 * in the encoding and not in the font */
 | 
						|
    int replacedchars;          /* number of characters replaced by
 | 
						|
                                 * typografically similar characters */
 | 
						|
    int unknownchars;           /* number of characters replaced by
 | 
						|
                                 * given replcement character */
 | 
						|
};
 | 
						|
 | 
						|
typedef struct pdf_ligat_s pdf_ligat;
 | 
						|
 | 
						|
struct pdf_ligat_s
 | 
						|
{
 | 
						|
    pdf_ligat  *next;
 | 
						|
    int         icp;    /* text position */
 | 
						|
    int         nb;     /* number of parts */
 | 
						|
    pdc_byte    culist[2 * PDC_MAX_UVLIST];
 | 
						|
                        /* ligature parts */
 | 
						|
};
 | 
						|
 | 
						|
static pdf_ligat *
 | 
						|
pdf_register_ligat(PDF *p, pdf_ligat *ligatlist, int icp, int nv,
 | 
						|
                   pdc_ushort *culist, int charlen)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdf_hook_ligat";
 | 
						|
    int i;
 | 
						|
 | 
						|
    pdf_ligat *ligat =
 | 
						|
        (pdf_ligat *) pdc_malloc_tmp(p->pdc, sizeof(pdf_ligat), fn, NULL, NULL);
 | 
						|
 | 
						|
    if (ligatlist == NULL)
 | 
						|
    {
 | 
						|
        ligatlist = ligat;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        pdf_ligat *next = ligatlist;
 | 
						|
 | 
						|
        while (next->next != NULL)
 | 
						|
            next = next->next;
 | 
						|
        next->next = ligat;
 | 
						|
    }
 | 
						|
 | 
						|
    ligat->next = NULL;
 | 
						|
    ligat->icp = charlen * icp;
 | 
						|
    nv--;
 | 
						|
    ligat->nb = charlen * nv;
 | 
						|
 | 
						|
    if (charlen == 1)
 | 
						|
    {
 | 
						|
        for (i = 0; i < nv; i++)
 | 
						|
            ligat->culist[i] = (pdc_byte) culist[i+1];
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        memcpy(ligat->culist, &culist[1], (size_t) ligat->nb);
 | 
						|
    }
 | 
						|
    return ligatlist;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pdf_cleanup_ligat(PDF *p, pdf_ligat *list)
 | 
						|
{
 | 
						|
    pdf_ligat *next;
 | 
						|
 | 
						|
    while (list != NULL)
 | 
						|
    {
 | 
						|
        next = list->next;
 | 
						|
        pdc_free_tmp(p->pdc, list);
 | 
						|
        list = next;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#define PDF_MAX_GLYPHCHECKS 8
 | 
						|
 | 
						|
int
 | 
						|
pdf_get_approximate_uvlist(PDF *p, pdf_font *currfont, pdc_encodingvector *ev,
 | 
						|
                    int usv, pdc_bool replace, pdf_fitres *fitres,
 | 
						|
                    pdc_ushort *uvlist, pdc_ushort *cglist)
 | 
						|
{
 | 
						|
    int cg = 0, nv = 1;
 | 
						|
 | 
						|
    (void) p;
 | 
						|
    (void) ev;
 | 
						|
    (void) usv;
 | 
						|
 | 
						|
 | 
						|
    if (cg <= 0)
 | 
						|
    {
 | 
						|
        if (replace)
 | 
						|
        {
 | 
						|
            cglist[0] = (pdc_ushort) currfont->replacementcode;
 | 
						|
            uvlist[0] = (pdc_ushort) currfont->replacementchar;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            cglist[0] = 0;
 | 
						|
            uvlist[0] = 0;
 | 
						|
        }
 | 
						|
        nv = 1;
 | 
						|
 | 
						|
        if (fitres != NULL)
 | 
						|
            fitres->unknownchars++;
 | 
						|
    }
 | 
						|
    else if (fitres != NULL)
 | 
						|
    {
 | 
						|
        fitres->replacedchars++;
 | 
						|
    }
 | 
						|
 | 
						|
    return nv;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pdf_logg_glyph_replacement(PDF *p, int ic, int code,
 | 
						|
                           pdc_encoding enc, int charlen,
 | 
						|
                           pdc_ushort *uvlist, pdc_ushort *cglist, int nv)
 | 
						|
{
 | 
						|
    const char *glyphname;
 | 
						|
    int i;
 | 
						|
 | 
						|
    pdc_logg(p->pdc, "\t\tat text position %d: ", ic);
 | 
						|
 | 
						|
    if (charlen == 1)
 | 
						|
        pdc_logg(p->pdc, "code x%02X ", code);
 | 
						|
    else
 | 
						|
        pdc_logg(p->pdc, "U+%04X ", code);
 | 
						|
 | 
						|
    pdc_logg(p->pdc, "was replaced by: ");
 | 
						|
    if (nv > 1)
 | 
						|
        pdc_logg(p->pdc, "\n");
 | 
						|
 | 
						|
    for (i = 0; i < nv; i++)
 | 
						|
    {
 | 
						|
        if (nv > 1)
 | 
						|
            pdc_logg(p->pdc, "\t\t\t");
 | 
						|
 | 
						|
        if (charlen == 1)
 | 
						|
            pdc_logg(p->pdc, "code x%02X ", cglist[i]);
 | 
						|
        else
 | 
						|
            pdc_logg(p->pdc, "U+%04X ", uvlist[i]);
 | 
						|
 | 
						|
        if (enc >= 0)
 | 
						|
        {
 | 
						|
            if (charlen == 1)
 | 
						|
                pdc_logg(p->pdc, "U+%04X ", uvlist[i]);
 | 
						|
            else
 | 
						|
                pdc_logg(p->pdc, "code x%02X ", cglist[i]);
 | 
						|
        }
 | 
						|
 | 
						|
        glyphname = pdc_unicode2glyphname(p->pdc, uvlist[i]);
 | 
						|
        if (glyphname && strlen(glyphname))
 | 
						|
            pdc_logg(p->pdc, "\"%s\"", glyphname);
 | 
						|
 | 
						|
        pdc_logg(p->pdc, "\n");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdf_get_input_textformat(pdf_font *currfont,
 | 
						|
        pdc_text_format *intextformat, int *convflags)
 | 
						|
{
 | 
						|
    /* input text format */
 | 
						|
    if (currfont->unibyte)
 | 
						|
    {
 | 
						|
        /* encoding=unicode, but 8-bit encoding ev is available */
 | 
						|
        *convflags |= PDC_CONV_FORCEUTF16;
 | 
						|
    }
 | 
						|
    else if (currfont->codesize <= 1)
 | 
						|
    {
 | 
						|
        /* we must force bytes[2] source input format
 | 
						|
         * for 8-bit encodings because of "pass through mode".
 | 
						|
         */
 | 
						|
        if (*intextformat == pdc_auto)
 | 
						|
            *intextformat = pdc_bytes;
 | 
						|
        else if (*intextformat == pdc_auto2)
 | 
						|
            *intextformat = pdc_bytes2;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* 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 pdc_false an error was occurred, otherwise pdc_true.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
pdc_bool
 | 
						|
pdf_check_textstring(PDF *p, const char *text, int len, int flags,
 | 
						|
                     pdf_text_options *to, pdf_fitres *fitres,
 | 
						|
                     pdc_byte **outtext_p, int *outlen,
 | 
						|
                     int *outcharlen, pdc_bool verbose)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdf_check_textstring";
 | 
						|
 | 
						|
    pdc_bool logg1 = pdc_logg_is_enabled(p->pdc, 1, trc_text);
 | 
						|
    pdc_bool logg2 = pdc_false;
 | 
						|
    pdf_font *currfont = &p->fonts[to->font];
 | 
						|
    pdc_encoding enc = currfont->ft.enc;
 | 
						|
    pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc);
 | 
						|
    pdc_encodingvector *inev = NULL;
 | 
						|
    pdc_encodingvector *outev = NULL;
 | 
						|
 | 
						|
    pdc_text_format intextformat = to->textformat;
 | 
						|
    pdc_text_format outtextformat = pdc_utf16;
 | 
						|
 | 
						|
    int maxlen = PDF_MAXDICTSIZE;
 | 
						|
    int charlen = 1, newcharlen = 1;
 | 
						|
    int convflags = PDC_CONV_NOBOM;
 | 
						|
 | 
						|
    pdf_ligat *ligat, *ligatlist = NULL;
 | 
						|
    pdc_byte *intext = (pdc_byte *) text, *outtext = NULL;
 | 
						|
    int newlen = -1, replchar;
 | 
						|
 | 
						|
    if (logg1)
 | 
						|
    {
 | 
						|
        logg2 = pdc_logg_is_enabled(p->pdc, 2, trc_text);
 | 
						|
 | 
						|
        if (logg2)
 | 
						|
            pdc_logg_hexdump(p->pdc, "input text", "\t\t", (char *) text, len);
 | 
						|
        else
 | 
						|
            pdc_logg(p->pdc,
 | 
						|
                "\tText will be checked and converted: \"%T\"\n", text, len);
 | 
						|
 | 
						|
        if (logg2)
 | 
						|
        {
 | 
						|
            pdc_logg(p->pdc,
 | 
						|
                "\t\tfont: \"%s\"\n"
 | 
						|
                "\t\tencoding: \"%s\"\n"
 | 
						|
                "\t\ttextformat: %s\n"
 | 
						|
                "\t\tcharref: %s\n"
 | 
						|
                "\t\tescapesequence: %s\n"
 | 
						|
                "\t\tglyphwarning: %s\n"
 | 
						|
                "\t\tglyphcheck: %s\n",
 | 
						|
                currfont->ft.name,
 | 
						|
                pdf_get_encoding_name(p, enc, currfont),
 | 
						|
                pdc_get_keyword(intextformat, pdf_textformat_keylist),
 | 
						|
                PDC_BOOLSTR(to->charref),
 | 
						|
                PDC_BOOLSTR(to->escapesequence),
 | 
						|
                PDC_BOOLSTR(to->glyphwarning),
 | 
						|
                pdc_get_keyword(to->glyphcheck, pdf_glyphcheck_keylist));
 | 
						|
 | 
						|
            convflags |= PDC_CONV_LOGGING;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* text is passed through for CID fonts with non Unicode CMap */
 | 
						|
    if (currfont->passthrough)
 | 
						|
    {
 | 
						|
        if (logg2)
 | 
						|
            pdc_logg(p->pdc, "\t\ttext is passed through as is\n");
 | 
						|
 | 
						|
        outtext = (pdc_byte *) ((flags & PDF_USE_TMPALLOC) ?
 | 
						|
             pdc_malloc_tmp(p->pdc, (size_t) len + 2, fn, NULL, NULL) :
 | 
						|
             pdc_malloc(p->pdc, (size_t) len + 2, fn));
 | 
						|
        memcpy(outtext, text, (size_t) len);
 | 
						|
        outtext[len] = 0;
 | 
						|
        outtext[len + 1] = 0;
 | 
						|
        *outlen = len;
 | 
						|
 | 
						|
        outtextformat = pdc_bytes;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
 | 
						|
        if (flags & PDF_FORCE_NEWALLOC)
 | 
						|
            convflags |= PDC_CONV_NEWALLOC;
 | 
						|
 | 
						|
        if (flags & PDF_USE_TMPALLOC)
 | 
						|
            convflags |= PDC_CONV_TMPALLOC;
 | 
						|
 | 
						|
        if (to->glyphcheck == (int) text_replace)
 | 
						|
        {
 | 
						|
            replchar = currfont->replacementchar;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            replchar = (int) to->glyphcheck;
 | 
						|
            if (to->glyphcheck == text_error)
 | 
						|
            {
 | 
						|
                convflags |= PDC_CONV_ENCERROR;
 | 
						|
                if (flags & PDF_KEEP_CONTROL)
 | 
						|
                    convflags |= PDC_CONV_KEEPLBCHAR;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (flags & PDF_KEEP_UNICODE || to->glyphcheck != text_nocheck)
 | 
						|
            inev = ev;
 | 
						|
 | 
						|
 | 
						|
        /* "Pass through mode" for 8-bit text.
 | 
						|
         * The encoding vector must be specified, because
 | 
						|
         * the text could emerge as a Unicode text due to a BOM.
 | 
						|
         */
 | 
						|
        if ((enc >= 0 && inev == NULL) ||
 | 
						|
            (enc == pdc_builtin && !(flags & PDF_KEEP_UNICODE)))
 | 
						|
        {
 | 
						|
            inev = ev;
 | 
						|
            outev = ev;
 | 
						|
            outtextformat = pdc_bytes;
 | 
						|
        }
 | 
						|
 | 
						|
        /* input text format */
 | 
						|
        pdf_get_input_textformat(currfont, &intextformat, &convflags);
 | 
						|
 | 
						|
        /* convert to 8-bit or UTF-16 text string */
 | 
						|
        if (pdc_convert_textstring(p->pdc, intextformat, currfont->codepage,
 | 
						|
                        inev,
 | 
						|
                        NULL, 0,
 | 
						|
                        replchar, intext, len,
 | 
						|
                        &outtextformat, outev, &outtext, outlen,
 | 
						|
                        convflags, pdc_false))
 | 
						|
        {
 | 
						|
            if (newlen > -1)
 | 
						|
                pdc_free_tmp(p->pdc, intext);
 | 
						|
            goto PDF_CHECK_TEXT_ERROR;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (newlen > -1)
 | 
						|
        pdc_free_tmp(p->pdc, intext);
 | 
						|
 | 
						|
    /* check text string */
 | 
						|
    if (outtext != NULL && *outlen)
 | 
						|
    {
 | 
						|
        pdc_ushort *usouttext = (pdc_ushort *) outtext;
 | 
						|
        pdc_ushort uvlist[PDC_MAX_UVLIST];
 | 
						|
        pdc_ushort cglist[PDC_MAX_UVLIST];
 | 
						|
        pdc_bool kcheck = pdc_true;
 | 
						|
        int i = 0, nv = 1, icp = 0, usvp;
 | 
						|
        int code, gid, usv, ic;
 | 
						|
 | 
						|
        (void) i;
 | 
						|
 | 
						|
        /* storage length of a character */
 | 
						|
        if (outtextformat == pdc_utf16)
 | 
						|
        {
 | 
						|
            charlen = 2;
 | 
						|
            newcharlen = 2;
 | 
						|
        }
 | 
						|
 | 
						|
        /* maximal text string length - found out emprirically! */
 | 
						|
        if (*outlen > maxlen && !(flags & PDF_KEEP_TEXTLEN))
 | 
						|
        {
 | 
						|
            int textlen = *outlen;
 | 
						|
 | 
						|
            if (!to->kerning && to->wordspacing == 0.0)
 | 
						|
            {
 | 
						|
                if (currfont->codesize == 1)
 | 
						|
                    textlen /= charlen;
 | 
						|
                maxlen = PDF_MAXTEXTSIZE;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                if (currfont->codesize == 2)
 | 
						|
                    maxlen *= charlen;
 | 
						|
            }
 | 
						|
 | 
						|
            if (textlen > maxlen)
 | 
						|
            {
 | 
						|
                pdc_set_errmsg(p->pdc, PDF_E_TEXT_TOOLONG,
 | 
						|
                               pdc_errprintf(p->pdc, "%d", textlen),
 | 
						|
                               pdc_errprintf(p->pdc, "%d", maxlen), 0, 0);
 | 
						|
                goto PDF_CHECK_TEXT_ERROR;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        len = *outlen / charlen;
 | 
						|
        switch (enc)
 | 
						|
        {
 | 
						|
 | 
						|
 | 
						|
            /*
 | 
						|
             * builtin
 | 
						|
             */
 | 
						|
            case pdc_builtin:
 | 
						|
            if (charlen == 1 || !(flags & PDF_KEEP_UNICODE))
 | 
						|
                newcharlen = 1;
 | 
						|
            for (ic = 0; ic < len; ic++)
 | 
						|
            {
 | 
						|
                if (charlen == 1)
 | 
						|
                    code = (int) outtext[ic];
 | 
						|
                else
 | 
						|
                    code = (int) usouttext[ic];
 | 
						|
 | 
						|
                if (code)
 | 
						|
                {
 | 
						|
                    gid = fnt_get_glyphid(code, &currfont->ft);
 | 
						|
 | 
						|
                    /* glyph id for code value not available */
 | 
						|
                    if (gid <= 0)
 | 
						|
                    {
 | 
						|
                        if (to->glyphcheck == text_error)
 | 
						|
                        {
 | 
						|
                            pdc_set_errmsg(p->pdc, PDF_E_FONT_CODENOTFOUND1,
 | 
						|
                                       pdc_errprintf(p->pdc, "x%02X", code),
 | 
						|
                                       currfont->ft.name, 0, 0);
 | 
						|
                            goto PDF_CHECK_TEXT_ERROR;
 | 
						|
                        }
 | 
						|
                        else if (to->glyphcheck == text_replace)
 | 
						|
                        {
 | 
						|
                            pdc_warning(p->pdc, PDF_E_FONT_CODENOTFOUNDREP1,
 | 
						|
                                       pdc_errprintf(p->pdc, "x%02X", code),
 | 
						|
                                       currfont->ft.name, 0, 0);
 | 
						|
                            code = currfont->replacementcode;
 | 
						|
 | 
						|
                            if (fitres != NULL)
 | 
						|
                                fitres->unknownchars++;
 | 
						|
                        }
 | 
						|
 | 
						|
                        if (fitres != NULL)
 | 
						|
                            fitres->unmappedchars++;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                if (newcharlen == 1)
 | 
						|
                    outtext[icp] = (pdc_byte) code;
 | 
						|
                else
 | 
						|
                    usouttext[icp] = (pdc_ushort) code;
 | 
						|
                icp++;
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
 | 
						|
 | 
						|
            /*
 | 
						|
             * cid
 | 
						|
             */
 | 
						|
            case pdc_cid:
 | 
						|
            /*
 | 
						|
             * pass through. check and temporary conversion in
 | 
						|
             * pdf_calculate_textsize(), because we want to keep native code.
 | 
						|
             */
 | 
						|
            break;
 | 
						|
 | 
						|
 | 
						|
            /*
 | 
						|
             * encoding vector
 | 
						|
             */
 | 
						|
            default:
 | 
						|
            if (charlen == 1 || !(flags & PDF_KEEP_UNICODE))
 | 
						|
                newcharlen = 1;
 | 
						|
            for (ic = 0; ic < len; ic++)
 | 
						|
            {
 | 
						|
                if (charlen == 1)
 | 
						|
                {
 | 
						|
                    code = (int) outtext[ic];
 | 
						|
                    usv = ev->codes[code];
 | 
						|
                    kcheck = code > 0;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    usv = (int) usouttext[ic];
 | 
						|
                    code = pdc_get_encoding_bytecode(p->pdc, ev,
 | 
						|
                                                     (pdc_ushort) usv);
 | 
						|
                    if (code < 0)
 | 
						|
                        code = 0;
 | 
						|
                    kcheck = usv > 0;
 | 
						|
                }
 | 
						|
 | 
						|
                if ((flags & PDF_KEEP_CONTROL) &&
 | 
						|
                    pdc_is_linebreaking_relchar((pdc_ushort) usv))
 | 
						|
                {
 | 
						|
                    kcheck = pdc_false;
 | 
						|
                }
 | 
						|
 | 
						|
                /* glyph check */
 | 
						|
                if (kcheck)
 | 
						|
                {
 | 
						|
                    /* encoding vector hasn't defined [Uni]code */
 | 
						|
                    if (usv <= 0 || code <= 0)
 | 
						|
                    {
 | 
						|
                        if (to->glyphcheck == text_error)
 | 
						|
                        {
 | 
						|
                            if (usv <= 0)
 | 
						|
                            {
 | 
						|
                                pdc_set_errmsg(p->pdc, PDC_E_ENC_NOTDEF_CODE,
 | 
						|
                                           pdc_errprintf(p->pdc, "x%02X", code),
 | 
						|
                                           ev->apiname, 0, 0);
 | 
						|
                                goto PDF_CHECK_TEXT_ERROR;
 | 
						|
                            }
 | 
						|
                            else if (code <= 0)
 | 
						|
                            {
 | 
						|
                                pdc_set_errmsg(p->pdc, PDC_E_ENC_NOTDEF_UNICODE,
 | 
						|
                                           pdc_errprintf(p->pdc, "%04X", usv),
 | 
						|
                                           ev->apiname, 0, 0);
 | 
						|
                                goto PDF_CHECK_TEXT_ERROR;
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                        else if (to->glyphcheck == text_replace)
 | 
						|
                        {
 | 
						|
                            usvp = (usv <= 0) ? code : usv;
 | 
						|
                            nv = pdf_get_approximate_uvlist(p, currfont, ev,
 | 
						|
                                                            usv, pdc_true,
 | 
						|
                                                            fitres,
 | 
						|
                                                            uvlist, cglist);
 | 
						|
                            usv = (int) uvlist[0];
 | 
						|
                            code = (int) cglist[0];
 | 
						|
 | 
						|
                            if (logg2)
 | 
						|
                            {
 | 
						|
                                pdf_logg_glyph_replacement(p, ic, usvp,
 | 
						|
                                              enc, charlen, uvlist, cglist, nv);
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
 | 
						|
                        if (fitres != NULL)
 | 
						|
                            fitres->unmappedchars++;
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        gid = fnt_get_glyphid(code, &currfont->ft);
 | 
						|
 | 
						|
                        /* glyph id for code not available */
 | 
						|
                        if (gid <= 0 && currfont->gid0code != code)
 | 
						|
                        {
 | 
						|
                            if (to->glyphcheck == text_error)
 | 
						|
                            {
 | 
						|
                                pdc_set_errmsg(p->pdc, PDF_E_FONT_CODENOTFOUND2,
 | 
						|
                                         pdc_errprintf(p->pdc, "x%02X", code),
 | 
						|
                                         pdc_errprintf(p->pdc, "%04X", usv),
 | 
						|
                                         currfont->ft.name, 0);
 | 
						|
                                goto PDF_CHECK_TEXT_ERROR;
 | 
						|
                            }
 | 
						|
                            else if (to->glyphcheck == text_replace)
 | 
						|
                            {
 | 
						|
                                pdc_warning(p->pdc, PDF_E_FONT_CODENOTFOUNDREP2,
 | 
						|
                                         pdc_errprintf(p->pdc, "x%02X", code),
 | 
						|
                                         pdc_errprintf(p->pdc, "%04X", usv),
 | 
						|
                                         currfont->ft.name, 0);
 | 
						|
 | 
						|
                                usvp = (usv <= 0) ? code : usv;
 | 
						|
                                nv = pdf_get_approximate_uvlist(p, currfont, ev,
 | 
						|
                                                                usv, pdc_true,
 | 
						|
                                                                fitres,
 | 
						|
                                                                uvlist, cglist);
 | 
						|
                                usv = (int) uvlist[0];
 | 
						|
                                code = (int) cglist[0];
 | 
						|
 | 
						|
                                if (logg2)
 | 
						|
                                {
 | 
						|
                                    pdf_logg_glyph_replacement(p, ic, usvp,
 | 
						|
                                              enc, charlen, uvlist, cglist, nv);
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
 | 
						|
                            if (fitres != NULL)
 | 
						|
                                fitres->unmappedchars++;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                if (newcharlen == 1)
 | 
						|
                {
 | 
						|
                    outtext[icp] = (pdc_byte) code;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    usouttext[icp] = (pdc_ushort) usv;
 | 
						|
                }
 | 
						|
                if (nv > 1)
 | 
						|
                {
 | 
						|
                    if (newcharlen == 1)
 | 
						|
                        ligatlist = pdf_register_ligat(p, ligatlist, icp, nv,
 | 
						|
                                                       cglist, newcharlen);
 | 
						|
                    else
 | 
						|
                        ligatlist = pdf_register_ligat(p, ligatlist,
 | 
						|
                                              icp, nv, uvlist, newcharlen);
 | 
						|
                    nv = 1;
 | 
						|
                }
 | 
						|
                icp++;
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (icp)
 | 
						|
        {
 | 
						|
            /* calculate complete text length */
 | 
						|
            len = newcharlen * icp;
 | 
						|
            if (ligatlist != NULL)
 | 
						|
            {
 | 
						|
                ligat = ligatlist;
 | 
						|
                while (ligat != NULL)
 | 
						|
                {
 | 
						|
                    len += ligat->nb;
 | 
						|
                    ligat = ligat->next;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (len != *outlen)
 | 
						|
            {
 | 
						|
                *outlen = len;
 | 
						|
                if (flags & PDF_USE_TMPALLOC)
 | 
						|
                    outtext = (pdc_byte *) pdc_realloc_tmp(p->pdc, outtext,
 | 
						|
                                           (size_t) (*outlen + newcharlen), fn);
 | 
						|
                else
 | 
						|
                    outtext = (pdc_byte *) pdc_realloc(p->pdc, outtext,
 | 
						|
                                           (size_t) (*outlen + newcharlen), fn);
 | 
						|
                outtext[*outlen] = 0;
 | 
						|
                if (newcharlen == 2)
 | 
						|
                    outtext[*outlen + 1] = 0;
 | 
						|
            }
 | 
						|
 | 
						|
            /* insert ligature parts */
 | 
						|
            if (ligatlist != NULL)
 | 
						|
            {
 | 
						|
                int nbrest, nbgap, nbmove = 0;
 | 
						|
 | 
						|
                len = newcharlen * icp;
 | 
						|
                ligat = ligatlist;
 | 
						|
                while (ligat != NULL)
 | 
						|
                {
 | 
						|
                    nbgap = ligat->nb;
 | 
						|
                    icp = ligat->icp + nbmove;
 | 
						|
                    nbrest = len - icp;
 | 
						|
                    icp += newcharlen;
 | 
						|
                    ic = icp + nbgap;
 | 
						|
 | 
						|
                    memmove(&outtext[ic], &outtext[icp], (size_t) nbrest);
 | 
						|
                    memcpy(&outtext[icp], ligat->culist, (size_t) nbgap);
 | 
						|
 | 
						|
                    nbmove += nbgap;
 | 
						|
                    len += nbgap;
 | 
						|
 | 
						|
                    ligat = ligat->next;
 | 
						|
                }
 | 
						|
 | 
						|
                pdf_cleanup_ligat(p, ligatlist);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    *outtext_p = outtext;
 | 
						|
    *outcharlen = newcharlen;
 | 
						|
 | 
						|
    if (logg1)
 | 
						|
    {
 | 
						|
        if (logg2)
 | 
						|
            pdc_logg_hexdump(p->pdc, "converted text", "\t\t",
 | 
						|
                             (char *) outtext, *outlen);
 | 
						|
        else
 | 
						|
            pdc_logg(p->pdc,
 | 
						|
                "\tChecked and converted text of length %d: \"%T\"\n",
 | 
						|
                *outlen, outtext, *outlen);
 | 
						|
    }
 | 
						|
 | 
						|
    if (*outlen)
 | 
						|
        return pdc_true;
 | 
						|
 | 
						|
    verbose = pdc_false;
 | 
						|
 | 
						|
    PDF_CHECK_TEXT_ERROR:
 | 
						|
 | 
						|
    if (outtext != NULL)
 | 
						|
    {
 | 
						|
        if (flags & PDF_USE_TMPALLOC)
 | 
						|
            pdc_free_tmp(p->pdc, outtext);
 | 
						|
        else
 | 
						|
            pdc_free(p->pdc, outtext);
 | 
						|
    }
 | 
						|
 | 
						|
    pdf_cleanup_ligat(p, ligatlist);
 | 
						|
 | 
						|
    if (verbose)
 | 
						|
        PDC_RETHROW(p->pdc);
 | 
						|
 | 
						|
    *outtext_p = NULL;
 | 
						|
    *outlen = 0;
 | 
						|
 | 
						|
    return pdc_false;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ------------------------ Text width functions ------------------------ */
 | 
						|
 | 
						|
/* Calculates the geometrical width and height of input text string
 | 
						|
 * depending on
 | 
						|
 *
 | 
						|
 *      to->font, to->fontsize, to->kerning,
 | 
						|
 *      to->charspacing, to->horizscaling, to->wordspacing,
 | 
						|
 *      to->xadvancelist
 | 
						|
 *
 | 
						|
 * In the case of vertical writing mode the width is the maximum
 | 
						|
 * of all glyph widths and height the height of the text string.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
pdc_scalar
 | 
						|
pdf_calculate_textsize(PDF *p, const pdc_byte *text, int len, int charlen,
 | 
						|
                       pdf_text_options *to, int breakchar, pdc_scalar *height,
 | 
						|
                       pdc_bool verbose)
 | 
						|
{
 | 
						|
    pdf_font *currfont = &p->fonts[to->font];
 | 
						|
    pdc_encoding enc = currfont->ft.enc;
 | 
						|
    pdc_byte *tmpstring = (pdc_byte *) text;
 | 
						|
    pdc_ushort *ustext = (pdc_ushort *) text;
 | 
						|
    pdc_scalar glwidth = 0, width = 0;
 | 
						|
    pdc_scalar font2user = to->fontsize / 1000.0;
 | 
						|
    pdc_bool kbreak = pdc_false;
 | 
						|
    int usv, ic, icc, numglyphs = 0, numspaces = 0;
 | 
						|
 | 
						|
    /* We cannot handle empty strings or fonts without widths info */
 | 
						|
    if (!len || currfont->widthsmissing)
 | 
						|
    {
 | 
						|
        if (height)
 | 
						|
            *height = 0.0;
 | 
						|
        return width;
 | 
						|
    }
 | 
						|
 | 
						|
    if (enc != pdc_cid)
 | 
						|
        len /= charlen;
 | 
						|
 | 
						|
    for (ic = 0; ic < len; )
 | 
						|
    {
 | 
						|
        icc = ic;
 | 
						|
 | 
						|
        {
 | 
						|
            if (charlen == 1)
 | 
						|
            {
 | 
						|
                usv = (int) text[ic];
 | 
						|
            }
 | 
						|
            else if (enc == pdc_unicode)
 | 
						|
            {
 | 
						|
                usv = pdc_char16_to_char32(p->pdc, ustext, &ic, len, verbose);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                usv = (int) ustext[ic];
 | 
						|
            }
 | 
						|
 | 
						|
            /* count spaces */
 | 
						|
            if (usv == (int) currfont->ft.spacechar)
 | 
						|
                numspaces++;
 | 
						|
 | 
						|
            /* break character */
 | 
						|
            if (breakchar > 0)
 | 
						|
                kbreak = (usv == breakchar);
 | 
						|
 | 
						|
            ic++;
 | 
						|
        }
 | 
						|
 | 
						|
        /* start by adding in the width of the character */
 | 
						|
        if (currfont->opt.monospace)
 | 
						|
        {
 | 
						|
            glwidth = (pdc_scalar) currfont->opt.monospace;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            glwidth = (pdc_scalar) fnt_get_glyphwidth(usv, &currfont->ft);
 | 
						|
            if (glwidth == FNT_MISSING_WIDTH)
 | 
						|
                glwidth = currfont->ft.m.defwidth;
 | 
						|
        }
 | 
						|
 | 
						|
        /* count glyphs */
 | 
						|
        numglyphs++;
 | 
						|
 | 
						|
        /* horizontal or vertical writing mode */
 | 
						|
        if (!currfont->ft.vertical)
 | 
						|
        {
 | 
						|
            width += glwidth;
 | 
						|
 | 
						|
 | 
						|
            /* supplied glyph widths */
 | 
						|
            if (icc < to->nglyphs)
 | 
						|
            {
 | 
						|
                pdc_scalar shift = to->xadvancelist[icc] / font2user - glwidth;
 | 
						|
                width += shift;
 | 
						|
                if (p->pdc->ptfrun)
 | 
						|
                    shift = PDC_ROUND(1e10 * shift) / 1e10;
 | 
						|
                shift = PDC_ROUND(1e1 * shift) / 1e1;
 | 
						|
                to->xadvancelist[icc] = shift;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            /* maximum of width */
 | 
						|
            if (glwidth > width)
 | 
						|
                width = glwidth;
 | 
						|
        }
 | 
						|
 | 
						|
        /* length of text part ranging to decimal character */
 | 
						|
        if (kbreak)
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (breakchar > 0 && !kbreak)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    /* charspacing and wordspacing */
 | 
						|
    if (!currfont->ft.vertical)
 | 
						|
    {
 | 
						|
        if (to->charspacing)
 | 
						|
            width += numglyphs * to->charspacing / font2user;
 | 
						|
        if (to->wordspacing)
 | 
						|
            width += numspaces * to->wordspacing / font2user;
 | 
						|
        if (height)
 | 
						|
            *height = 0.0;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        /* height for positive y direction.
 | 
						|
         * Acrobat calculates with negative direction (see pdf_place_text).
 | 
						|
         */
 | 
						|
        *height = numglyphs * (to->fontsize + -to->charspacing) +
 | 
						|
                  numspaces * (-to->wordspacing);
 | 
						|
    }
 | 
						|
 | 
						|
    /* take horizontal scaling factor and font scaling factor into account */
 | 
						|
    width *= font2user * to->horizscaling;
 | 
						|
 | 
						|
    if (tmpstring != text)
 | 
						|
        pdc_free_tmp(p->pdc, tmpstring);
 | 
						|
 | 
						|
    return width;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
pdc_scalar
 | 
						|
pdf_trim_textwidth(pdc_scalar width, pdf_text_options *to)
 | 
						|
{
 | 
						|
    if (!PDC_FLOAT_ISNULL(width))
 | 
						|
         width -= to->horizscaling * to->charspacing;
 | 
						|
 | 
						|
    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, height = 0;
 | 
						|
    pdf_text_options to = *p->curr_ppt->currto;
 | 
						|
 | 
						|
    len = pdc_check_text_length(p->pdc, &text, len, PDF_MAXTEXTSIZE);
 | 
						|
    if (!len)
 | 
						|
        return 0.0;
 | 
						|
 | 
						|
    pdf_check_handle(p, font, pdc_fonthandle);
 | 
						|
 | 
						|
    pdc_check_number_zero(p->pdc, "fontsize", fontsize);
 | 
						|
 | 
						|
    /* convert text string */
 | 
						|
    to.font = font;
 | 
						|
    to.fontsize = fontsize;
 | 
						|
    if (pdf_check_textstring(p, text, len, PDF_KEEP_TEXTLEN | PDF_USE_TMPALLOC,
 | 
						|
                             &to, NULL, &utext, &len, &charlen, pdc_true))
 | 
						|
    {
 | 
						|
        width = pdf_calculate_textsize(p, utext, len, charlen,
 | 
						|
                                       &to, -1, &height, pdc_true);
 | 
						|
    }
 | 
						|
 | 
						|
    return width;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ------------------------ Text output functions ------------------------ */
 | 
						|
 | 
						|
static void
 | 
						|
pdf_convert_text_towinansi(PDF *p, const pdc_byte *fromtext, int len,
 | 
						|
                           pdc_byte *totext, pdf_font *currfont)
 | 
						|
{
 | 
						|
    pdc_encodingvector *evfrom =
 | 
						|
        pdc_get_encoding_vector(p->pdc, currfont->ft.enc);
 | 
						|
    pdc_encodingvector *evto =
 | 
						|
        pdc_get_encoding_vector(p->pdc, 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 if (font > -1)
 | 
						|
    {
 | 
						|
        static const char fn[] = "pdf_put_fieldtext";
 | 
						|
        pdf_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,
 | 
						|
                   pdf_font *currfont)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdf_put_textstring";
 | 
						|
    pdc_byte *tmpstring = (pdc_byte *) text;
 | 
						|
 | 
						|
    (void) charlen;
 | 
						|
 | 
						|
    if (len)
 | 
						|
    {
 | 
						|
 | 
						|
            /* Convert 8-bit code string to winansi */
 | 
						|
            if (currfont->towinansi != pdc_invalidenc)
 | 
						|
            {
 | 
						|
                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)
 | 
						|
{
 | 
						|
    pdf_font *currfont = &p->fonts[to->font];
 | 
						|
    pdc_ushort *ustext = (pdc_ushort *) text;
 | 
						|
    pdc_byte *currtext;
 | 
						|
    pdc_scalar shift;
 | 
						|
    pdc_bool isutf16;
 | 
						|
    int currlen, nchars;
 | 
						|
    int leftchar = 0, rightchar;
 | 
						|
    int ic, icp, incr = charlen;
 | 
						|
 | 
						|
    currlen = 0;
 | 
						|
    currtext = text;
 | 
						|
    nchars = len/charlen;
 | 
						|
    isutf16 = charlen == 2 &&
 | 
						|
              currfont->codesize == 2 &&
 | 
						|
              currfont->ft.enc == pdc_unicode;
 | 
						|
    for (ic = 0; ic < nchars; ic++)
 | 
						|
    {
 | 
						|
        if (charlen == 1)
 | 
						|
        {
 | 
						|
            rightchar = (int) text[ic];
 | 
						|
        }
 | 
						|
        else if(!isutf16)
 | 
						|
        {
 | 
						|
            rightchar = (int) ustext[ic];
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            icp = ic;
 | 
						|
            rightchar =
 | 
						|
                pdc_char16_to_char32(p->pdc, ustext, &ic, nchars, pdc_true);
 | 
						|
            incr = (1 + ic - icp) * charlen;
 | 
						|
        }
 | 
						|
 | 
						|
        if (ic)
 | 
						|
        {
 | 
						|
            /* PDF wants the inverse shift amount
 | 
						|
             * (positive numbers move left, negative move right!) */
 | 
						|
 | 
						|
            if (spaceshift != 0 && leftchar == (int) currfont->ft.spacechar)
 | 
						|
                shift = -spaceshift;
 | 
						|
            else
 | 
						|
                shift = 0;
 | 
						|
 | 
						|
 | 
						|
            if (ic <= to->nglyphs)
 | 
						|
                shift -= to->xadvancelist[ic-1];
 | 
						|
 | 
						|
            if (shift)
 | 
						|
            {
 | 
						|
                pdf_put_textstring(p, currtext, currlen, charlen, currfont);
 | 
						|
                pdc_printf(p->out, "%f", shift);
 | 
						|
                currtext = &text[charlen * ic];
 | 
						|
                currlen = 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        leftchar = rightchar;
 | 
						|
        currlen += incr;
 | 
						|
    }
 | 
						|
 | 
						|
    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
 | 
						|
#define PDF_ITALICANGLE_DEFAULT -12
 | 
						|
 | 
						|
static void
 | 
						|
pdf_place_singletext(PDF *p, pdc_byte *text, int len, int charlen,
 | 
						|
                     pdf_text_options *to, pdc_scalar tx, pdc_scalar ty,
 | 
						|
                     pdc_scalar width, pdc_scalar height, pdc_scalar leading,
 | 
						|
                     pdc_bool cont)
 | 
						|
{
 | 
						|
    pdf_tstate *ts = &p->curr_ppt->tstate[p->curr_ppt->sl];
 | 
						|
    pdf_font *currfont = &p->fonts[to->font];
 | 
						|
    pdc_scalar dx, dy, spaceshift = 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;
 | 
						|
 | 
						|
    /* default linewidth for underlinewidth and strokewidth */
 | 
						|
    if (hasdeco || (to->mask & (1 << to_strokewidth)))
 | 
						|
    {
 | 
						|
        if (currfont->ft.m.underlineThickness == 0)
 | 
						|
            currfont->ft.m.underlineThickness = 50;
 | 
						|
        deflinewidth = fabs(to->horizscaling * font2user *
 | 
						|
                            currfont->ft.m.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, fs, trise, lineheight;
 | 
						|
        pdc_scalar txe = 0, tye = 0;
 | 
						|
        pdc_scalar lineposition = 0;
 | 
						|
 | 
						|
        fs = p->ydirection * font2user;
 | 
						|
        trise = p->ydirection * to->textrise;
 | 
						|
        lineheight = fs * currfont->ft.m.ascender;
 | 
						|
        delta = scale * (fs * currfont->ft.m.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;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            lineposition = p->ydirection * to->underlineposition;
 | 
						|
            if ((to->pcmask & (1 << to_underlineposition)))
 | 
						|
                lineposition *= to->fontsize;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!currfont->ft.vertical)
 | 
						|
        {
 | 
						|
            txe = tx + width;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            txe = tx - width / 2.0;
 | 
						|
            tye = ty - p->ydirection *  height;
 | 
						|
            lineposition *= p->ydirection;
 | 
						|
            delta = fabs(delta);
 | 
						|
        }
 | 
						|
 | 
						|
        pdf__setlinecap(p, 0);
 | 
						|
        if (!(to->mask & (1 << to_dasharray)))
 | 
						|
            pdf__setdash(p, 0, 0);
 | 
						|
 | 
						|
        if (to->underline)
 | 
						|
        {
 | 
						|
            pdf__setlinewidth(p, linewidth);
 | 
						|
            if (!currfont->ft.vertical)
 | 
						|
            {
 | 
						|
                pdf__moveto(p, tx,  ty + lineposition);
 | 
						|
                pdf__lineto(p, txe, ty + lineposition);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                pdf__moveto(p, txe + lineposition, ty);
 | 
						|
                pdf__lineto(p, txe + lineposition, tye);
 | 
						|
            }
 | 
						|
            pdf__stroke(p);
 | 
						|
        }
 | 
						|
 | 
						|
        if (to->strikeout)
 | 
						|
        {
 | 
						|
            pdf__setlinewidth(p, deflinewidth);
 | 
						|
            if (!currfont->ft.vertical)
 | 
						|
            {
 | 
						|
                pdf__moveto(p, tx,  ty + lineheight/2 + delta);
 | 
						|
                pdf__lineto(p, txe, ty + lineheight/2 + delta);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                pdf__moveto(p, tx, ty);
 | 
						|
                pdf__lineto(p, tx, tye);
 | 
						|
            }
 | 
						|
            pdf__stroke(p);
 | 
						|
        }
 | 
						|
 | 
						|
        if (to->overline)
 | 
						|
        {
 | 
						|
            pdf__setlinewidth(p, deflinewidth);
 | 
						|
            if (!currfont->ft.vertical)
 | 
						|
            {
 | 
						|
                delta = scale * (fs * currfont->ft.m.underlinePosition - trise);
 | 
						|
                pdf__moveto(p, tx,  ty + lineheight - delta);
 | 
						|
                pdf__lineto(p, txe, ty + lineheight - delta);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                pdf__moveto(p, txe + width + delta, ty);
 | 
						|
                pdf__lineto(p, txe + width + delta, tye);
 | 
						|
            }
 | 
						|
            pdf__stroke(p);
 | 
						|
        }
 | 
						|
 | 
						|
        pdf__restore(p);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    /* wordspacing */
 | 
						|
    if (!PDC_FLOAT_ISNULL(to->wordspacing))
 | 
						|
    {
 | 
						|
        spaceshift = to->wordspacing / font2user;
 | 
						|
        if (p->pdc->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) ||
 | 
						|
        currfont->metricflags & font_italic)
 | 
						|
    {
 | 
						|
        if (!currfont->ft.vertical)
 | 
						|
        {
 | 
						|
            pdc_scalar italicangle = -p->ydirection * to->italicangle;
 | 
						|
 | 
						|
            if (currfont->metricflags & font_italic && italicangle == 0)
 | 
						|
                italicangle = -p->ydirection * PDF_ITALICANGLE_DEFAULT;
 | 
						|
 | 
						|
            if (ts->hs < 0)
 | 
						|
                italicangle = -italicangle;
 | 
						|
 | 
						|
            pdc_printf(p->out, "1 0 %f 1 %f %f Tm\n",
 | 
						|
                       tan(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 */
 | 
						|
    if (!currfont->ft.vertical)
 | 
						|
    {
 | 
						|
        ts->currtx = tx + width;
 | 
						|
        ts->currty = ty;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        ts->currtx = tx;
 | 
						|
        ts->currty = ty - p->ydirection *  height;
 | 
						|
    }
 | 
						|
    ts->prevtx = ts->currtx;
 | 
						|
    ts->prevty = ts->currty;
 | 
						|
 | 
						|
    if (to->textrendering >= PDF_RENDERMODE_FILLCLIP)
 | 
						|
        pdf_end_text(p);
 | 
						|
}
 | 
						|
 | 
						|
#define PDF_FAKEBOLD_OFFSET 0.03    /* 3% of font size */
 | 
						|
 | 
						|
void
 | 
						|
pdf_place_text(PDF *p, pdc_byte *text, int len, int charlen,
 | 
						|
               pdf_text_options *to, pdc_scalar width, pdc_scalar height,
 | 
						|
               pdc_bool cont)
 | 
						|
{
 | 
						|
    pdf_tstate *ts = &p->curr_ppt->tstate[p->curr_ppt->sl];
 | 
						|
    pdf_font *currfont = &p->fonts[to->font];
 | 
						|
    pdc_scalar tx, ty, leading = 0;
 | 
						|
 | 
						|
    /* text position */
 | 
						|
    if (!cont)
 | 
						|
    {
 | 
						|
        tx = ts->currtx;
 | 
						|
        ty = ts->currty;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        leading = p->ydirection * to->leading;
 | 
						|
        tx = ts->linetx;
 | 
						|
        ty = ts->currty - leading;
 | 
						|
    }
 | 
						|
 | 
						|
    pdf_place_singletext(p, text, len, charlen, to, tx, ty,
 | 
						|
                         width, height, leading, cont);
 | 
						|
 | 
						|
    /* text bolding */
 | 
						|
    if (to->fakebold || currfont->metricflags & font_bold)
 | 
						|
    {
 | 
						|
        static const pdc_scalar fx[] = {0, 0.70711, 1};
 | 
						|
        static const pdc_scalar fy[] = {1, 0.70711, 0};
 | 
						|
        pdc_scalar offset, currtx, currty, linetx;
 | 
						|
        int it, nt = 3;
 | 
						|
 | 
						|
        offset = PDF_FAKEBOLD_OFFSET * to->fontsize;
 | 
						|
 | 
						|
        linetx = ts->linetx;
 | 
						|
        currtx = ts->currtx;
 | 
						|
        currty = ts->currty;
 | 
						|
        for (it = 0; it < nt; it++)
 | 
						|
        {
 | 
						|
            pdf__set_text_pos(p, tx + fx[it] * offset,
 | 
						|
                              ty + p->ydirection * fy[it] * offset);
 | 
						|
            pdf_place_singletext(p, text, len, charlen, to,
 | 
						|
                                 ts->currtx, ts->currty,
 | 
						|
                                 width, height, leading, pdc_false);
 | 
						|
        }
 | 
						|
        pdf__set_text_pos(p, currtx, currty);
 | 
						|
        ts->linetx = linetx;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* --------------------- 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 = 0, height = 0;
 | 
						|
 | 
						|
    len = pdc_check_text_length(p->pdc, &text, len, PDF_MAXTEXTSIZE);
 | 
						|
    if (!len && !cont)
 | 
						|
        return;
 | 
						|
 | 
						|
    /* no font set */
 | 
						|
    if (currto->font == -1)
 | 
						|
        pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0);
 | 
						|
 | 
						|
    if (len)
 | 
						|
    {
 | 
						|
        /* convert text string */
 | 
						|
        if (pdf_check_textstring(p, text, len, PDF_USE_TMPALLOC,
 | 
						|
                        currto, NULL, &utext, &len, &charlen, pdc_true))
 | 
						|
        {
 | 
						|
            /* width and height of text string */
 | 
						|
            width = pdf_calculate_textsize(p, utext, len, charlen,
 | 
						|
                                           currto, -1, &height, pdc_true);
 | 
						|
        }
 | 
						|
        else if (!cont)
 | 
						|
        {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        utext = (pdc_byte *) pdc_calloc_tmp(p->pdc, 2, fn, NULL, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    /* place text */
 | 
						|
    pdf_place_text(p, utext, len, charlen, currto, width, height, 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, height;
 | 
						|
 | 
						|
    len = pdc_check_text_length(p->pdc, &text, len, PDF_MAXTEXTSIZE);
 | 
						|
    if (!len)
 | 
						|
        return;
 | 
						|
 | 
						|
    /* no font set */
 | 
						|
    if (currto->font == -1)
 | 
						|
        pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0);
 | 
						|
 | 
						|
    /* convert text string */
 | 
						|
    if (pdf_check_textstring(p, text, len, PDF_USE_TMPALLOC,
 | 
						|
                             currto, NULL, &utext, &len, &charlen, pdc_true))
 | 
						|
    {
 | 
						|
        /* 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_textsize(p, utext, len, charlen,
 | 
						|
                                       currto, -1, &height, pdc_true);
 | 
						|
 | 
						|
 | 
						|
        /* place text */
 | 
						|
        pdf_place_text(p, utext, len, charlen, currto, width, height,
 | 
						|
                       pdc_false);
 | 
						|
 | 
						|
        currto->xadvancelist = NULL;
 | 
						|
        currto->nglyphs = 0;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* --------------------------- Leader functions ---------------------------- */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* ----------------------- Text fitting function ------------------------ */
 | 
						|
 | 
						|
 | 
						|
/* 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
 | 
						|
    PDF_FIT_OPTIONS6
 | 
						|
 | 
						|
    PDF_FONT_OPTIONS1
 | 
						|
    PDF_FONT_OPTIONS2
 | 
						|
 | 
						|
    PDF_ERRORPOLICY_OPTION
 | 
						|
    PDC_OPT_TERMINATE
 | 
						|
};
 | 
						|
 | 
						|
pdc_resopt *
 | 
						|
pdf_parse_fittextline_optlist(PDF *p, pdf_text_options *to,
 | 
						|
                              pdf_fit_options *fit, const char *optlist)
 | 
						|
{
 | 
						|
    pdc_resopt *resopts = NULL;
 | 
						|
    pdf_font_options fo;
 | 
						|
 | 
						|
    /* *to must be initialized */
 | 
						|
 | 
						|
    /* initialize fit options */
 | 
						|
    pdf_init_fit_options(p, pdc_false, fit);
 | 
						|
    fit->flags |= is_textline;
 | 
						|
 | 
						|
    /* initialize font options */
 | 
						|
    pdf_init_font_options(p, &fo);
 | 
						|
    fo.flags |= is_textline;
 | 
						|
 | 
						|
    /* parsing option list */
 | 
						|
    if (optlist && strlen(optlist))
 | 
						|
    {
 | 
						|
        pdc_clientdata data;
 | 
						|
 | 
						|
        pdf_set_clientdata(p, &data);
 | 
						|
        resopts = pdc_parse_optionlist(p->pdc, optlist,
 | 
						|
                      pdf_fit_textline_options, &data, pdc_true);
 | 
						|
 | 
						|
        pdf_get_font_options(p, &fo, resopts);
 | 
						|
        pdf_get_text_options(p, to, resopts);
 | 
						|
        pdf_get_fit_options(p, pdc_false, fit, resopts);
 | 
						|
    }
 | 
						|
 | 
						|
    /* font options specified */
 | 
						|
    if (fo.mask & (1 << fo_fontname) && fo.mask & (1 << fo_encoding))
 | 
						|
    {
 | 
						|
        to->font = pdf_load_font_internal(p, &fo);
 | 
						|
        to->mask |= (1L << to_font);
 | 
						|
        to->fontset |= (1L << to_font);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        pdf_cleanup_font_options(p, &fo);
 | 
						|
    }
 | 
						|
 | 
						|
    return resopts;
 | 
						|
}
 | 
						|
 | 
						|
static pdc_bool
 | 
						|
pdf_parse_textline_options(PDF *p, const char *text, int len,
 | 
						|
                           pdf_text_options *to, pdf_fit_options *fit,
 | 
						|
                           const char *optlist)
 | 
						|
{
 | 
						|
    pdf_ppt *ppt = p->curr_ppt;
 | 
						|
 | 
						|
    len = pdc_check_text_length(p->pdc, &text, len, PDF_MAXTEXTSIZE);
 | 
						|
    if (!len)
 | 
						|
        return pdc_false;
 | 
						|
 | 
						|
    /* initialize text options */
 | 
						|
    *to = *ppt->currto;
 | 
						|
    to->text = (char *) text;
 | 
						|
    to->textlen = len;
 | 
						|
 | 
						|
    /* parsing option list */
 | 
						|
    pdf_parse_fittextline_optlist(p, to, fit, optlist);
 | 
						|
 | 
						|
    /* no font set */
 | 
						|
    if (to->font == -1)
 | 
						|
        pdc_error(p->pdc, PDF_E_TEXT_NOFONT, 0, 0, 0, 0);
 | 
						|
 | 
						|
    /* no font size set */
 | 
						|
    if (to->fontsize == PDC_FLOAT_MIN)
 | 
						|
    {
 | 
						|
            pdc_error(p->pdc, PDF_E_TEXT_NOFONTSIZESET, 0, 0, 0, 0);
 | 
						|
    }
 | 
						|
 | 
						|
    return pdc_true;
 | 
						|
}
 | 
						|
 | 
						|
pdc_bool
 | 
						|
pdf_fit_textline_internal(PDF *p, pdf_fitres *fitres,
 | 
						|
                          pdf_text_options *to, pdf_fit_options *fit,
 | 
						|
                          pdc_matrix *matrix)
 | 
						|
{
 | 
						|
    pdc_bool logg5 = pdc_logg_is_enabled(p->pdc, 5, trc_text);
 | 
						|
    pdf_ppt *ppt = p->curr_ppt;
 | 
						|
    pdf_font *currfont = &p->fonts[to->font];
 | 
						|
    pdc_byte *utext = (pdc_byte *) "";
 | 
						|
    int len, charlen;
 | 
						|
    pdc_bool blind = (fitres != NULL) ? pdc_true : pdc_false;
 | 
						|
    pdc_bool vertical = currfont->ft.vertical;
 | 
						|
 | 
						|
    pdc_matrix ctm = ppt->gstate[ppt->sl].ctm;
 | 
						|
    pdc_matrix m, mm;
 | 
						|
    pdc_vector elemsize, elemscale, elemmargin, textrelpos, fitrelpos;
 | 
						|
    pdc_vector polyline[5];
 | 
						|
    pdc_scalar textyextent[2];
 | 
						|
    pdc_box fitbox, elembox;
 | 
						|
    pdc_scalar ss, width, height, boxwidth, boxheight, fontsizeref;
 | 
						|
    pdc_scalar ascender, capheight, xheight, descender;
 | 
						|
    pdc_scalar x, y, tx = 0, ty = 0, basey = 0;
 | 
						|
    pdc_bool hasfitbox = pdc_false;
 | 
						|
    pdc_bool hasboxwidth = pdc_false;
 | 
						|
    pdc_bool verbose = pdc_true;
 | 
						|
    pdc_scalar font2user;
 | 
						|
    int indangle = fit->orientate / 90;
 | 
						|
    int i;
 | 
						|
 | 
						|
    (void) ppt;
 | 
						|
 | 
						|
    /* box size */
 | 
						|
    boxwidth = fit->boxsize[0];
 | 
						|
    boxheight = fit->boxsize[1];
 | 
						|
 | 
						|
    /* reference for font size as percentage */
 | 
						|
    if (indangle % 2)
 | 
						|
        fontsizeref = boxwidth;
 | 
						|
    else
 | 
						|
        fontsizeref = boxheight;
 | 
						|
 | 
						|
    /* calculate and set text options */
 | 
						|
    pdf_calculate_text_options(p, to, pdc_false, 1.0, PDC_FLOAT_PREC,
 | 
						|
                               fontsizeref);
 | 
						|
    if (!blind)
 | 
						|
        pdf_set_text_options(p, to);
 | 
						|
    else
 | 
						|
        verbose = fitres->verbose;
 | 
						|
 | 
						|
    /* convert text string */
 | 
						|
    if (!pdf_check_textstring(p, to->text, to->textlen, PDF_USE_TMPALLOC,
 | 
						|
                              to, fitres, &utext, &len, &charlen, verbose))
 | 
						|
        return pdc_false;
 | 
						|
 | 
						|
    if (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 and height of text */
 | 
						|
    width = pdf_calculate_textsize(p, utext, len, charlen,
 | 
						|
                                   to, -1, &height, pdc_true);
 | 
						|
    width = pdf_trim_textwidth(width, to);
 | 
						|
 | 
						|
    /* incredible bug #1451
 | 
						|
    if (PDC_FLOAT_ISNULL(width))
 | 
						|
        return -1;
 | 
						|
    */
 | 
						|
 | 
						|
    /* font specifics */
 | 
						|
    font2user = to->fontsize / 1000.0;
 | 
						|
    ascender = font2user * currfont->ft.m.ascender;
 | 
						|
    capheight = font2user * currfont->ft.m.capHeight;
 | 
						|
    xheight = font2user * currfont->ft.m.xHeight;
 | 
						|
    descender = font2user * currfont->ft.m.descender;
 | 
						|
 | 
						|
    /* margin lower left corner */
 | 
						|
    elemmargin.x = fit->margin[0];
 | 
						|
    elemmargin.y = fit->margin[1];
 | 
						|
 | 
						|
    /* new box size */
 | 
						|
    boxwidth -= 2 * elemmargin.x;
 | 
						|
    if (boxwidth < 0)
 | 
						|
        boxwidth = 0;
 | 
						|
    boxheight -= 2 * elemmargin.y;
 | 
						|
    if (boxheight < 0)
 | 
						|
        boxheight = 0;
 | 
						|
    hasboxwidth = boxwidth > PDC_FLOAT_PREC;
 | 
						|
    hasfitbox = hasboxwidth && boxheight > PDC_FLOAT_PREC;
 | 
						|
 | 
						|
    /* kind of text box */
 | 
						|
    pdf_get_mbox_boxheight(p, fit->matchbox, textyextent);
 | 
						|
 | 
						|
    /* text x size */
 | 
						|
    elemsize.x = width;
 | 
						|
 | 
						|
    /* TODO: for vertical text */
 | 
						|
    /* text y size */
 | 
						|
    if (!vertical)
 | 
						|
    {
 | 
						|
        height = 0;
 | 
						|
        for (i = 0; i < 2; i++)
 | 
						|
        {
 | 
						|
            basey = 0;
 | 
						|
            if (textyextent[i] <= 0)
 | 
						|
            {
 | 
						|
                switch ((int) textyextent[i])
 | 
						|
                {
 | 
						|
                    case text_none:
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case text_ascender:
 | 
						|
                    basey = ascender;
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case text_capheight:
 | 
						|
                    basey = capheight;
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case text_xheight:
 | 
						|
                    basey = xheight;
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case text_descender:
 | 
						|
                    basey = -descender;
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case text_textrise:
 | 
						|
                    basey = to->textrise;
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case text_fontsize:
 | 
						|
                    basey = to->fontsize;
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case text_leading:
 | 
						|
                    basey = to->leading;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                basey = textyextent[i];
 | 
						|
            }
 | 
						|
            height += basey;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    elemsize.y = height;
 | 
						|
 | 
						|
    /* orientation */
 | 
						|
    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 = boxwidth;
 | 
						|
    fitbox.ur.y = boxheight;
 | 
						|
 | 
						|
    /* relativ position in fit and text box */
 | 
						|
    fitrelpos.x = fit->position[0] / 100.0;
 | 
						|
    fitrelpos.y = fit->position[1] / 100.0;
 | 
						|
    textrelpos = fitrelpos;
 | 
						|
 | 
						|
    /* decimal character and position */
 | 
						|
    if (fit->alignchar)
 | 
						|
    {
 | 
						|
        pdc_encoding enc = currfont->ft.enc;
 | 
						|
        pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc);
 | 
						|
        pdc_scalar decwidth, decheight, pos1, pos2;
 | 
						|
        int poschar = (int) fit->alignchar;
 | 
						|
 | 
						|
        switch(enc)
 | 
						|
        {
 | 
						|
            case pdc_cid:
 | 
						|
            /* non-Unicode compatible CMaps seem to work (see bug #1605)
 | 
						|
            if (currfont->codesize != 2)
 | 
						|
                poschar = -1;
 | 
						|
            */
 | 
						|
            break;
 | 
						|
 | 
						|
            case pdc_glyphid:
 | 
						|
            poschar = fnt_get_glyphid(poschar, &currfont->ft);
 | 
						|
            break;
 | 
						|
 | 
						|
            case pdc_builtin:
 | 
						|
            poschar = -1;
 | 
						|
            break;
 | 
						|
 | 
						|
            default:
 | 
						|
            if (ev != NULL && charlen == 1)
 | 
						|
            {
 | 
						|
                poschar = pdc_get_encoding_bytecode(p->pdc, ev,
 | 
						|
                                                    (pdc_ushort) poschar);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (to->glyphcheck == text_error && poschar == -1)
 | 
						|
        {
 | 
						|
            pdc_set_errmsg(p->pdc, PDF_E_TEXT_ALIGNCHARNOTFOUND,
 | 
						|
                           pdc_errprintf(p->pdc, "%04X", fit->alignchar),
 | 
						|
                                         0, 0, 0);
 | 
						|
            if (verbose)
 | 
						|
                PDC_RETHROW(p->pdc);
 | 
						|
 | 
						|
            return pdc_false;
 | 
						|
        }
 | 
						|
 | 
						|
        /* width and height of text part ranging to decimal character */
 | 
						|
        decwidth = pdf_calculate_textsize(p, utext, len, charlen,
 | 
						|
                                          to, poschar, &decheight, pdc_true);
 | 
						|
 | 
						|
        /* position found */
 | 
						|
        if (decwidth > 0 && !PDC_FLOAT_ISNULL(width))
 | 
						|
        {
 | 
						|
            /* relative position of position character */
 | 
						|
            pos1 = decwidth / width;
 | 
						|
            pos2 = 1 - pos1;
 | 
						|
            i = vertical ? ((indangle + 3) % 4) : indangle;
 | 
						|
            switch (i)
 | 
						|
            {
 | 
						|
                case 0:
 | 
						|
                textrelpos.x = pos1;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 1:
 | 
						|
                textrelpos.y = pos1;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 2:
 | 
						|
                textrelpos.x = pos2;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 3:
 | 
						|
                textrelpos.y = pos2;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* calculate image box */
 | 
						|
    pdc_place_element(fit->fitmethod, fit->shrinklimit, &fitbox, &fitrelpos,
 | 
						|
                      &elemsize, &textrelpos, &elembox, &elemscale);
 | 
						|
 | 
						|
    if (logg5)
 | 
						|
        pdc_logg(p->pdc,
 | 
						|
                 "\t\tFitting input parameter:\n"
 | 
						|
                 "\t\t\tfitmethod = %s\n"
 | 
						|
                 "\t\t\tshrinklimit = %f\n"
 | 
						|
                 "\t\t\trefpoint = %f, %f\n"
 | 
						|
                 "\t\t\tboxsize = %f, %f\n"
 | 
						|
                 "\t\t\tfitrelpos = %f, %f\n"
 | 
						|
                 "\t\t\telemsize = %f, %f\n"
 | 
						|
                 "\t\t\ttextrelpos = %f, %f\n"
 | 
						|
                 "\t\tFitting output parameter:\n"
 | 
						|
                 "\t\t\telembox = %f, %f, %f, %f\n"
 | 
						|
                 "\t\t\telemscale = %f, %f\n",
 | 
						|
                 pdc_get_keyword(fit->fitmethod, pdf_fitmethod_keylist),
 | 
						|
                 fit->shrinklimit, fit->refpoint[0], fit->refpoint[1],
 | 
						|
                 fitbox.ur.x, fitbox.ur.y, fitrelpos.x, fitrelpos.y,
 | 
						|
                 elemsize.x, elemsize.y, textrelpos.x, textrelpos.y,
 | 
						|
                 elembox.ll.x, elembox.ll.y, elembox.ur.x, elembox.ur.y,
 | 
						|
                 elemscale.x, elemscale.y);
 | 
						|
 | 
						|
    /* reference point */
 | 
						|
    pdc_translation_matrix(fit->refpoint[0], fit->refpoint[1], &mm);
 | 
						|
    if (matrix == NULL)
 | 
						|
    {
 | 
						|
        if (blind)
 | 
						|
        {
 | 
						|
            m = ctm;
 | 
						|
            pdc_multiply_matrix(&mm, &m);
 | 
						|
        }
 | 
						|
        else
 | 
						|
            m = mm;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        m = *matrix;
 | 
						|
        pdc_multiply_matrix(&mm, &m);
 | 
						|
    }
 | 
						|
 | 
						|
    /* optional rotation */
 | 
						|
    if (fabs(fit->rotate) > PDC_FLOAT_PREC)
 | 
						|
    {
 | 
						|
        pdc_rotation_matrix(p->ydirection * fit->rotate, &mm);
 | 
						|
        pdc_multiply_matrix(&mm, &m);
 | 
						|
    }
 | 
						|
 | 
						|
    /* output after translation and rotation */
 | 
						|
    if (!blind)
 | 
						|
    {
 | 
						|
        /* new CTM */
 | 
						|
        if (fit->showborder ||
 | 
						|
            fit->fitmethod == pdc_clip || fit->fitmethod == pdc_slice)
 | 
						|
        {
 | 
						|
            pdf_concat_raw(p, &m);
 | 
						|
            pdc_identity_matrix(&m);
 | 
						|
        }
 | 
						|
 | 
						|
        /* show border */
 | 
						|
        if (fit->showborder)
 | 
						|
        {
 | 
						|
            pdf__rect(p, elemmargin.x, p->ydirection * elemmargin.y,
 | 
						|
                      boxwidth, boxheight);
 | 
						|
            pdf__rect(p, 0, 0, fit->boxsize[0], fit->boxsize[1]);
 | 
						|
            pdf__stroke(p);
 | 
						|
        }
 | 
						|
 | 
						|
        /* clipping */
 | 
						|
        if (
 | 
						|
            (fit->fitmethod == pdc_clip || fit->fitmethod == pdc_slice))
 | 
						|
        {
 | 
						|
            pdc_scalar cw = fit->boxsize[0];
 | 
						|
            pdc_scalar ch = fit->boxsize[1];
 | 
						|
 | 
						|
            if (cw < PDC_FLOAT_PREC)
 | 
						|
                cw = PDF_ACRO_MAXPAGE;
 | 
						|
            if (ch < PDC_FLOAT_PREC)
 | 
						|
                ch = PDF_ACRO_MAXPAGE;
 | 
						|
            pdf__rect(p, 0, 0, cw, ch);
 | 
						|
            pdf__clip(p);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* reference point for elembox */
 | 
						|
    if (elemmargin.x > PDC_FLOAT_PREC || elemmargin.y > PDC_FLOAT_PREC)
 | 
						|
    {
 | 
						|
        tx = elemmargin.x;
 | 
						|
        if (boxwidth < PDC_FLOAT_PREC)
 | 
						|
            tx *= 1.0 - 2 * fitrelpos.x;
 | 
						|
        ty = elemmargin.y;
 | 
						|
        if (boxheight < PDC_FLOAT_PREC)
 | 
						|
            ty *= 1.0 - 2 * fitrelpos.y;
 | 
						|
 | 
						|
        pdc_translation_matrix(tx, p->ydirection * ty, &mm);
 | 
						|
        pdc_multiply_matrix(&mm, &m);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    /* translation of element box */
 | 
						|
    elembox.ll.y *= p->ydirection;
 | 
						|
    elembox.ur.y *= p->ydirection;
 | 
						|
    pdc_box2polyline(NULL, &elembox, polyline);
 | 
						|
    tx = polyline[indangle].x;
 | 
						|
    ty = polyline[indangle].y;
 | 
						|
    pdc_translation_matrix(tx, ty, &mm);
 | 
						|
    pdc_multiply_matrix(&mm, &m);
 | 
						|
    boxwidth = elembox.ur.x - elembox.ll.x;
 | 
						|
    boxheight = elembox.ur.y - elembox.ll.y;
 | 
						|
 | 
						|
    /* 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;
 | 
						|
 | 
						|
            ss = boxwidth;
 | 
						|
            boxwidth = p->ydirection * boxheight;
 | 
						|
            boxheight = p->ydirection * ss;
 | 
						|
 | 
						|
            ss = elemmargin.x;
 | 
						|
            elemmargin.x = p->ydirection * elemmargin.y;
 | 
						|
            elemmargin.y = p->ydirection * ss;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* matchbox */
 | 
						|
    if (!blind && fit->matchbox)
 | 
						|
    {
 | 
						|
        pdc_rectangle matchrect;
 | 
						|
 | 
						|
        pdf_concat_raw(p, &m);
 | 
						|
        pdc_identity_matrix(&m);
 | 
						|
 | 
						|
        matchrect.llx = 0;
 | 
						|
        matchrect.lly = 0;
 | 
						|
        matchrect.urx = boxwidth;
 | 
						|
        matchrect.ury = boxheight;
 | 
						|
 | 
						|
        pdf_set_mbox_rectangle(p, fit->matchbox, &matchrect, 0);
 | 
						|
        pdf_draw_mbox_rectangle(p, fit->matchbox,
 | 
						|
                                mbox_saverestore | mbox_area | mbox_border);
 | 
						|
 | 
						|
        pdf_add_page_mbox(p, fit->matchbox);
 | 
						|
    }
 | 
						|
 | 
						|
    /* scaling */
 | 
						|
    if (elemscale.x != 1 || elemscale.y != 1)
 | 
						|
    {
 | 
						|
        pdc_scale_matrix(elemscale.x, elemscale.y, &mm);
 | 
						|
        pdc_multiply_matrix(&mm, &m);
 | 
						|
    }
 | 
						|
 | 
						|
    /* relative text position */
 | 
						|
    if (!vertical)
 | 
						|
    {
 | 
						|
        x = 0;
 | 
						|
        y = p->ydirection * basey;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        x = width / 2.0;
 | 
						|
        y = p->ydirection * height;
 | 
						|
    }
 | 
						|
 | 
						|
    if (logg5)
 | 
						|
        pdc_logg(p->pdc,
 | 
						|
               "\t\tReference point:\n"
 | 
						|
               "\t\t\tx = %f\n"
 | 
						|
               "\t\t\ty = %f\n"
 | 
						|
               "\t\tEmbedding matrix components of textline fitting:\n"
 | 
						|
               "\t\t\ta = %f\n"
 | 
						|
               "\t\t\tb = %f\n"
 | 
						|
               "\t\t\tc = %f\n"
 | 
						|
               "\t\t\td = %f\n"
 | 
						|
               "\t\t\te = %f\n"
 | 
						|
               "\t\t\tf = %f\n",
 | 
						|
               x, y, m.a, m.b, m.c, m.d, m.e, m.f);
 | 
						|
 | 
						|
    /*
 | 
						|
     * blind mode: pdf__info_textline
 | 
						|
     */
 | 
						|
    if (blind)
 | 
						|
    {
 | 
						|
        pdc_scalar mwidth = 2 * fabs(elemmargin.x);
 | 
						|
        pdc_scalar mheight = 2 * fabs(elemmargin.y);
 | 
						|
        pdc_scalar vlen;
 | 
						|
 | 
						|
        /* start position */
 | 
						|
        pdc_transform_point(&m, x, y, &tx, &ty);
 | 
						|
        fitres->start.x = tx;
 | 
						|
        fitres->start.y = ty;
 | 
						|
 | 
						|
        /* end position */
 | 
						|
        if (!vertical)
 | 
						|
        {
 | 
						|
            tx = x + width;
 | 
						|
            ty = y;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            tx = x;
 | 
						|
            ty = y - p->ydirection * height;
 | 
						|
        }
 | 
						|
        pdc_transform_point(&m, tx, ty, &tx, &ty);
 | 
						|
        fitres->end.x = tx;
 | 
						|
        fitres->end.y = ty;
 | 
						|
 | 
						|
        /* relative vector from start to end  */
 | 
						|
        tx = fitres->end.x - fitres->start.x;
 | 
						|
        ty = fitres->end.y - fitres->start.y;
 | 
						|
        vlen = sqrt(tx * tx + ty * ty);
 | 
						|
        if (!vertical)
 | 
						|
        {
 | 
						|
            /* width and x scaling */
 | 
						|
            fitres->width = vlen;
 | 
						|
            fitres->mwidth = vlen + mwidth;
 | 
						|
            fitres->scale.x = fitres->width / width;
 | 
						|
 | 
						|
            /* unit vector of base line */
 | 
						|
            fitres->writingdir.x = tx / vlen;
 | 
						|
            fitres->writingdir.y = ty / vlen;
 | 
						|
 | 
						|
            /* relative vector of fontsize */
 | 
						|
            tx = x;
 | 
						|
            ty = y + p->ydirection * height;
 | 
						|
            pdc_transform_point(&m, tx, ty, &tx, &ty);
 | 
						|
            tx -= fitres->start.x;
 | 
						|
            ty -= fitres->start.y;
 | 
						|
            vlen = sqrt(tx * tx + ty * ty);
 | 
						|
 | 
						|
            /* height and y scaling */
 | 
						|
            fitres->height = vlen;
 | 
						|
            fitres->mheight = vlen + mheight;
 | 
						|
            fitres->scale.y = fitres->height / height;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            /* height and y scaling */
 | 
						|
            fitres->height = vlen;
 | 
						|
            fitres->mheight = vlen + mheight;
 | 
						|
            fitres->scale.y = fitres->height / height;
 | 
						|
 | 
						|
            /* unit vector of perpendiculardir line */
 | 
						|
            fitres->writingdir.x = tx / vlen;
 | 
						|
            fitres->writingdir.y = ty / vlen;
 | 
						|
 | 
						|
            /* relative vector of width */
 | 
						|
            tx = x + width;
 | 
						|
            ty = y;
 | 
						|
            pdc_transform_point(&m, tx, ty, &tx, &ty);
 | 
						|
            tx -= fitres->start.x;
 | 
						|
            ty -= fitres->start.y;
 | 
						|
            vlen = sqrt(tx * tx + ty * ty);
 | 
						|
 | 
						|
            /* width ans x scaling */
 | 
						|
            fitres->width = vlen;
 | 
						|
            fitres->mwidth = vlen + mwidth;
 | 
						|
            fitres->scale.x = fitres->width / width;
 | 
						|
        }
 | 
						|
 | 
						|
        /* unit vector of perpendiculardir line */
 | 
						|
        fitres->perpendiculardir.x = tx / vlen;
 | 
						|
        fitres->perpendiculardir.y = ty / vlen;
 | 
						|
 | 
						|
        /* rotation angle of base line */
 | 
						|
        fitres->angle = atan2(fitres->writingdir.y, fitres->writingdir.x) /
 | 
						|
                        PDC_DEG2RAD;
 | 
						|
 | 
						|
        /* font specifics */
 | 
						|
        fitres->ascender = pdc_transform_scalar(&m, ascender);
 | 
						|
        fitres->capheight = pdc_transform_scalar(&m, capheight);
 | 
						|
        fitres->xheight = pdc_transform_scalar(&m, xheight);
 | 
						|
        fitres->descender = pdc_transform_scalar(&m, descender);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        /* CTM */
 | 
						|
        pdf_concat_raw(p, &m);
 | 
						|
 | 
						|
        /* set text position */
 | 
						|
        pdf__set_text_pos(p, x, y);
 | 
						|
 | 
						|
 | 
						|
        /* place text */
 | 
						|
        pdf_place_text(p, utext, len, charlen, to, width, height, pdc_false);
 | 
						|
 | 
						|
 | 
						|
        /* create a link - deprecated - */
 | 
						|
        if (to->link)
 | 
						|
        {
 | 
						|
            if (pdf_check_textstring(p, to->text, to->textlen,
 | 
						|
                                 PDF_USE_TMPALLOC | PDF_KEEP_UNICODE,
 | 
						|
                                 to, NULL, &utext, &len, &charlen, pdc_true))
 | 
						|
            {
 | 
						|
                pdf_create_link(p, to->linktype,
 | 
						|
                                x, y + p->ydirection * descender,
 | 
						|
                                x + width, y + p->ydirection * to->fontsize,
 | 
						|
                                to->link, (char *) utext, len);
 | 
						|
                pdc_free_tmp(p->pdc, utext);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return pdc_true;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdf_calculate_textline_size(PDF *p, pdf_text_options *to, pdf_fit_options *fit,
 | 
						|
                    pdc_scalar *width, pdc_scalar *height)
 | 
						|
{
 | 
						|
    pdf_ppt *ppt = p->curr_ppt;
 | 
						|
    pdf_fitres fitres;
 | 
						|
    pdc_matrix ctminv;
 | 
						|
 | 
						|
    /* calculate textline size for table cells */
 | 
						|
    fitres.verbose = pdc_true;
 | 
						|
    fitres.width = 0.0;
 | 
						|
    fitres.height = 0.0;
 | 
						|
    pdf_fit_textline_internal(p, &fitres, to, fit, NULL);
 | 
						|
 | 
						|
    pdc_invert_matrix(p->pdc, &ctminv, &ppt->gstate[ppt->sl].ctm);
 | 
						|
    if (width)
 | 
						|
        *width = pdc_transform_scalar(&ctminv, fitres.mwidth);
 | 
						|
    if (height)
 | 
						|
        *height = pdc_transform_scalar(&ctminv, fitres.mheight);
 | 
						|
}
 | 
						|
 | 
						|
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_tstate *ts;
 | 
						|
    pdf_text_options to;
 | 
						|
    pdf_fit_options fit;
 | 
						|
    pdc_matrix ctminv;
 | 
						|
    pdc_scalar currtx, currty;
 | 
						|
 | 
						|
    pdc_check_number(p->pdc, "x", x);
 | 
						|
    pdc_check_number(p->pdc, "y", y);
 | 
						|
 | 
						|
    /* parse options */
 | 
						|
    if (!pdf_parse_textline_options(p, text, len, &to, &fit, optlist))
 | 
						|
        return;
 | 
						|
 | 
						|
    fit.refpoint[0] = x;
 | 
						|
    fit.refpoint[1] = y;
 | 
						|
 | 
						|
    pdf__save(p);
 | 
						|
 | 
						|
    /* output text line */
 | 
						|
    pdf_fit_textline_internal(p, NULL, &to, &fit, NULL);
 | 
						|
    pdf_cleanup_fit_options(p, &fit);
 | 
						|
 | 
						|
    ts = &ppt->tstate[ppt->sl];
 | 
						|
    pdc_transform_point(&ppt->gstate[ppt->sl].ctm,
 | 
						|
                        ts->currtx, ts->currty, &currtx, &currty);
 | 
						|
 | 
						|
    pdf__restore(p);
 | 
						|
 | 
						|
    /* calculate current text position*/
 | 
						|
    pdc_invert_matrix(p->pdc, &ctminv, &ppt->gstate[ppt->sl].ctm);
 | 
						|
    pdc_transform_point(&ctminv, currtx, currty, &currtx, &currty);
 | 
						|
    pdf__set_text_pos(p, currtx, currty);
 | 
						|
}
 | 
						|
 | 
						|
static const pdc_keyconn pdf_info_keylist[] =
 | 
						|
{
 | 
						|
    {"startx",            1},
 | 
						|
    {"starty",            2},
 | 
						|
    {"endx",              3},
 | 
						|
    {"endy",              4},
 | 
						|
    {"writingdirx",       5},
 | 
						|
    {"writingdiry",       6},
 | 
						|
    {"perpendiculardirx", 7},
 | 
						|
    {"perpendiculardiry", 8},
 | 
						|
    {"scalex",            9},
 | 
						|
    {"scaley",           10},
 | 
						|
    {"width",            11},
 | 
						|
    {"height",           12},
 | 
						|
    {"ascender",         13},
 | 
						|
    {"capheight",        14},
 | 
						|
    {"xheight",          15},
 | 
						|
    {"descender",        16},
 | 
						|
    {"angle",            17},
 | 
						|
 | 
						|
    {"unmappedglyphs",   20}, /* deprecated */
 | 
						|
    {"unmappedchars",    20},
 | 
						|
    {"replacedchars",    21},
 | 
						|
    {"unknownchars",     22},
 | 
						|
    {"wellformed",       23},
 | 
						|
    {NULL, 0}
 | 
						|
};
 | 
						|
 | 
						|
double
 | 
						|
pdf__info_textline(PDF *p, const char *text, int len, const char *keyword,
 | 
						|
                   const char *optlist)
 | 
						|
{
 | 
						|
    pdf_ppt *ppt = p->curr_ppt;
 | 
						|
    pdf_text_options to;
 | 
						|
    pdf_fit_options fit;
 | 
						|
    pdf_fitres fitres;
 | 
						|
    double tinfo = 0.0;
 | 
						|
    int retval, infokey;
 | 
						|
 | 
						|
    if (!keyword || !*keyword)
 | 
						|
        pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "keyword", 0, 0, 0);
 | 
						|
 | 
						|
    infokey = pdc_get_keycode_ci(keyword, pdf_info_keylist);
 | 
						|
    if (infokey == PDC_KEY_NOTFOUND)
 | 
						|
        pdc_error(p->pdc, PDC_E_ILLARG_STRING, "keyword", keyword, 0, 0);
 | 
						|
 | 
						|
    /* parse options */
 | 
						|
    retval = pdf_parse_textline_options(p, text, len, &to, &fit, optlist);
 | 
						|
 | 
						|
    if (retval)
 | 
						|
    {
 | 
						|
        /* calculate textline */
 | 
						|
        fitres.verbose = to.glyphwarning;
 | 
						|
        fitres.unmappedchars = 0;
 | 
						|
        fitres.replacedchars = 0;
 | 
						|
        fitres.unknownchars = 0;
 | 
						|
        retval = pdf_fit_textline_internal(p, &fitres, &to, &fit, NULL);
 | 
						|
        pdf_cleanup_fit_options(p, &fit);
 | 
						|
 | 
						|
        if (retval)
 | 
						|
        {
 | 
						|
            pdf_font *currfont = &p->fonts[to.font];
 | 
						|
            pdc_matrix ctminv;
 | 
						|
 | 
						|
            pdc_invert_matrix(p->pdc, &ctminv, &ppt->gstate[ppt->sl].ctm);
 | 
						|
 | 
						|
            switch(infokey)
 | 
						|
            {
 | 
						|
                case 1:
 | 
						|
                case 2:
 | 
						|
                pdc_transform_vector(&ctminv, &fitres.start, NULL);
 | 
						|
                break;
 | 
						|
 | 
						|
                case 3:
 | 
						|
                case 4:
 | 
						|
                pdc_transform_vector(&ctminv, &fitres.end, NULL);
 | 
						|
                break;
 | 
						|
 | 
						|
                case 5:
 | 
						|
                case 6:
 | 
						|
                pdc_transform_rvector(&ctminv, &fitres.writingdir, NULL);
 | 
						|
                break;
 | 
						|
 | 
						|
                case 7:
 | 
						|
                case 8:
 | 
						|
                pdc_transform_rvector(&ctminv, &fitres.perpendiculardir, NULL);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            pdc_logg_cond(p->pdc, 1, trc_text,
 | 
						|
                "\tInfo textline%s:\n"
 | 
						|
                "\tstartx = %f\n"
 | 
						|
                "\tstarty = %f\n"
 | 
						|
                "\tendx = %f\n"
 | 
						|
                "\tendy = %f\n"
 | 
						|
                "\twritingdirx = %f\n"
 | 
						|
                "\twritingdiry = %f\n"
 | 
						|
                "\tperpendiculardirx = %f\n"
 | 
						|
                "\tperpendiculardiry = %f\n"
 | 
						|
                "\tscalex = %f\n"
 | 
						|
                "\tscaley = %f\n"
 | 
						|
                "\twidth = %f\n"
 | 
						|
                "\theight = %f\n"
 | 
						|
                "\tascender = %f\n"
 | 
						|
                "\tcapheight = %f\n"
 | 
						|
                "\txheight = %f\n"
 | 
						|
                "\tdescender = %f\n",
 | 
						|
                currfont->ft.vertical ? " (vertical writing mode)" : "",
 | 
						|
                fitres.start.x, fitres.start.y,
 | 
						|
                fitres.end.x, fitres.end.y,
 | 
						|
                fitres.writingdir.x, fitres.writingdir.y,
 | 
						|
                fitres.perpendiculardir.x, fitres.perpendiculardir.y,
 | 
						|
                fitres.scale.x, fitres.scale.y,
 | 
						|
                fitres.width, fitres.height,
 | 
						|
                fitres.ascender, fitres.capheight,
 | 
						|
                fitres.xheight,fitres.descender);
 | 
						|
 | 
						|
            switch(infokey)
 | 
						|
            {
 | 
						|
                case 1:
 | 
						|
                tinfo = (double) fitres.start.x;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 2:
 | 
						|
                tinfo = (double) fitres.start.y;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 3:
 | 
						|
                tinfo = (double) fitres.end.x;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 4:
 | 
						|
                tinfo = (double) fitres.end.y;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 5:
 | 
						|
                tinfo = (double) fitres.writingdir.x;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 6:
 | 
						|
                tinfo = (double) fitres.writingdir.y;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 7:
 | 
						|
                tinfo = (double) fitres.perpendiculardir.x;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 8:
 | 
						|
                tinfo = (double) fitres.perpendiculardir.y;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 9:
 | 
						|
                tinfo = (double) fitres.scale.x;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 10:
 | 
						|
                tinfo = (double) fitres.scale.y;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 11:
 | 
						|
                tinfo = (double) fitres.width;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 12:
 | 
						|
                tinfo = (double) fitres.height;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 13:
 | 
						|
                tinfo = (double) fitres.ascender;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 14:
 | 
						|
                tinfo = (double) fitres.capheight;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 15:
 | 
						|
                tinfo = (double) fitres.xheight;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 16:
 | 
						|
                tinfo = (double) fitres.descender;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 17:
 | 
						|
                tinfo = (double) fitres.angle;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 20:
 | 
						|
                tinfo = (double) fitres.unmappedchars;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 21:
 | 
						|
                tinfo = (double) fitres.replacedchars;
 | 
						|
                break;
 | 
						|
 | 
						|
                case 22:
 | 
						|
                tinfo = (double) fitres.unknownchars;
 | 
						|
                break;
 | 
						|
 | 
						|
                /* wellformed */
 | 
						|
                case 23:
 | 
						|
                tinfo = (double) 1;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return tinfo;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
/**         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_textsize(p,
 | 
						|
                        (pdc_byte *) text, (int)strlen(text), 1,
 | 
						|
                        currto, -1, NULL, pdc_true);
 | 
						|
    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;
 | 
						|
    pdf_font *currfont;
 | 
						|
    pdc_byte *utext = NULL;
 | 
						|
    pdc_text_format old_textformat;
 | 
						|
    pdf_alignment mode = text_left;
 | 
						|
    pdc_bool blind = pdc_false;
 | 
						|
 | 
						|
    len = pdc_check_text_length(p->pdc, &text, len, PDF_MAXTEXTSIZE);
 | 
						|
    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);
 | 
						|
 | 
						|
    if (currfont->ft.vertical)
 | 
						|
    {
 | 
						|
        pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "vertical writing mode",
 | 
						|
                  0, 0, 0);
 | 
						|
    }
 | 
						|
 | 
						|
    /* we cannot handle several encodings */
 | 
						|
    if (currfont->ft.enc == pdc_unicode)
 | 
						|
    {
 | 
						|
        pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "Unicode", 0, 0, 0);
 | 
						|
    }
 | 
						|
 | 
						|
    if (currfont->ft.enc == pdc_glyphid)
 | 
						|
    {
 | 
						|
        pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "glyphid", 0, 0, 0);
 | 
						|
    }
 | 
						|
 | 
						|
    if (currfont->ft.enc == pdc_cid)
 | 
						|
    {
 | 
						|
	pdc_error(p->pdc, PDF_E_DOC_FUNCUNSUPP, "CID", 0, 0, 0);
 | 
						|
    }
 | 
						|
 | 
						|
    if (currfont->ft.enc == pdc_ebcdic ||
 | 
						|
        currfont->ft.enc == pdc_ebcdic_37 ||
 | 
						|
        currfont->ft.enc == pdc_ebcdic_winansi)
 | 
						|
    {
 | 
						|
	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 */
 | 
						|
        if (!pdf_check_textstring(p, text, len,
 | 
						|
                    PDF_KEEP_CONTROL | PDF_KEEP_TEXTLEN | PDF_USE_TMPALLOC,
 | 
						|
                    currto, NULL, &utext, &len, &charlen, pdc_true))
 | 
						|
            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);
 | 
						|
}
 |