351
372
#define DEBUG_TEXT
375
#define hex2dec( a ) isdigit(a) ? a - 48 : (toupper(a) - 65) + 10
377
/*--------------------------------------------------------------------------*\
378
* int text2num( char *text, char end, PLUNICODE *num)
379
* char *text - pointer to the text to be parsed
380
* char end - end character (i.e. ')' or ']' to stop parsing
381
* PLUNICODE *num - pointer to an PLUNICODE to store the value
383
* Function takes a string, which can be either hex or decimal,
384
* and converts it into an PLUNICODE, stopping at either a null,
385
* or the character pointed to by 'end'. It is a bit brain-dead,
386
* and probably should make more checks, but it works.
387
\*--------------------------------------------------------------------------*/
389
int text2num( const char *text, char end, PLUNICODE *num)
401
while ((text[i]!=end)&&(text[i]!=0))
404
*num+=hex2dec(text[i]);
410
/*--------------------------------------------------------------------------*\
411
* int text2fci( char *text, unsigned char *hexdigit, unsigned char *hexpower)
412
* char *text - pointer to the text to be parsed
413
* unsigned char *hexdigit - pointer to hex value that is stored.
414
* unsigned char *hexpower - pointer to hex power (left shift) that is stored.
416
* Function takes a pointer to a string, which is looked up in a table
417
* to determine the corresponding FCI (font characterization integer)
418
* hex digit value and hex power (left shift). All matched strings
419
* start with "<" and end with the two characters "/>".
420
* If the lookup succeeds, hexdigit and hexpower are set to the appropriate
421
* values in the table, and the function returns the number of characters
422
* in text that are consumed by the matching string in the table lookup.
424
* If the lookup fails, hexdigit is set to 0, hexpower is set to and
425
* impossible value, and the function returns 0.
426
\*--------------------------------------------------------------------------*/
428
int text2fci( const char *text, unsigned char *hexdigit, unsigned char *hexpower)
433
unsigned char hexdigit;
434
unsigned char hexpower;
437
/* This defines the various font control commands and the corresponding
438
* hexdigit and hexpower in the FCI.
440
#define N_TextLookupTable 10
441
const TextLookupTable lookup[N_TextLookupTable] = {
442
{"<sans-serif/>", PL_FCI_SANS, PL_FCI_FAMILY},
443
{"<serif/>", PL_FCI_SERIF, PL_FCI_FAMILY},
444
{"<monospace/>", PL_FCI_MONO, PL_FCI_FAMILY},
445
{"<script/>", PL_FCI_SCRIPT, PL_FCI_FAMILY},
446
{"<symbol/>", PL_FCI_SYMBOL, PL_FCI_FAMILY},
447
{"<upright/>", PL_FCI_UPRIGHT, PL_FCI_STYLE},
448
{"<italic/>", PL_FCI_ITALIC, PL_FCI_STYLE},
449
{"<oblique/>", PL_FCI_OBLIQUE, PL_FCI_STYLE},
450
{"<medium/>", PL_FCI_MEDIUM, PL_FCI_WEIGHT},
451
{"<bold/>", PL_FCI_BOLD, PL_FCI_WEIGHT}
454
for (i=0; i<N_TextLookupTable; i++) {
455
length = strlen(lookup[i].ptext);
456
if (! strncmp(text, lookup[i].ptext, length)) {
457
*hexdigit = lookup[i].hexdigit;
458
*hexpower = lookup[i].hexpower;
463
*hexpower = PL_FCI_HEXPOWER_IMPOSSIBLE;
467
PLUNICODE unicode_buffer[1024];
355
470
plP_text(PLINT base, PLFLT just, PLFLT *xform, PLINT x, PLINT y,
356
471
PLINT refx, PLINT refy, const char *string)
358
if (plsc->dev_text) {
474
if (plsc->dev_text) { /* Does the device render it's own text ? */
490
args.string = string;
492
if (plsc->dev_unicode) { /* Does the device also understand unicode? */
494
PLUNICODE fci, fcisave;
495
unsigned char hexdigit, hexpower;
497
/* Now process the text string */
499
if (string!=NULL) { /* If the string isn't blank, then we will
503
len=strlen(string); /* this length is only used in the loop
504
* counter, we will work out the length of
505
* the unicode string as we go */
508
/* At this stage we will do some translations into unicode, like
509
* conversion to Greek , and will save other translations such as
510
* superscript for the driver to do later on. As we move through
511
* the string and do the translations, we will get
512
* rid of the esc character sequence, just replacing it with
516
/* Obtain FCI (font characterization integer) for start of
519
for (j=i=0;i<len;i++) { /* Walk through the string, and convert
520
* some stuff to unicode on the fly */
523
if (string[i]==esc) {
524
switch(string[i+1]) {
525
case '(': /* hershey code */
526
i+=2+text2num(&string[i+2],')',&code);
527
idx=plhershey2unicode(code);
528
/* momentarily switch to symbol font. */
530
plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
531
unicode_buffer[j++]= fci;
532
unicode_buffer[j++] = \
533
(PLUNICODE)hershey_to_unicode_lookup_table[idx].Unicode;
535
/* if unicode_buffer[j-1] corresponds to the escape
536
* character must unescape it by appending one more.
537
* This will probably always be necessary since it is
538
* likely unicode_buffer will always have to contain
539
* escape characters that are interpreted by the device
542
if (unicode_buffer[j-1]==esc) unicode_buffer[j++]=esc;
544
unicode_buffer[j]= fci;
548
case '[': /* unicode */
549
i+=2+text2num(&string[i+2],']',&code);
550
/* momentarily switch to symbol font. */
552
plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
553
unicode_buffer[j++]= fci;
554
unicode_buffer[j++]=code;
555
/* if unicode_buffer[j-1] corresponds to the escape
556
* character must unescape it by appending one more.
557
* This will probably always be necessary since it is
558
* likely unicode_buffer will always have to contain
559
* escape characters that are interpreted by the device
562
if (unicode_buffer[j-1]==esc) unicode_buffer[j++]=esc;
564
unicode_buffer[j] = fci;
568
case '<': /* change font*/
569
if ('0' <= string[i+2] && string[i+2] <= '9' ) {
570
i+=2+text2num(&string[i+2],'>', &code);
571
if (code & PL_FCI_MARK) {
572
/* code is a complete FCI (font characterization
573
* integer): change FCI to this value.
576
unicode_buffer[j]=fci;
580
/* code is not complete FCI. Change
581
* FCI with hex power in rightmost hex
582
* digit and hex digit value in second rightmost
585
hexdigit = (code >> 4) & PL_FCI_HEXDIGIT_MASK;
586
hexpower = code & PL_FCI_HEXPOWER_MASK;
587
plP_hex2fci(hexdigit, hexpower, &fci);
588
unicode_buffer[j]=fci;
594
i+=text2fci(&string[i+1], &hexdigit, &hexpower);
596
plP_hex2fci(hexdigit, hexpower, &fci);
597
unicode_buffer[j]=fci;
603
case 'f': /* Deprecated Hershey-style font change*/
604
case 'F': /* Deprecated Hershey-style font change*/
605
/* We implement an approximate response here so that
606
* reasonable results are obtained for unicode fonts,
607
* but this method is deprecated and the #<nnn> or
608
* #<command string> methods should be used instead
609
* to change unicode fonts in mid-string.
612
if (string[i+2] == 'n') {
613
/* medium, upright, sans-serif */
614
plP_hex2fci(PL_FCI_SANS, PL_FCI_FAMILY, &fci);
615
} else if (string[i+2] == 'r') {
616
/* medium, upright, serif */
617
plP_hex2fci(PL_FCI_SERIF, PL_FCI_FAMILY, &fci);
618
} else if (string[i+2] == 'i') {
619
/* medium, italic, serif */
620
plP_hex2fci(PL_FCI_ITALIC, PL_FCI_STYLE, &fci);
621
plP_hex2fci(PL_FCI_SERIF, PL_FCI_FAMILY, &fci);
622
} else if (string[i+2] == 's') {
623
/* medium, upright, script */
624
plP_hex2fci(PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci);
626
fci = PL_FCI_IMPOSSIBLE;
628
if (fci != PL_FCI_IMPOSSIBLE){
630
unicode_buffer[j] = fci;
635
case 'g': /* Greek font */
636
case 'G': /* Greek font */
637
/* Get the index in the lookup table
638
* 527 = upper case alpha displacement in Hershey Table
639
* 627 = lower case alpha displacement in Hershey Table
641
/* momentarily switch to symbol font. */
643
plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
644
unicode_buffer[j++]= fci;
645
ig = plP_strpos(plP_greek_mnemonic, string[i+2]);
649
idx=plhershey2unicode(ig+527);
650
unicode_buffer[j++] = \
651
(PLUNICODE)hershey_to_unicode_lookup_table[idx].Unicode;
653
skip=1; /* skip is set if we have copied something
654
* into the unicode table */
657
/* Use "unknown" unicode character if string[i+2]
658
* is not in the Greek array.*/
659
unicode_buffer[j++]=(PLUNICODE)0x00;
661
skip=1; /* skip is set if we have copied something
662
* into the unicode table */
665
unicode_buffer[j]= fci;
672
PLUNICODE unichar = 0;
673
#ifdef HAVE_LIBUNICODE
674
char* ptr = unicode_get_utf8 (string + i, &unichar);
676
char* ptr = utf8_to_ucs4 (string + i, &unichar);
680
strncpy (buf, string, 30);
681
sprintf (buf, "UTF-8 string is malformed: %s%s",
682
buf, strlen (string) > 30 ? "[...]" : "");
685
unicode_buffer [j] = unichar;
686
i += ptr - (string + i) - 1;
688
/* Search for escesc (an unescaped escape) in the input
689
* string and adjust unicode_buffer accordingly).
691
if (unicode_buffer[j] == esc && string[i+1] == esc) {
693
unicode_buffer[++j] = esc;
699
args.unicode_array_len=j; /* Much easier to set the length than
700
* work it out later :-) */
701
args.unicode_array=&unicode_buffer[0]; /* Get address of the
702
* unicode buffer (even
704
* currently static) */
706
/* Don't print anything, if there is no unicode to print! */
711
if (plsc->dev_unicode) {
712
args.string=NULL; /* We are using unicode */
368
715
args.string = string;
370
if (plsc->plbuf_write)
371
plbuf_esc(plsc, PLESC_HAS_TEXT, &args);
373
plP_esc(PLESC_HAS_TEXT, &args);
718
plP_esc(PLESC_HAS_TEXT, &args);
374
719
#ifndef DEBUG_TEXT
377
plstr(base, xform, refx, refy, string);
722
plstr(base, xform, refx, refy, string);
726
/* convert utf8 string to ucs4 unichar */
728
utf8_to_ucs4(const char *ptr, PLUNICODE *unichar)
735
/* Get next character in string */
737
if (isFirst) { /* First char in UTF8 sequence */
739
/* Determine length of sequence */
740
if ((unsigned char)(tmp & 0x80) == 0x00) { /* single char */
741
*unichar = (unsigned int)tmp & 0x7F;
743
} else if ((unsigned char)(tmp & 0xE0) == 0xC0) { /* 2 chars */
744
*unichar = (unsigned int)tmp & 0x1F;
746
} else if ((unsigned char)(tmp & 0xF0) == 0xE0) { /* 3 chars */
747
*unichar = (unsigned char)tmp & 0x0F;
749
} else if ((unsigned char)(tmp & 0xF8) == 0xF0) { /* 4 chars */
750
*unichar = (unsigned char)tmp & 0x07;
752
} else if ((unsigned char)(tmp & 0xFC) == 0xF8) { /* 5 chars */
753
*unichar = (unsigned char)tmp & 0x03;
755
} else if ((unsigned char)(tmp & 0xFE) == 0xFC) { /* 6 chars */
756
*unichar = (unsigned char)tmp & 0x01;
758
} else { /* Malformed */
762
} else { /* Subsequent char in UTF8 sequence */
763
if ((unsigned char)(tmp & 0xC0) == 0x80) {
764
*unichar = (*unichar << 6) | ((unsigned int)tmp & 0x3F);
766
} else { /* Malformed */
775
/* convert ucs4 unichar to utf8 string */
777
ucs4_to_utf8(PLUNICODE unichar, char *ptr)
782
tmp = (unsigned char *)ptr;
784
if ( (unichar & 0xffff80) == 0 ) { /* single byte */
785
*tmp = (unsigned char) unichar;
789
else if ( (unichar & 0xfff800) == 0) { /* two bytes */
790
*tmp = (unsigned char) 0xc0 | (unichar >> 6);
792
*tmp = (unsigned char) 0x80 | (unichar & 0x3f);
796
else if ( (unichar & 0xff0000) == 0) { /* three bytes */
797
*tmp = (unsigned char) 0xe0 | (unichar >> 12);
799
*tmp = (unsigned char) 0x80 | ((unichar >> 6) & 0x3f);
801
*tmp = (unsigned char) 0x80 | (unichar & 0x3f);
805
else if ( (unichar & 0xe0000) == 0){ /* four bytes */
806
*tmp = (unsigned char) 0xf0 | (unichar >> 18);
808
*tmp = (unsigned char) 0x80 | ((unichar >> 12) & 0x3f);
810
*tmp = (unsigned char) 0x80 | ((unichar >> 6) & 0x3f);
812
*tmp = (unsigned char) 0x80 | (unichar & 0x3f);
816
else { /* Illegal coding */
382
825
grline(short *x, short *y, PLINT npts)
384
(*plsc->dispatch_table->pl_line) ( (struct PLStream_struct *) plsc,
385
x[0], y[0], x[1], y[1] );
827
(*plsc->dispatch_table->pl_line) ( (struct PLStream_struct *) plsc,
828
x[0], y[0], x[1], y[1] );
389
832
grpolyline(short *x, short *y, PLINT npts)
391
(*plsc->dispatch_table->pl_polyline) ( (struct PLStream_struct *) plsc,
834
(*plsc->dispatch_table->pl_polyline) ( (struct PLStream_struct *) plsc,
396
839
grfill(short *x, short *y, PLINT npts)
398
plsc->dev_npts = npts;
841
plsc->dev_npts = npts;
402
(*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
845
(*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
406
849
/*--------------------------------------------------------------------------*\