1
/* $Id: psttf.cc,v 1.8 2006/05/18 11:56:39 rlaboiss Exp $
3
PLplot PostScript device driver using LASi to provide fonts
4
based on original ps.c PostScript driver
6
Copyright (C) 1992, 2001 Geoffrey Furnish
7
Copyright (C) 1992, 1993, 1994, 1995, 2001 Maurice LeBrun
8
Copyright (C) 2000, 2001, 2002, 2004, 2005 Alan W. Irwin
9
Copyright (C) 2001, 2002 Joao Cardoso
10
Copyright (C) 2001, 2003, 2004 Rafael Laboissiere
11
Copyright (C) 2004, 2005 Thomas J. Duck
12
Copyright (C) 2005, 2006 Andrew Ross
14
This file is part of PLplot.
16
PLplot is free software; you can redistribute it and/or modify
17
it under the terms of the GNU General Library Public License as published
18
by the Free Software Foundation; either version 2 of the License, or
19
(at your option) any later version.
21
PLplot is distributed in the hope that it will be useful,
22
but WITHOUT ANY WARRANTY; without even the implied warranty of
23
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
GNU Library General Public License for more details.
26
You should have received a copy of the GNU Library General Public License
27
along with PLplot; if not, write to the Free Software
28
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
36
#if defined(PLD_psttf)
45
#include "plfreetype.h"
55
char* plD_DEVICE_INFO_psttf =
56
"psttf:PostScript File (monochrome):0:psttf:55:psttfm\n"
57
"psttfc:PostScript File (color):0:psttf:56:psttfc";
60
/* Prototypes for functions in this file. */
62
void plD_dispatch_init_psttfm ( PLDispatchTable *pdt );
63
void plD_dispatch_init_psttfc ( PLDispatchTable *pdt );
65
static char *ps_getdate (void);
66
static void ps_init (PLStream *);
67
static void fill_polygon (PLStream *pls);
68
static void proc_str (PLStream *, EscText *);
69
static void esc_purge (char *, char *);
71
static char outbuf[128];
74
static int hrshsym = 0;
76
/* Font style and weight lookup tables */
78
#define N_Pango_Lookup 5
80
const char * DefaultFamilyLookup[N_Pango_Lookup] = {
88
const char * EnvFamilyLookup[N_Pango_Lookup] = {
89
"PLPLOT_FREETYPE_SANS_FAMILY",
90
"PLPLOT_FREETYPE_SERIF_FAMILY",
91
"PLPLOT_FREETYPE_MONO_FAMILY",
92
"PLPLOT_FREETYPE_SCRIPT_FAMILY",
93
"PLPLOT_FREETYPE_SYMBOL_FAMILY"
96
char FamilyLookup[N_Pango_Lookup][1024];
98
const FontWeight WeightLookup[2] = {
103
const FontStyle StyleLookup[3] = {
109
static DrvOpt ps_options[] = {{"text", DRV_INT, &text, "Use Postscript text (text=0|1)"},
110
{"color", DRV_INT, &color, "Use color (color=0|1)"},
111
{"hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)"},
112
{NULL, DRV_INT, NULL, NULL}};
114
/* text > 0 uses some postscript tricks, namely a transformation matrix
115
that scales, rotates (with slanting) and offsets text strings.
116
It has yet some bugs for 3d plots. */
119
static void psttf_dispatch_init_helper( PLDispatchTable *pdt,
120
char *menustr, char *devnam,
121
int type, int seq, plD_init_fp init )
123
#ifndef ENABLE_DYNDRIVERS
124
pdt->pl_MenuStr = menustr;
125
pdt->pl_DevName = devnam;
130
pdt->pl_line = (plD_line_fp) plD_line_psttf;
131
pdt->pl_polyline = (plD_polyline_fp) plD_polyline_psttf;
132
pdt->pl_eop = (plD_eop_fp) plD_eop_psttf;
133
pdt->pl_bop = (plD_bop_fp) plD_bop_psttf;
134
pdt->pl_tidy = (plD_tidy_fp) plD_tidy_psttf;
135
pdt->pl_state = (plD_state_fp) plD_state_psttf;
136
pdt->pl_esc = (plD_esc_fp) plD_esc_psttf;
139
void plD_dispatch_init_psttfm ( PLDispatchTable *pdt )
141
psttf_dispatch_init_helper( pdt,
142
"PostScript File (monochrome)", "psttf",
143
plDevType_FileOriented, 55,
144
(plD_init_fp) plD_init_psttfm );
147
void plD_dispatch_init_psttfc ( PLDispatchTable *pdt )
149
psttf_dispatch_init_helper( pdt,
150
"PostScript File (color)", "psttfc",
151
plDevType_FileOriented, 56,
152
(plD_init_fp) plD_init_psttfc );
155
/*--------------------------------------------------------------------------*\
159
\*--------------------------------------------------------------------------*/
162
plD_init_psttfm(PLStream *pls)
165
pls->color = 0; /* Not a color device */
167
plParseDrvOpts(ps_options);
169
pls->color = 1; /* But user wants color */
174
plD_init_psttfc(PLStream *pls)
177
pls->color = 1; /* Is a color device */
178
plParseDrvOpts(ps_options);
181
pls->color = 0; /* But user does not want color */
185
#define MAX_NUM_TRIES 10
187
ps_init(PLStream *pls)
193
PLFLT pxlx = YPSSIZE/LPAGE_X;
194
PLFLT pxly = XPSSIZE/LPAGE_Y;
198
pls->dev_text = 1; /* want to draw text */
199
pls->dev_unicode = 1; /* want unicode */
200
if(hrshsym) pls->dev_hrshsym = 1; /* want Hershey symbols */
203
pls->dev_fill0 = 1; /* Can do solid fills */
205
/* Initialize family file info */
209
/* Prompt for a file name if not already set */
213
/* Create postscript document object */
214
if (pls->psdoc != NULL)
215
delete (PostscriptDocument *) pls->psdoc;
217
pls->psdoc = new PostscriptDocument();
219
/* Allocate and initialize device-specific data */
221
if (pls->dev != NULL)
222
free((void *) pls->dev);
224
pls->dev = calloc(1, (size_t) sizeof(PSDev));
225
if (pls->dev == NULL)
226
plexit("ps_init: Out of memory.");
228
dev = (PSDev *) pls->dev;
230
dev->xold = PL_UNDEFINED;
231
dev->yold = PL_UNDEFINED;
233
plP_setpxl(pxlx, pxly);
241
/* Rotate by 90 degrees since portrait mode addressing is used */
247
dev->xlen = dev->xmax - dev->xmin;
248
dev->ylen = dev->ymax - dev->ymin;
250
plP_setphy(dev->xmin, dev->xmax, dev->ymin, dev->ymax);
252
/* If portrait mode is specified, then set up an additional rotation
253
* transformation with aspect ratio allowed to adjust via freeaspect.
254
* Default orientation is landscape (ORIENTATION == 3 or 90 deg rotation
255
* counter-clockwise from portrait). (Legacy PLplot used seascape
256
* which was equivalent to ORIENTATION == 1 or 90 deg clockwise rotation
260
plsdiori((PLFLT)(4 - ORIENTATION));
264
// File table for font families using either environment variables
266
for (i=0;i<N_Pango_Lookup;i++) {
267
if ( (a = getenv(EnvFamilyLookup[i])) != NULL ) {
268
strcpy(FamilyLookup[i],a);
271
strcpy(FamilyLookup[i],DefaultFamilyLookup[i]);
278
/*--------------------------------------------------------------------------*\
281
* Write plplot postscript commands into the header
282
\*--------------------------------------------------------------------------*/
285
writeHeader(PLStream *pls) {
286
PostscriptDocument *doc = (PostscriptDocument *) (pls->psdoc);
288
doc->osHeader() << "%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
290
doc->osHeader() << "%%Title: PLplot Graph\n";
291
doc->osHeader() << "%%Creator: PLplot Version " << VERSION << "\n";
292
doc->osHeader() << "%%CreationDate: " << ps_getdate() << "\n";
293
doc->osHeader() << "%%Pages: (atend)\n";
294
doc->osHeader() << "%%EndComments\n\n";
299
doc->osHeader() << "/PSSave save def\n";
301
/* Define a dictionary and start using it */
303
doc->osHeader() << "/PSDict 200 dict def\n";
304
doc->osHeader() << "PSDict begin\n";
306
doc->osHeader() << "/@restore /restore load def\n";
307
doc->osHeader() << "/restore\n";
308
doc->osHeader() << " {vmstatus pop\n";
309
doc->osHeader() << " dup @VMused lt {pop @VMused} if\n";
310
doc->osHeader() << " exch pop exch @restore /@VMused exch def\n";
311
doc->osHeader() << " } def\n";
312
doc->osHeader() << "/@pri\n";
313
doc->osHeader() << " {\n";
314
doc->osHeader() << " ( ) print\n";
315
doc->osHeader() << " ( ) cvs print\n";
316
doc->osHeader() << " } def\n";
320
doc->osHeader() << "/@copies\n";
321
doc->osHeader() << " {\n";
322
doc->osHeader() << " /#copies exch def\n";
323
doc->osHeader() << " } def\n";
325
/* - @start - -- start everything */
327
doc->osHeader() << "/@start\n";
328
doc->osHeader() << " {\n";
329
doc->osHeader() << " vmstatus pop /@VMused exch def pop\n";
330
doc->osHeader() << " } def\n";
332
/* - @end - -- finished */
334
doc->osHeader() << "/@end\n";
335
doc->osHeader() << " {flush\n";
336
doc->osHeader() << " end\n";
337
doc->osHeader() << " PSSave restore\n";
338
doc->osHeader() << " } def\n";
340
/* bop - -- begin a new page */
341
/* Only fill background if we are using color and if the bg isn't white */
343
doc->osHeader() << "/bop\n";
344
doc->osHeader() << " {\n";
345
doc->osHeader() << " /SaveImage save def\n";
346
doc->osHeader() << " } def\n";
348
/* - eop - -- end a page */
350
doc->osHeader() << "/eop\n";
351
doc->osHeader() << " {\n";
352
doc->osHeader() << " showpage\n";
353
doc->osHeader() << " SaveImage restore\n";
354
doc->osHeader() << " } def\n";
356
/* Set line parameters */
358
doc->osHeader() << "/@line\n";
359
doc->osHeader() << " {0 setlinecap\n";
360
doc->osHeader() << " 0 setlinejoin\n";
361
doc->osHeader() << " 1 setmiterlimit\n";
362
doc->osHeader() << " } def\n";
364
/* d @hsize - horizontal clipping dimension */
366
doc->osHeader() << "/@hsize {/hs exch def} def\n";
367
doc->osHeader() << "/@vsize {/vs exch def} def\n";
369
/* d @hoffset - shift for the plots */
371
doc->osHeader() << "/@hoffset {/ho exch def} def\n";
372
doc->osHeader() << "/@voffset {/vo exch def} def\n";
376
doc->osHeader() << "/lw " << (int) (
377
(pls->width < MIN_WIDTH) ? DEF_WIDTH :
378
(pls->width > MAX_WIDTH) ? MAX_WIDTH : pls->width) << " def\n";
380
/* Setup user specified offsets, scales, sizes for clipping */
382
doc->osHeader() << "/@SetPlot\n";
383
doc->osHeader() << " {\n";
384
doc->osHeader() << " ho vo translate\n";
385
doc->osHeader() << " XScale YScale scale\n";
386
doc->osHeader() << " lw setlinewidth\n";
387
doc->osHeader() << " } def\n";
389
/* Setup x & y scales */
391
doc->osHeader() << "/XScale\n";
392
doc->osHeader() << " {hs " << YPSSIZE << " div} def\n";
393
doc->osHeader() << "/YScale\n";
394
doc->osHeader() << " {vs " << XPSSIZE << " div} def\n";
396
/* Macro definitions of common instructions, to keep output small */
398
doc->osHeader() << "/M {moveto} def\n";
399
doc->osHeader() << "/D {lineto} def\n";
400
doc->osHeader() << "/A {0.5 0 360 arc} def\n";
401
doc->osHeader() << "/S {stroke} def\n";
402
doc->osHeader() << "/Z {stroke newpath} def\n";
403
doc->osHeader() << "/F {fill} def\n";
404
doc->osHeader() << "/C {setrgbcolor} def\n";
405
doc->osHeader() << "/G {setgray} def\n";
406
doc->osHeader() << "/W {setlinewidth} def\n";
407
doc->osHeader() << "/R {rotate} def\n";
408
doc->osHeader() << "/B {Z " << XMIN << " " << YMIN << " M " << XMIN << " " << YMAX << " D " << XMAX << " " << YMAX << " D " << XMAX << " " << YMIN << " D " << XMIN << " " << YMIN << " closepath} def\n";
409
doc->osHeader() << "/CL {newpath M D D D closepath clip} def\n";
411
/* End of dictionary definition */
413
doc->osHeader() << "end\n\n";
415
/* Set up the plots */
417
doc->osHeader() << "PSDict begin\n";
418
doc->osHeader() << "@start\n";
419
doc->osHeader() << "%d @copies\n", COPIES;
420
doc->osHeader() << "@line\n";
421
doc->osHeader() << YSIZE << " @hsize\n";
422
doc->osHeader() << XSIZE << " @vsize\n";
423
doc->osHeader() << YOFFSET << " @hoffset\n";
424
doc->osHeader() << XOFFSET << " @voffset\n";
426
doc->osHeader() << "@SetPlot\n" << endl;
429
/*--------------------------------------------------------------------------*\
432
* Draw a line in the current color from (x1,y1) to (x2,y2).
433
\*--------------------------------------------------------------------------*/
436
plD_line_psttf(PLStream *pls, short x1a, short y1a, short x2a, short y2a)
438
PSDev *dev = (PSDev *) pls->dev;
439
PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
440
PLINT x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a;
442
/* Rotate by 90 degrees */
444
plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x1, &y1);
445
plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x2, &y2);
447
if (x1 == dev->xold && y1 == dev->yold && dev->ptcnt < 40) {
448
if (pls->linepos + 12 > LINELENGTH) {
449
doc->osBody() << '\n';
453
doc->osBody() << ' ';
455
sprintf(outbuf, "%d %d D", x2, y2);
460
doc->osBody() << " Z\n";
463
if (x1 == x2 && y1 == y2) /* must be a single dot, draw a circle */
464
sprintf(outbuf, "%d %d A", x1, y1);
466
sprintf(outbuf, "%d %d M %d %d D", x1, y1, x2, y2);
467
dev->llx = MIN(dev->llx, x1);
468
dev->lly = MIN(dev->lly, y1);
469
dev->urx = MAX(dev->urx, x1);
470
dev->ury = MAX(dev->ury, y1);
474
dev->llx = MIN(dev->llx, x2);
475
dev->lly = MIN(dev->lly, y2);
476
dev->urx = MAX(dev->urx, x2);
477
dev->ury = MAX(dev->ury, y2);
479
doc->osBody() << outbuf;
480
pls->bytecnt += 1 + strlen(outbuf);
485
/*--------------------------------------------------------------------------*\
486
* plD_polyline_psttf()
488
* Draw a polyline in the current color.
489
\*--------------------------------------------------------------------------*/
492
plD_polyline_psttf(PLStream *pls, short *xa, short *ya, PLINT npts)
496
for (i = 0; i < npts - 1; i++)
497
plD_line_psttf(pls, xa[i], ya[i], xa[i + 1], ya[i + 1]);
500
/*--------------------------------------------------------------------------*\
504
\*--------------------------------------------------------------------------*/
507
plD_eop_psttf(PLStream *pls)
509
PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
510
doc->osBody() << " S\neop\n";
513
/*--------------------------------------------------------------------------*\
516
* Set up for the next page.
517
* Advance to next family file if necessary (file output).
518
\*--------------------------------------------------------------------------*/
521
plD_bop_psttf(PLStream *pls)
523
PSDev *dev = (PSDev *) pls->dev;
524
PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
526
dev->xold = PL_UNDEFINED;
527
dev->yold = PL_UNDEFINED;
535
doc->osBody() << "%%Page: " << (int) pls->page << " 1\n";
537
doc->osBody() << "%%Page: " << (int) pls->page << " " << (int) pls->page << "\n";
539
doc->osBody() << "bop\n";
542
if (pls->cmap0[0].r != 0xFF ||
543
pls->cmap0[0].g != 0xFF ||
544
pls->cmap0[0].b != 0xFF ) {
546
r = ((PLFLT) pls->cmap0[0].r) / 255.;
547
g = ((PLFLT) pls->cmap0[0].g) / 255.;
548
b = ((PLFLT) pls->cmap0[0].b) / 255.;
550
doc->osBody() << "B " << r << " " << g << " " << b << " C F\n";
555
/* This ensures the color and line width are set correctly at the beginning of
558
plD_state_psttf(pls, PLSTATE_COLOR0);
559
plD_state_psttf(pls, PLSTATE_WIDTH);
562
/*--------------------------------------------------------------------------*\
565
* Close graphics file or otherwise clean up.
566
\*--------------------------------------------------------------------------*/
569
plD_tidy_psttf(PLStream *pls)
571
PSDev *dev = (PSDev *) pls->dev;
572
PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
583
/* changed for correct Bounding boundaries Jan Thorbecke okt 1993*/
584
/* occurs from the integer truncation -- postscript uses fp arithmetic */
590
doc->osFooter() << "%%Pages: 1\n";
592
doc->osFooter() << "%%Pages: " << (int) pls->page << "\n";
594
doc->osFooter() << "@end" << endl;
596
/* Now write the rest of the header */
599
/* Write out postscript document to file and close*/
600
/* For C++ stream we first need to close the file using
601
the C FILE * handle, then reopen as a ofstream. Yuck! */
602
fclose(pls->OutFile);
603
if (! strcmp(pls->FileName,"-")) {
604
doc->write(cout,dev->llx,dev->lly,dev->urx,dev->ury);
608
out.open(pls->FileName);
609
doc->write(out,dev->llx,dev->lly,dev->urx,dev->ury);
618
/*--------------------------------------------------------------------------*\
621
* Handle change in PLStream state (color, pen width, fill attribute, etc).
622
\*--------------------------------------------------------------------------*/
625
plD_state_psttf(PLStream *pls, PLINT op)
627
PSDev *dev = (PSDev *) pls->dev;
628
PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
634
(pls->width < MIN_WIDTH) ? DEF_WIDTH :
635
(pls->width > MAX_WIDTH) ? MAX_WIDTH : pls->width;
637
doc->osBody() << " S\n" << width << " W";
639
dev->xold = PL_UNDEFINED;
640
dev->yold = PL_UNDEFINED;
645
doc->osBody() << " S\n" << (pls->icol0 ? 0.0 : 1.0) << " G";
648
/* else fallthrough */
651
PLFLT r = ((PLFLT) pls->curcolor.r) / 255.0;
652
PLFLT g = ((PLFLT) pls->curcolor.g) / 255.0;
653
PLFLT b = ((PLFLT) pls->curcolor.b) / 255.0;
655
doc->osBody() << " S\n" << r << " " << g << " " << b << " C";
658
PLFLT r = ((PLFLT) pls->curcolor.r) / 255.0;
659
doc->osBody() << " S\n" << 1.0 - r << " G";
664
/* Reinitialize current point location. */
666
if (dev->xold != PL_UNDEFINED && dev->yold != PL_UNDEFINED) {
667
doc->osBody() << " " << (int)dev->xold << " " << (int)dev->yold << " M \n";
671
/*--------------------------------------------------------------------------*\
675
\*--------------------------------------------------------------------------*/
678
plD_esc_psttf(PLStream *pls, PLINT op, void *ptr)
685
proc_str(pls, (EscText *)ptr);
690
/*--------------------------------------------------------------------------*\
693
* Fill polygon described in points pls->dev_x[] and pls->dev_y[].
694
* Only solid color fill supported.
695
\*--------------------------------------------------------------------------*/
698
fill_polygon(PLStream *pls)
700
PSDev *dev = (PSDev *) pls->dev;
701
PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
702
PLINT n, ix = 0, iy = 0;
705
doc->osBody() << " Z\n";
707
for (n = 0; n < pls->dev_npts; n++) {
708
x = pls->dev_x[ix++];
709
y = pls->dev_y[iy++];
711
/* Rotate by 90 degrees */
713
plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x, &y);
715
/* First time through start with a x y moveto */
718
sprintf(outbuf, "%d %d M", x, y);
719
dev->llx = MIN(dev->llx, x);
720
dev->lly = MIN(dev->lly, y);
721
dev->urx = MAX(dev->urx, x);
722
dev->ury = MAX(dev->ury, y);
723
doc->osBody() << outbuf;
724
pls->bytecnt += strlen(outbuf);
728
if (pls->linepos + 21 > LINELENGTH) {
729
doc->osBody() << '\n';
733
doc->osBody() << ' ';
737
sprintf(outbuf, "%d %d D", x, y);
738
dev->llx = MIN(dev->llx, x);
739
dev->lly = MIN(dev->lly, y);
740
dev->urx = MAX(dev->urx, x);
741
dev->ury = MAX(dev->ury, y);
743
doc->osBody() << outbuf;
744
pls->bytecnt += strlen(outbuf);
747
dev->xold = PL_UNDEFINED;
748
dev->yold = PL_UNDEFINED;
749
doc->osBody() << " F ";
752
/*--------------------------------------------------------------------------*\
755
* Get the date and time
756
\*--------------------------------------------------------------------------*/
765
t = time((time_t *) 0);
768
*(p + len - 1) = '\0'; /* zap the newline character */
773
/*--------------------------------------------------------------------------*\
776
* Prints postscript strings.
777
* N.B. Now unicode only, no string access!
779
\*--------------------------------------------------------------------------*/
782
proc_str (PLStream *pls, EscText *args)
784
PLFLT *t = args->xform, tt[4]; /* Transform matrices */
785
PLFLT theta; /* Rotation angle and shear from the matrix */
786
PLFLT ft_ht, offset; /* Font height and offset */
788
PSDev *dev = (PSDev *) pls->dev;
789
PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
793
/* Be generous. Used to store lots of font changes which take
794
* 3 characters per change.*/
795
#define PROC_STR_STRING_LENGTH 1000
796
char *strp, str[PROC_STR_STRING_LENGTH], *cur_strp,
797
cur_str[PROC_STR_STRING_LENGTH];
798
float font_factor = 1.4;
799
PLINT clxmin, clxmax, clymin, clymax; /* Clip limits */
800
PLINT clipx[4],clipy[4]; /* Current clip limits */
802
PLFLT scale = 1., up = 0.; /* Font scaling and shifting parameters */
804
double lineSpacing, xAdvance, xwid, ymintmp, ymaxtmp, ymin, ymax, xmin, xmax;
807
int i=0; /* String index */
814
/* unicode only! so test for it. */
815
if (args->unicode_array_len>0)
818
FT = (FT_Data *) pls->FT;
820
char *fonts[PROC_STR_STRING_LENGTH];
821
FontStyle styles[PROC_STR_STRING_LENGTH];
822
FontWeight weights[PROC_STR_STRING_LENGTH];
823
const PLUNICODE *cur_text;
824
const PLUNICODE *cur_text_limit;
826
unsigned char fontfamily, fontstyle, fontweight;
827
/* translate from unicode into type 1 font index. */
829
* Choose the font family, style, variant, and weight using
830
* the FCI (font characterization integer).
835
plP_fci2hex(fci,&fontfamily,PL_FCI_FAMILY);
836
plP_fci2hex(fci,&fontstyle,PL_FCI_STYLE);
837
plP_fci2hex(fci,&fontweight,PL_FCI_WEIGHT);
838
font = (char *) FamilyLookup[fontfamily];
839
weight = WeightLookup[fontweight];
840
style = StyleLookup[fontstyle];
841
/* Need to add some error checking here */
843
fprintf(stderr, "fci = 0x%x, font name pointer = NULL \n", fci);
844
plabort("proc_str: FCI inconsistent with TrueTypeLookup; "
845
"internal PLplot error");
848
/*pldebug("proc_str", "fci = 0x%x, font name = %s\n", fci, font);*/
849
cur_text = args->unicode_array;
850
for (f=s=j=0; j < args->unicode_array_len; j++) {
851
if (cur_text[j] & PL_FCI_MARK) {
852
/* process an FCI by saving it and escaping cur_str
853
* with an escff to make it a 2-character escape
854
* that is not used in legacy Hershey code
856
if ((f < PROC_STR_STRING_LENGTH) && (s+3 < PROC_STR_STRING_LENGTH)) {
857
plP_fci2hex(cur_text[j],&fontfamily,PL_FCI_FAMILY);
858
plP_fci2hex(cur_text[j],&fontstyle,PL_FCI_STYLE);
859
plP_fci2hex(cur_text[j],&fontweight,PL_FCI_WEIGHT);
860
fonts[f] = (char *) FamilyLookup[fontfamily];
861
weights[f] = WeightLookup[fontweight];
862
styles[f] = StyleLookup[fontstyle];
863
if (fonts[f] == NULL) {
864
fprintf(stderr, "string-supplied FCI = 0x%x, font name pointer = NULL \n", cur_text[j]);
865
plabort("proc_str: string-supplied FCI inconsistent with font lookup;");
868
/*pldebug("proc_str", "string-supplied FCI = 0x%x, font name = %s\n", cur_text[j], fonts[f]);*/
875
else if (s+1 < PROC_STR_STRING_LENGTH) {
876
s += ucs4_to_utf8(cur_text[j],&cur_str[s]);
877
/*pldebug("proc_str", "unicode = 0x%x, type 1 code = %d\n",
878
cur_text[j], cur_str[j]);*/
883
/* finish previous polyline */
885
dev->xold = PL_UNDEFINED;
886
dev->yold = PL_UNDEFINED;
888
/* Determine the font height */
889
ft_ht = pls->chrht * 72.0/25.4; /* ft_ht in points, ht is in mm */
892
/* The transform matrix has only rotations and shears; extract them */
893
theta = acos(t[0]) * 180. / PI; /* Determine the rotation (in degrees)... */
894
if (t[2] < 0.) theta *= -1.; /* ... and sign ... */
895
cs = cos(theta*PI/180.);
896
sn = sin(theta*PI/180.);
897
tt[0] = t[0]*cs + t[2]*sn;
898
tt[1] = t[1]*cs + t[3]*sn;
899
tt[2] = -t[0]*sn + t[2]*cs;
900
tt[3] = -t[1]*sn + t[3]*cs;
903
* Reference point conventions:
904
* If base = 0, it is aligned with the center of the text box
905
* If base = 1, it is aligned with the baseline of the text box
906
* If base = 2, it is aligned with the top of the text box
908
* Currently plplot only uses base=0
909
* Postscript uses base=1
911
* We must calculate the difference between the two and apply the offset.
914
if (args->base == 2) /* not supported by plplot */
915
offset = ENLARGE * ft_ht / 2.; /* half font height */
916
else if (args->base == 1)
919
offset = -ENLARGE * ft_ht / 2.;
921
/* Determine the adjustment for page orientation */
922
theta -= 90.*pls->diorot;
923
args->y += (int) (offset*cos(theta*PI/180.));
924
args->x -= (int) (offset*sin(theta*PI/180.));
926
/* ps driver is rotated by default */
927
plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
928
&(args->x), &(args->y));
930
/* Correct for the fact ps driver uses landscape by default */
935
clipx[0]=pls->clpxmi;
936
clipx[2]=pls->clpxma;
937
clipy[0]=pls->clpymi;
938
clipy[2]=pls->clpyma;
943
difilt(clipx, clipy, 4, &clxmin, &clxmax, &clymin, &clymax);
944
plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
945
&clipx[0], &clipy[0]);
946
plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
947
&clipx[1], &clipy[1]);
948
plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
949
&clipx[2], &clipy[2]);
950
plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
951
&clipx[3], &clipy[3]);
952
// doc->osBody() << " gsave " << clipx[0] << " " << clipy[0] << " " <<
953
// clipx[1] << " " << clipy[1] << " " << clipx[2] << " " <<
954
// clipy[2] << " " << clipx[3] << " " << clipy[3] << " CL\n";
956
/* move to string reference point */
957
doc->osBody() << " " << args->x << " " << args->y << " M\n";
959
/* Save the current position and set the string rotation */
960
doc->osBody() << "gsave " << theta << " R\n";
962
doc->osBody() << "[" << tt[0] << " " << tt[2] << " " << tt[1]
963
<< " " << tt[3] << " 0 0] concat\n";
965
/* Purge escape sequences from string, to find it's
966
* length. The string length is computed with the current font,
967
* and can thus be wrong if there are font change escape sequences
970
esc_purge(str, cur_str);
972
doc->setFont(font,style,weight);
973
doc->setFontSize(font_factor*ENLARGE*ft_ht);
975
// Get the approximate length of the string to calculate offset
976
// Also used later for bounding box
977
doc->get_dimensions((const char *)str, &lineSpacing, &xAdvance);
978
xmin = -xAdvance*args->just;
983
/* Move relative to position to account for justification */
984
doc->osBody() << " gsave " << xmin*tt[0] << " " <<
985
xmin*tt[2] << " rmoveto\n";
987
/* Parse string for PLplot escape sequences and print everything out */
995
if (*cur_strp == esc) {
998
if (*cur_strp == esc) { /* <esc><esc> */
999
*strp++ = *cur_strp++;
1001
else if (*cur_strp == 'f') {
1003
if (*cur_strp++ != 'f') {
1004
/* escff occurs because of logic above. But any suffix
1005
* other than "f" should never happen. */
1006
plabort("proc_str, internal PLplot logic error;"
1007
"wrong escf escape sequence");
1012
weight = weights[f];
1014
/*pldebug("proc_str", "string-specified fci = 0x%x, font name = %s\n", fci, font);*/
1017
else switch (*cur_strp++) {
1021
if(up>0.) scale *= 1.25; /* Subscript scaling parameter */
1022
else scale *= 0.8; /* Subscript scaling parameter */
1023
up -= font_factor * ENLARGE * ft_ht / 2.;
1028
if(up<0.) scale *= 1.25; /* Subscript scaling parameter */
1029
else scale *= 0.8; /* Subscript scaling parameter */
1030
up += font_factor * ENLARGE * ft_ht / 2.;
1033
/* ignore the next sequences */
1039
plwarn("'+', '-', and 'b/B' text escape sequences not processed.");
1044
/* copy from current to next token, adding a postscript escape
1045
* char '\' if necessary
1047
while(*cur_strp && *cur_strp != esc) {
1048
*strp++ = *cur_strp++;
1052
if(fabs(up)<0.001) up = 0.; /* Watch out for small differences */
1054
/* Set the font size */
1055
doc->setFontSize(font_factor*ENLARGE*ft_ht*scale);
1056
doc->setFont(font,style,weight);
1057
doc->get_dimensions((const char *)str, &lineSpacing, &xAdvance, &ymintmp, &ymaxtmp);
1058
ymin = MIN(ymintmp+up,ymin);
1059
ymax = MAX(ymaxtmp+up,ymax);
1062
/* if up/down escape sequences, save current point and adjust baseline;
1063
* take the shear into account */
1065
doc->osBody() << "gsave " << up*tt[1] << " " << up*tt[3] << " rmoveto\n";
1067
/* print the string */
1068
doc->osBody() << show((const char *)str);
1070
/* back to baseline */
1072
doc->osBody() << "grestore (" << str << ") stringwidth rmoveto\n";
1076
doc->osBody() << "grestore\n";
1077
doc->osBody() << "grestore\n";
1080
* Estimate text bounding box from LASi get_dimensions function.
1081
* xmin, xmax are text left and right extents,
1082
* ymin, ymax are top and bottom extents.
1083
* These need to be rotated / transformed to get the correct values
1085
xx[0] = (PLINT) (t[0]*xmin+t[1]*ymin);
1086
yy[0] = (PLINT) (t[2]*xmin+t[3]*ymin);
1087
xx[1] = (PLINT) (t[0]*xmin+t[1]*ymax);
1088
yy[1] = (PLINT) (t[2]*xmin+t[3]*ymax);
1089
xx[2] = (PLINT) (t[0]*xmax+t[1]*ymin);
1090
yy[2] = (PLINT) (t[2]*xmax+t[3]*ymin);
1091
xx[3] = (PLINT) (t[0]*xmax+t[1]*ymax);
1092
yy[3] = (PLINT) (t[2]*xmax+t[3]*ymax);
1094
plRotPhy(ORIENTATION, 0,0,0,0, &xx[0], &yy[0]);
1095
plRotPhy(ORIENTATION, 0,0,0,0, &xx[1], &yy[1]);
1096
plRotPhy(ORIENTATION, 0,0,0,0, &xx[2], &yy[2]);
1097
plRotPhy(ORIENTATION, 0,0,0,0, &xx[3], &yy[3]);
1100
xmin = MIN(MIN(MIN(xx[0],xx[1]),xx[2]),xx[3])+args->x;
1101
xmax = MAX(MAX(MAX(xx[0],xx[1]),xx[2]),xx[3])+args->x;
1102
ymin = MIN(MIN(MIN(yy[0],yy[1]),yy[2]),yy[3])+args->y;
1103
ymax = MAX(MAX(MAX(yy[0],yy[1]),yy[2]),yy[3])+args->y;
1105
dev->llx = (int) (MIN(dev->llx, xmin));
1106
dev->lly = (int) (MIN(dev->lly, ymin));
1107
dev->urx = (int) (MAX(dev->urx, xmax));
1108
dev->ury = (int) (MAX(dev->ury, ymax));
1109
// doc->osBody() << "Z " << xmin << " " << ymin << " M "
1110
// << xmin << " " << ymax << " D "
1111
// << xmax << " " << ymax << " D "
1112
// << xmax << " " << ymin << " D "
1113
// << xmin << " " << ymin << " closepath\n"
1114
// << "Z " << args->x << " " << args->y << " A closepath\n";
1119
esc_purge(char *dstr, char *sstr) {
1140
break; /* two chars sequence */
1143
break; /* single char escape */
1157
#endif /* defined(PLD_psttf) || .... */