The R Project SVN R

Rev

Rev 29864 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 29864 Rev 30691
Line 1... Line 1...
1
/*
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
4
 *  Copyright (C) 1998--2003  Robert Gentleman, Ross Ihaka and the
4
 *  Copyright (C) 1998--2004  Robert Gentleman, Ross Ihaka and the
5
 *                            R Development Core Team
5
 *                            R Development Core Team
6
 *
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  the Free Software Foundation; either version 2 of the License, or
Line 161... Line 161...
161
 
161
 
162
    { NULL }
162
    { NULL }
163
};
163
};
164
 
164
 
165
 
165
 
166
static char familyname[5][50];
-
 
167
 
-
 
168
/* Part 1.  AFM File Parsing.  */
166
/* Part 1.  AFM File Parsing.  */
169
 
167
 
170
/* These are the basic entities in the AFM file */
168
/* These are the basic entities in the AFM file */
171
 
169
 
172
#define BUFSIZE 512
170
#define BUFSIZE 512
Line 315... Line 313...
315
	    (metrics->FontBBox[3]));
313
	    (metrics->FontBBox[3]));
316
#endif
314
#endif
317
    return 1;
315
    return 1;
318
}
316
}
319
 
317
 
320
static char charnames[256][25];
318
typedef struct {
321
static char encnames[256][25];
319
    char cname[25];
-
 
320
} CNAME;
322
 
321
 
323
/* If reencode > 0, remap to new encoding */
322
/* If reencode > 0, remap to new encoding */
324
static int GetCharInfo(char *buf, FontMetricInfo *metrics, int reencode)
323
static int GetCharInfo(char *buf, FontMetricInfo *metrics, 
-
 
324
		       CNAME *charnames, CNAME *encnames,
-
 
325
		       int reencode)
325
{
326
{
326
    char *p = buf, charname[25];
327
    char *p = buf, charname[25];
327
    int nchar, nchar2=-1, i;
328
    int nchar, nchar2=-1, i;
328
    short WX;
329
    short WX;
329
 
330
 
Line 346... Line 347...
346
	Rprintf("char name %s\n", charname);
347
	Rprintf("char name %s\n", charname);
347
#endif
348
#endif
348
	/* a few chars appear twice in ISOLatin1 */
349
	/* a few chars appear twice in ISOLatin1 */
349
	nchar = nchar2 = -1;
350
	nchar = nchar2 = -1;
350
	for (i = 0; i < 256; i++)
351
	for (i = 0; i < 256; i++)
351
	    if(!strcmp(charname, encnames[i])) {
352
	    if(!strcmp(charname, encnames[i].cname)) {
352
		strcpy(charnames[i], charname);
353
		strcpy(charnames[i].cname, charname);
353
		if(nchar == -1) nchar = i; else nchar2 = i;
354
		if(nchar == -1) nchar = i; else nchar2 = i;
354
	    }
355
	    }
355
	if (nchar == -1) return 1;
356
	if (nchar == -1) return 1;
356
    } else {
357
    } else {
357
	sscanf(p, "%s", charnames[nchar]);
358
	sscanf(p, "%s", charnames[nchar].cname);
358
    }
359
    }
359
    metrics->CharInfo[nchar].WX = WX;
360
    metrics->CharInfo[nchar].WX = WX;
360
    p = SkipToNextKey(p);
361
    p = SkipToNextKey(p);
361
 
362
 
362
    if (!MatchKey(p, "B ")) return 0;
363
    if (!MatchKey(p, "B ")) return 0;
Line 393... Line 394...
393
#endif
394
#endif
394
    }
395
    }
395
    return 1;
396
    return 1;
396
}
397
}
397
 
398
 
398
static int GetKPX(char *buf, int nkp, FontMetricInfo *metrics)
399
static int GetKPX(char *buf, int nkp, FontMetricInfo *metrics,
-
 
400
		  CNAME *charnames)
399
{
401
{
400
    char *p = buf, c1[50], c2[50];
402
    char *p = buf, c1[50], c2[50];
401
    int i, done = 0;
403
    int i, done = 0;
402
 
404
 
403
    p = SkipToNextItem(p);
405
    p = SkipToNextItem(p);
404
    sscanf(p, "%s %s %hd", c1, c2, &(metrics->KernPairs[nkp].kern));
406
    sscanf(p, "%s %s %hd", c1, c2, &(metrics->KernPairs[nkp].kern));
405
    for(i = 0; i < 256; i++) {
407
    for(i = 0; i < 256; i++) {
406
	if (!strcmp(c1, charnames[i])) {
408
	if (!strcmp(c1, charnames[i].cname)) {
407
	    metrics->KernPairs[nkp].c1 = i;
409
	    metrics->KernPairs[nkp].c1 = i;
408
	    done++;
410
	    done++;
409
	    break;
411
	    break;
410
	}
412
	}
411
    }
413
    }
412
    for(i = 0; i < 256; i++)
414
    for(i = 0; i < 256; i++)
413
	if (!strcmp(c2, charnames[i])) {
415
	if (!strcmp(c2, charnames[i].cname)) {
414
	    metrics->KernPairs[nkp].c2 = i;
416
	    metrics->KernPairs[nkp].c2 = i;
415
	    done++;
417
	    done++;
416
	    break;
418
	    break;
417
	}
419
	}
418
    return (done==2);
420
    return (done==2);
Line 450... Line 452...
450
	break;
452
	break;
451
    }
453
    }
452
    return 0;
454
    return 0;
453
}
455
}
454
 
456
 
455
static char enccode[5000];
-
 
456
 
-
 
457
/* Load encoding array from a file: defaults to the R_HOME/afm directory */
457
/* Load encoding array from a file: defaults to the R_HOME/afm directory */
-
 
458
 
-
 
459
/*
-
 
460
 * encpath gives the file to read from
-
 
461
 * encname is filled with the encoding name from the file
-
 
462
 * encnames is filled with the character names from the file 
-
 
463
 * enccode is filled with the raw source of the file
-
 
464
 */
458
static int
465
static int
459
LoadEncoding(char *encpath, char *encname, Rboolean isPDF)
466
LoadEncoding(char *encpath, char *encname, CNAME *encnames,
-
 
467
	     char *enccode, Rboolean isPDF)
460
{
468
{
461
    char buf[BUFSIZE];
469
    char buf[BUFSIZE];
462
    int i;
470
    int i;
463
    FILE *fp;
471
    FILE *fp;
464
    EncodingInputState state;
472
    EncodingInputState state;
Line 478... Line 486...
478
    if (!isPDF) snprintf(enccode, 5000, "/%s [\n", encname);
486
    if (!isPDF) snprintf(enccode, 5000, "/%s [\n", encname);
479
    else enccode[0] = '\0';
487
    else enccode[0] = '\0';
480
    if (GetNextItem(fp, buf, 0, &state)) { fclose(fp); return 0;} /* [ */
488
    if (GetNextItem(fp, buf, 0, &state)) { fclose(fp); return 0;} /* [ */
481
    for(i = 0; i < 256; i++) {
489
    for(i = 0; i < 256; i++) {
482
	if (GetNextItem(fp, buf, i, &state)) { fclose(fp); return 0; }
490
	if (GetNextItem(fp, buf, i, &state)) { fclose(fp); return 0; }
483
	strcpy(encnames[i], buf+1);
491
	strcpy(encnames[i].cname, buf+1);
484
	strcat(enccode, " /"); strcat(enccode, encnames[i]);
492
	strcat(enccode, " /"); strcat(enccode, encnames[i].cname);
485
	if(i%8 == 7) strcat(enccode, "\n");
493
	if(i%8 == 7) strcat(enccode, "\n");
486
    }
494
    }
487
    if (GetNextItem(fp, buf, 0, &state)) { fclose(fp); return 0;} /* ] */
495
    if (GetNextItem(fp, buf, 0, &state)) { fclose(fp); return 0;} /* ] */
488
    fclose(fp);
496
    fclose(fp);
489
    if (!isPDF) strcat(enccode,"]\n");
497
    if (!isPDF) strcat(enccode,"]\n");
Line 493... Line 501...
493
 
501
 
494
 
502
 
495
/* Load font metrics from a file: defaults to the R_HOME/afm directory */
503
/* Load font metrics from a file: defaults to the R_HOME/afm directory */
496
 
504
 
497
static int
505
static int
498
PostScriptLoadFontMetrics(const char * const fontpath, FontMetricInfo *metrics,
506
PostScriptLoadFontMetrics(const char * const fontpath, 
-
 
507
			  FontMetricInfo *metrics,
499
			  char *fontname, int reencode)
508
			  char *fontname, 
-
 
509
			  CNAME *charnames,
-
 
510
			  CNAME *encnames,
-
 
511
			  int reencode)
500
{
512
{
501
    char buf[BUFSIZE], *p;
513
    char buf[BUFSIZE], *p;
502
    int mode, i = 0, j, ii, nKPX=0;
514
    int mode, i = 0, j, ii, nKPX=0;
503
    FILE *fp;
515
    FILE *fp;
504
 
516
 
Line 509... Line 521...
509
    Rprintf("reencode is %d\n", reencode);
521
    Rprintf("reencode is %d\n", reencode);
510
#endif
522
#endif
511
 
523
 
512
    if (!(fp = R_fopen(R_ExpandFileName(buf), "r"))) return 0;
524
    if (!(fp = R_fopen(R_ExpandFileName(buf), "r"))) return 0;
513
 
525
 
-
 
526
    metrics->KernPairs = NULL;
514
    mode = 0;
527
    mode = 0;
515
    for (ii = 0; ii < 256; ii++) {
528
    for (ii = 0; ii < 256; ii++) {
516
	charnames[ii][0] = '\0';
529
	charnames[ii].cname[0] = '\0';
517
	metrics->CharInfo[ii].WX = NA_SHORT;
530
	metrics->CharInfo[ii].WX = NA_SHORT;
518
	for(j = 0; j < 4; j++) metrics->CharInfo[ii].BBox[j] = 0;
531
	for(j = 0; j < 4; j++) metrics->CharInfo[ii].BBox[j] = 0;
519
    }
532
    }
520
    while (fgets(buf, BUFSIZE, fp)) {
533
    while (fgets(buf, BUFSIZE, fp)) {
521
	switch(KeyType(buf)) {
534
	switch(KeyType(buf)) {
Line 532... Line 545...
532
	    if (!GetFontBBox(buf, metrics)) goto pserror;
545
	    if (!GetFontBBox(buf, metrics)) goto pserror;
533
	    break;
546
	    break;
534
 
547
 
535
	case C:
548
	case C:
536
	    if (mode != StartFontMetrics) goto pserror;
549
	    if (mode != StartFontMetrics) goto pserror;
537
	    if (!GetCharInfo(buf, metrics, reencode)) goto pserror;
550
	    if (!GetCharInfo(buf, metrics, charnames, encnames, reencode)) 
-
 
551
		goto pserror;
538
	    break;
552
	    break;
539
 
553
 
540
	case StartKernData:
554
	case StartKernData:
541
	    mode = StartKernData;
555
	    mode = StartKernData;
542
	    break;
556
	    break;
Line 552... Line 566...
552
	    }
566
	    }
553
	    break;
567
	    break;
554
 
568
 
555
	case KPX:
569
	case KPX:
556
	    if(mode != StartKernData || i >= nKPX) goto pserror;
570
	    if(mode != StartKernData || i >= nKPX) goto pserror;
557
	    if (GetKPX(buf, i, metrics)) i++;
571
	    if (GetKPX(buf, i, metrics, charnames)) i++;
558
	    break;
572
	    break;
559
 
573
 
560
	case EndKernData:
574
	case EndKernData:
561
	    mode = 0;
575
	    mode = 0;
562
	    break;
576
	    break;
Line 651... Line 665...
651
	*width = 0.001 * wx;
665
	*width = 0.001 * wx;
652
    }
666
    }
653
}
667
}
654
 
668
 
655
 
669
 
-
 
670
/*******************************************************
-
 
671
 * Data structures and functions for loading Type 1 fonts into an R session.
-
 
672
 *
-
 
673
 * Used by PostScript, XFig and PDF drivers.
-
 
674
 *
-
 
675
 * The idea is that font information is only loaded once for each font 
-
 
676
 * within an R session.  Also, each encoding is only loaded once per
-
 
677
 * session.  A global list of loaded fonts and a global list of 
-
 
678
 * loaded encodings are maintained.  Devices maintain their own list
-
 
679
 * of fonts and encodings used on the device;  the elements of these
-
 
680
 * lists are just pointers to the elements of the global lists.
-
 
681
 * 
-
 
682
 * Cleaning up device lists just involves free'ing the lists themselves.
-
 
683
 * When the R session closes, the actual font and encoding information
-
 
684
 * is unloaded using the global lists.
-
 
685
 */
-
 
686
 
-
 
687
/*
656
/*  Part 2.  Graphics Support Code.  */
688
 * Information about one Type 1 font 
-
 
689
 */
-
 
690
typedef struct T1FontInfo {
-
 
691
    char name[50];
-
 
692
    FontMetricInfo metrics;
-
 
693
    CNAME charnames[256];
-
 
694
} Type1FontInfo, *type1fontinfo;
-
 
695
 
-
 
696
/*
-
 
697
 * Information about a font encoding
-
 
698
 */
-
 
699
typedef struct EncInfo {
-
 
700
    char encpath[PATH_MAX]; 
-
 
701
    char name[100]; 
-
 
702
    CNAME encnames[256];    
-
 
703
    char enccode[5000];
-
 
704
} EncodingInfo, *encodinginfo;
657
 
705
 
-
 
706
/*
-
 
707
 * Information about a font family 
-
 
708
 * (5 fonts representing plain, bold, italic, bolditalic, and symbol)
-
 
709
 *
-
 
710
 * The name is a graphics engine font family name
-
 
711
 * (distinct from the Type 1 font name)
-
 
712
 */
-
 
713
typedef struct T1FontFamily {
-
 
714
    char name[50];
-
 
715
    type1fontinfo fonts[5];
-
 
716
    encodinginfo encoding;
-
 
717
} Type1FontFamily, *type1fontfamily;
-
 
718
 
-
 
719
/*
-
 
720
 * A list of Type 1 font families
-
 
721
 *
-
 
722
 * Used to keep track of fonts currently loaded in the session
658
static const char * const TypeFaceDef[] = { "R", "B", "I", "BI", "S" };
723
 * AND by each device to keep track of fonts currently used on the device.
-
 
724
 */
-
 
725
typedef struct T1FontList {
-
 
726
    type1fontfamily family;
-
 
727
    struct T1FontList *next;
-
 
728
} Type1FontList, *type1fontlist;
-
 
729
 
-
 
730
/*
-
 
731
 * Same as type 1 font list, but for encodings.
-
 
732
 */
-
 
733
typedef struct EncList {
-
 
734
    encodinginfo encoding;
-
 
735
    struct EncList *next;
-
 
736
} EncodingList, *encodinglist;
-
 
737
 
-
 
738
/*
-
 
739
 * Various constructors and destructors
-
 
740
 */
-
 
741
static type1fontinfo makeType1Font() 
-
 
742
{
-
 
743
    type1fontinfo font = (Type1FontInfo *) malloc(sizeof(Type1FontInfo));    
-
 
744
    if (!font)
-
 
745
	warning("Failed to allocate Type 1 font info");
-
 
746
    return font;
-
 
747
}
659
 
748
 
-
 
749
static void freeType1Font(type1fontinfo font) 
-
 
750
{
-
 
751
    if (font->metrics.KernPairs) 
-
 
752
	free(font->metrics.KernPairs);
-
 
753
    free(font);
-
 
754
}
-
 
755
 
-
 
756
static encodinginfo makeEncoding()
-
 
757
{
-
 
758
    encodinginfo encoding = (EncodingInfo *) malloc(sizeof(EncodingInfo));
-
 
759
    if (!encoding) 
-
 
760
	warning("Failed to allocate encoding info");
-
 
761
    return encoding;
-
 
762
}
-
 
763
 
660
static void PSEncodeFont(FILE *fp, char *encname)
764
static void freeEncoding(encodinginfo encoding)
-
 
765
{
-
 
766
    free(encoding);
-
 
767
}
-
 
768
 
-
 
769
static type1fontfamily makeFontFamily()
-
 
770
{
-
 
771
    type1fontfamily family = (Type1FontFamily *) malloc(sizeof(Type1FontFamily));
-
 
772
    if (family) {
-
 
773
	int i;
-
 
774
	for (i=0; i<5; i++)
-
 
775
	    family->fonts[i] = NULL;
-
 
776
	family->encoding = NULL;
-
 
777
    } else
-
 
778
	warning("Failed to allocate Type 1 font family");
-
 
779
    return family;
-
 
780
}
-
 
781
 
-
 
782
/*
-
 
783
 * Frees a font family, including fonts, but NOT encoding
-
 
784
 *
-
 
785
 * Used by global font list to free all fonts loaded in session
-
 
786
 * (should not be used by devices; else may free fonts more than once)
-
 
787
 *
-
 
788
 * Encodings a freed using the global encoding list
-
 
789
 * (to ensure that each encoding is only freed once)
-
 
790
 */
-
 
791
static void freeFontFamily(type1fontfamily family)
661
{
792
{
662
    int i;
793
    int i;
-
 
794
    for (i=0; i<5; i++)
-
 
795
	if (family->fonts[i])
-
 
796
	    freeType1Font(family->fonts[i]);
-
 
797
    free(family);
-
 
798
}
663
 
799
 
-
 
800
static type1fontlist makeFontList()
-
 
801
{
664
    /* include encoding unless it is ISOLatin1Encoding, which is predefined */
802
    type1fontlist fontlist = (Type1FontList *) malloc(sizeof(Type1FontList));
665
    if (strcmp(encname, "ISOLatin1Encoding"))
803
    if (fontlist) {
-
 
804
	fontlist->family = NULL;
-
 
805
	fontlist->next = NULL;
-
 
806
    } else
666
	fprintf(fp, "%% begin encoding\n%s def\n%% end encoding\n", enccode);
807
	warning("Failed to allocate font list");
-
 
808
    return fontlist;
-
 
809
}
667
 
810
 
-
 
811
/*
-
 
812
 * Just free the Type1FontList structure, do NOT free elements it points to
-
 
813
 *
-
 
814
 * Used by both global font list and devices to free the font lists
-
 
815
 * (global font list separately takes care of the fonts pointed to)
-
 
816
 */
-
 
817
static void freeFontList(type1fontlist fontlist) {
-
 
818
    /* 
-
 
819
     * These will help to find any errors if attempt to
-
 
820
     * use freed font list.
-
 
821
     */
-
 
822
    fontlist->family = NULL;
-
 
823
    fontlist->next = NULL;
-
 
824
    free(fontlist);
-
 
825
}
-
 
826
 
-
 
827
static void freeDeviceFontList(type1fontlist fontlist) {
-
 
828
    if (fontlist) {
-
 
829
	if (fontlist->next) 
-
 
830
	    freeDeviceFontList(fontlist->next);
-
 
831
	freeFontList(fontlist);
-
 
832
    }
-
 
833
}
-
 
834
 
-
 
835
static encodinglist makeEncList()
-
 
836
{
-
 
837
    encodinglist enclist = (EncodingList *) malloc(sizeof(EncodingList));
-
 
838
    if (enclist) {
-
 
839
	enclist->encoding = NULL;
-
 
840
	enclist->next = NULL;
-
 
841
    } else
-
 
842
	warning("Failed to allocated encoding list");
-
 
843
    return enclist;
-
 
844
}
-
 
845
 
-
 
846
static void freeEncList(encodinglist enclist) 
-
 
847
{
-
 
848
    enclist->encoding = NULL;
-
 
849
    enclist->next = NULL;
-
 
850
    free(enclist);
-
 
851
}
-
 
852
 
-
 
853
static void freeDeviceEncList(encodinglist enclist) {
-
 
854
    if (enclist) {
-
 
855
	if (enclist->next) 
-
 
856
	    freeDeviceEncList(enclist->next);
-
 
857
	freeEncList(enclist);
-
 
858
    }
-
 
859
}
-
 
860
 
-
 
861
/*
-
 
862
 * Global list of fonts and encodings that have been loaded this session
-
 
863
 */
-
 
864
static type1fontlist loadedFonts = NULL;
-
 
865
static encodinglist loadedEncodings = NULL;
-
 
866
 
-
 
867
/*
-
 
868
 * Free the above globals
-
 
869
 * 
-
 
870
 * NOTE that freeing the font families does NOT free the encodings
-
 
871
 * Hence we free all encodings first.
-
 
872
 */
-
 
873
void freeType1Fonts() 
-
 
874
{
-
 
875
    encodinglist enclist = loadedEncodings;
-
 
876
    type1fontlist fontlist = loadedFonts;
-
 
877
    while (enclist) {
-
 
878
	enclist = enclist->next;
-
 
879
	freeEncoding(loadedEncodings->encoding);
-
 
880
	freeEncList(loadedEncodings);
-
 
881
	loadedEncodings = enclist;
-
 
882
    }
-
 
883
    while (fontlist) {
-
 
884
	fontlist = fontlist->next;
-
 
885
	freeFontFamily(loadedFonts->family);
-
 
886
	freeFontList(loadedFonts);
-
 
887
	loadedFonts = fontlist;
-
 
888
    }
-
 
889
}
-
 
890
 
-
 
891
/*
-
 
892
 * Given a path to an encoding file, 
-
 
893
 * find an EncodingInfo that corresponds
-
 
894
 */
-
 
895
static encodinginfo findEncoding(char *encpath) 
-
 
896
{
-
 
897
    encodinglist enclist = loadedEncodings;
-
 
898
    encodinginfo encoding = NULL;
-
 
899
    int found = 0;
-
 
900
    while (enclist && !found) {
-
 
901
	found = !strcmp(encpath, enclist->encoding->encpath);
-
 
902
	if (found)
-
 
903
	    encoding = enclist->encoding;
-
 
904
	enclist = enclist->next;
-
 
905
    }
-
 
906
    return encoding;
-
 
907
}
-
 
908
 
-
 
909
/*
-
 
910
 * Find an encoding in device encoding list
-
 
911
 */
-
 
912
static encodinginfo findDeviceEncoding(char *encpath, encodinglist enclist,
-
 
913
				       int *index)
-
 
914
{
-
 
915
    encodinginfo encoding = NULL;
-
 
916
    int found = 0;
-
 
917
    *index = 0;
-
 
918
    while (enclist && !found) {
-
 
919
	found = !strcmp(encpath, enclist->encoding->encpath);
-
 
920
	if (found)
-
 
921
	    encoding = enclist->encoding;
-
 
922
	enclist = enclist->next;
-
 
923
	*index = *index + 1;
-
 
924
    }
-
 
925
    return encoding;
-
 
926
}
-
 
927
 
-
 
928
/*
-
 
929
 * Utility to avoid string overrun
-
 
930
 */
-
 
931
static void safestrcpy(char *dest, char *src, int maxlen)
-
 
932
{
-
 
933
    if (strlen(src) < maxlen)
-
 
934
	strcpy(dest, src);
-
 
935
    else { 
-
 
936
	warning("Truncated string which was too long for copy");
-
 
937
	strncpy(dest, src, maxlen-1);
-
 
938
	dest[maxlen-1] = '\0';
-
 
939
    }
-
 
940
}
-
 
941
 
-
 
942
/*
-
 
943
 * Add an encoding to the list of loaded encodings ...
-
 
944
 *
-
 
945
 * ... and return the new encoding
-
 
946
 */
-
 
947
static encodinginfo addEncoding(char* encpath, 
-
 
948
				Rboolean isPDF) 
-
 
949
{
-
 
950
    encodinginfo encoding = makeEncoding();
-
 
951
    if (encoding) {
-
 
952
	if (LoadEncoding(encpath, 
-
 
953
			 encoding->name, encoding->encnames, 
-
 
954
			 encoding->enccode, 
-
 
955
			 isPDF)) {
-
 
956
	    encodinglist newenc = makeEncList();
-
 
957
	    if (!newenc) {
-
 
958
		freeEncoding(encoding);
-
 
959
		encoding = NULL;
-
 
960
	    } else {
-
 
961
		encodinglist enclist = loadedEncodings;
-
 
962
		safestrcpy(encoding->encpath, encpath, PATH_MAX);
-
 
963
		newenc->encoding = encoding;
-
 
964
		if (!enclist)
-
 
965
		    loadedEncodings = newenc;
-
 
966
		else {
-
 
967
		    while (enclist->next) 
-
 
968
			enclist = enclist->next;
-
 
969
		    enclist->next = newenc;
-
 
970
		}
-
 
971
	    }
-
 
972
	} else {
-
 
973
	    warning("Failed to load encoding file");
-
 
974
	    freeEncoding(encoding);
-
 
975
	    encoding = NULL;
-
 
976
	}
-
 
977
    } else
-
 
978
	encoding = NULL;
-
 
979
    return encoding;
-
 
980
}
-
 
981
 
-
 
982
/*
-
 
983
 * Add an encoding to a list of device encodings ...
-
 
984
 *
-
 
985
 * ... and return the new list
-
 
986
 */
-
 
987
static encodinglist addDeviceEncoding(encodinginfo encoding,
-
 
988
				      encodinglist devEncs)
-
 
989
{
-
 
990
    encodinglist newenc = makeEncList();
-
 
991
    if (!newenc) {
-
 
992
	devEncs = NULL;
-
 
993
    } else {
-
 
994
	encodinglist enclist = devEncs;
-
 
995
	newenc->encoding = encoding;
-
 
996
	if (!devEncs)
-
 
997
	    devEncs = newenc;
-
 
998
	else {
-
 
999
	    while (enclist->next)
-
 
1000
		enclist = enclist->next;
-
 
1001
	    enclist->next = newenc;
-
 
1002
	}
-
 
1003
    }
-
 
1004
    return devEncs;
-
 
1005
}
-
 
1006
 
-
 
1007
/*
-
 
1008
 * Given a graphics engine font family name,
-
 
1009
 * find a Type1FontFamily that corresponds
-
 
1010
 * 
-
 
1011
 * Returns NULL if can't find font in loadedFonts
-
 
1012
 */
-
 
1013
static type1fontfamily findLoadedFont(char *name) 
-
 
1014
{
-
 
1015
    type1fontlist fontlist = loadedFonts;
-
 
1016
    type1fontfamily font = NULL;
-
 
1017
    int found = 0;
-
 
1018
    while (fontlist && !found) {
-
 
1019
	found = !strcmp(name, fontlist->family->name);
-
 
1020
	if (found)
-
 
1021
	    font = fontlist->family;
-
 
1022
	fontlist = fontlist->next;
-
 
1023
    }
-
 
1024
    return font;
-
 
1025
}
-
 
1026
 
-
 
1027
SEXP do_Type1FontInUse(SEXP call, SEXP op, SEXP args, SEXP env)
-
 
1028
{
-
 
1029
    SEXP result;
-
 
1030
    SEXP name = CAR(args);
-
 
1031
    if (!isString(name) || LENGTH(name) > 1)
-
 
1032
	error("Invalid font name or more than one font name");
-
 
1033
    PROTECT(result = allocVector(LGLSXP, 1));
-
 
1034
    if (findLoadedFont(CHAR(STRING_ELT(name, 0))))
-
 
1035
	LOGICAL(result)[0] = TRUE;
-
 
1036
    else
-
 
1037
	LOGICAL(result)[0] = FALSE;
-
 
1038
    UNPROTECT(1);
-
 
1039
    return result;
-
 
1040
}
-
 
1041
 
-
 
1042
/*
-
 
1043
 * Same as findLoadedFont only given different info
-
 
1044
 */
-
 
1045
static type1fontfamily findDefaultLoadedFont(char *encpath, char* family,
-
 
1046
					     Rboolean isPDF)
-
 
1047
{
-
 
1048
    type1fontlist fontlist = loadedFonts;
-
 
1049
    type1fontfamily font = NULL;
-
 
1050
    int found = 0;
-
 
1051
    while (fontlist && !found) {
-
 
1052
	found = 
-
 
1053
	    !strcmp(encpath, fontlist->family->encoding->encpath) &&
-
 
1054
	    !strcmp(family, fontlist->family->fonts[0]->name);
-
 
1055
	if (found)
-
 
1056
	    font = fontlist->family;
-
 
1057
	fontlist = fontlist->next;
-
 
1058
    }
-
 
1059
    return font;
-
 
1060
}
-
 
1061
 
-
 
1062
/*
-
 
1063
 * Find a font in device font list
-
 
1064
 */
-
 
1065
static type1fontfamily findDeviceFont(char *name, type1fontlist fontlist,
-
 
1066
				      int *index) 
-
 
1067
{
-
 
1068
    type1fontfamily font = NULL;
-
 
1069
    int found = 0;
-
 
1070
    *index = 0;
-
 
1071
    /*
-
 
1072
     * If the graphics engine font family is ""
-
 
1073
     * just use the default font that was loaded when the device
-
 
1074
     * was created. 
-
 
1075
     * This will (MUST) be the first font in the device
-
 
1076
     */
-
 
1077
    if (strlen(name) > 0) {
-
 
1078
	while (fontlist && !found) {
-
 
1079
	    found = !strcmp(name, fontlist->family->name);
-
 
1080
	    if (found)
-
 
1081
		font = fontlist->family;
-
 
1082
	    fontlist = fontlist->next;
-
 
1083
	    *index = *index + 1;
-
 
1084
	}
-
 
1085
    } else {
-
 
1086
	font = fontlist->family;
-
 
1087
	*index = 1;
-
 
1088
    }
-
 
1089
    return font;    
-
 
1090
}
-
 
1091
 
-
 
1092
/*
-
 
1093
 * Get the path to the afm file for a user-specifed font
-
 
1094
 * given a graphics engine font family and the face
-
 
1095
 * index (0..4)
-
 
1096
 *
-
 
1097
 * Do this by looking up the font name in the PostScript
-
 
1098
 * font database
-
 
1099
 */
-
 
1100
static char* fontMetricsFileName(char *family, int faceIndex)
-
 
1101
{
-
 
1102
    SEXP graphicsNS, PSenv, fontdb, fontnames;
-
 
1103
    int i, nfonts;
-
 
1104
    char* result = NULL;
-
 
1105
    int found = 0;
-
 
1106
    PROTECT(graphicsNS = R_FindNamespace(ScalarString(mkChar("grDevices"))));
-
 
1107
    PROTECT(PSenv = findVar(install(".PSenv"), graphicsNS));
-
 
1108
    /* under lazy loading this will be a promise on first use */
-
 
1109
    if(TYPEOF(PSenv) == PROMSXP) {
-
 
1110
	PROTECT(PSenv);
-
 
1111
	PSenv = eval(PSenv, graphicsNS);
-
 
1112
	UNPROTECT(1);
-
 
1113
    }
-
 
1114
    PROTECT(fontdb = findVar(install(".PostScript.Fonts"), PSenv));
-
 
1115
    PROTECT(fontnames = getAttrib(fontdb, R_NamesSymbol));
-
 
1116
    nfonts = LENGTH(fontdb);
-
 
1117
    for (i=0; i<nfonts && !found; i++) {
-
 
1118
	char* fontFamily = CHAR(STRING_ELT(fontnames, i));
668
    if(strcmp(familyname[4], "CMSY10 CMBSY10 CMMI10") == 0) {
1119
	if (strcmp(family, fontFamily) == 0) {
-
 
1120
	    found = 1;
-
 
1121
	    result = CHAR(STRING_ELT(VECTOR_ELT(VECTOR_ELT(fontdb, i), 1), 
-
 
1122
				     faceIndex));
-
 
1123
	}
-
 
1124
    }
-
 
1125
    if (!found)
-
 
1126
	warning("Font family not found in PostScript font database");
-
 
1127
    UNPROTECT(4);
-
 
1128
    return result;
-
 
1129
}
-
 
1130
 
-
 
1131
static char WinAnsiEnc[] = "WinAnsi.enc";
-
 
1132
static char ISOLatin1Enc[] = "ISOLatin1.enc";
-
 
1133
 
-
 
1134
/* 
-
 
1135
 * Get encoding name from font database
-
 
1136
 */
-
 
1137
static char* getFontEncoding(char *family) {
-
 
1138
    SEXP graphicsNS, PSenv, fontdb, fontnames;
-
 
1139
    int i, nfonts;
-
 
1140
    char* result = NULL;
-
 
1141
    int found = 0;
-
 
1142
    PROTECT(graphicsNS = R_FindNamespace(ScalarString(mkChar("grDevices"))));
-
 
1143
    PROTECT(PSenv = findVar(install(".PSenv"), graphicsNS));
-
 
1144
    /* under lazy loading this will be a promise on first use */
-
 
1145
    if(TYPEOF(PSenv) == PROMSXP) {
-
 
1146
	PROTECT(PSenv);
-
 
1147
	PSenv = eval(PSenv, graphicsNS);
-
 
1148
	UNPROTECT(1);
-
 
1149
    }
-
 
1150
    PROTECT(fontdb = findVar(install(".PostScript.Fonts"), PSenv));
-
 
1151
    PROTECT(fontnames = getAttrib(fontdb, R_NamesSymbol));
-
 
1152
    nfonts = LENGTH(fontdb);
-
 
1153
    for (i=0; i<nfonts && !found; i++) {
-
 
1154
	char* fontFamily = CHAR(STRING_ELT(fontnames, i));
-
 
1155
	if (strcmp(family, fontFamily) == 0) {
-
 
1156
	    found = 1;
-
 
1157
	    result = CHAR(STRING_ELT(VECTOR_ELT(VECTOR_ELT(fontdb, i), 2), 0));
-
 
1158
	}
-
 
1159
    }
-
 
1160
    if (!found)
-
 
1161
	warning("Font encoding not found in PostScript font database");
-
 
1162
    else {
-
 
1163
	/*
-
 
1164
	 * Convert "default" to "WinAnsi.enc" on Windows
-
 
1165
	 * and "ISOLatin1.enc" elsewhere
-
 
1166
	 * 
-
 
1167
	 * Equivalent of following code in postscript.R;
-
 
1168
	 * 
-
 
1169
	 * old$encoding <- switch(.Platform$OS.type,
-
 
1170
         *                        "windows" = "WinAnsi.enc",
-
 
1171
         *                        "ISOLatin1.enc")
-
 
1172
	 */
-
 
1173
	if (!strcmp(result, "default")) {
-
 
1174
	    SEXP platform, platformNames, OStype;
-
 
1175
	    PROTECT(platform = findVar(install(".Platform"), R_GlobalEnv));
-
 
1176
	    PROTECT(platformNames = getAttrib(platform, R_NamesSymbol));
-
 
1177
	    if (strcmp(CHAR(STRING_ELT(platformNames, 0)), "OS.type"))
-
 
1178
		error(".Platform has changed and nobody told postscript");
-
 
1179
	    PROTECT(OStype = VECTOR_ELT(platform, 0));
-
 
1180
	    if (!strcmp(CHAR(STRING_ELT(OStype, 0)), "windows"))
-
 
1181
		result = WinAnsiEnc;
-
 
1182
	    else
-
 
1183
		result = ISOLatin1Enc;
-
 
1184
	    UNPROTECT(3);
-
 
1185
	}
-
 
1186
    }
-
 
1187
    UNPROTECT(4);
-
 
1188
    return result;
-
 
1189
}
-
 
1190
 
-
 
1191
/*
-
 
1192
 * Add a graphics engine font family/encoding to the list of loaded fonts ...
-
 
1193
 *
-
 
1194
 * ... and return the new font
-
 
1195
 */
-
 
1196
static type1fontfamily addLoadedFont(type1fontfamily font)
-
 
1197
{
-
 
1198
    type1fontlist newfont = makeFontList();
-
 
1199
    if (!newfont) {
-
 
1200
	freeFontFamily(font);
-
 
1201
	font = NULL;
-
 
1202
    } else {
-
 
1203
	type1fontlist fontlist = loadedFonts;
-
 
1204
	newfont->family = font;
-
 
1205
	if (!loadedFonts)
-
 
1206
	    loadedFonts = newfont;
-
 
1207
	else {
-
 
1208
	    while (fontlist->next)
-
 
1209
		fontlist = fontlist->next;
-
 
1210
	    fontlist->next = newfont;
-
 
1211
	}
-
 
1212
    }
-
 
1213
    return font;
-
 
1214
}
-
 
1215
 
-
 
1216
/*
-
 
1217
 * Add a font from a graphics engine font family name
-
 
1218
 */
-
 
1219
static type1fontfamily addFont(char *name, Rboolean isPDF)
-
 
1220
{
-
 
1221
    type1fontfamily fontfamily = makeFontFamily();
-
 
1222
    if (fontfamily) {
-
 
1223
	int i;
-
 
1224
	encodinginfo encoding;
-
 
1225
	char *encpath = getFontEncoding(name);
-
 
1226
	if (!encpath) {
-
 
1227
	    freeFontFamily(fontfamily);
-
 
1228
	    fontfamily = NULL;
-
 
1229
	} else {
-
 
1230
	    /*
-
 
1231
	     * Set the name of the font
-
 
1232
	     */
-
 
1233
	    safestrcpy(fontfamily->name, name, 50);
-
 
1234
	    /*
-
 
1235
	     * Find or add encoding
-
 
1236
	     */
-
 
1237
	    if (!(encoding = findEncoding(encpath)))
-
 
1238
		encoding = addEncoding(encpath, isPDF);
-
 
1239
	    if (!encoding) {
-
 
1240
		freeFontFamily(fontfamily);
-
 
1241
		fontfamily = NULL;
-
 
1242
	    } else {
-
 
1243
		/* 
-
 
1244
		 * Load font info
-
 
1245
		 */
-
 
1246
		fontfamily->encoding = encoding;
-
 
1247
		for(i = 0; i < 5 ; i++) {
-
 
1248
		    type1fontinfo font = makeType1Font();
-
 
1249
		    char *afmpath = fontMetricsFileName(name, i);
-
 
1250
		    if (!font) {
-
 
1251
			freeFontFamily(fontfamily);
-
 
1252
			fontfamily = NULL;
-
 
1253
			break;
-
 
1254
		    }
-
 
1255
		    if (!afmpath) {
-
 
1256
			freeFontFamily(fontfamily);
-
 
1257
			fontfamily = NULL;
-
 
1258
			break;
-
 
1259
		    } 
-
 
1260
		    fontfamily->fonts[i] = font;
-
 
1261
		    if (!PostScriptLoadFontMetrics(afmpath, 
-
 
1262
						   &(fontfamily->fonts[i]->metrics),
-
 
1263
						   fontfamily->fonts[i]->name,
-
 
1264
						   fontfamily->fonts[i]->charnames,
-
 
1265
						   /* 
-
 
1266
						    * Reencode all but
-
 
1267
						    * symbol face
-
 
1268
						    */
-
 
1269
						   encoding->encnames,
-
 
1270
						   (i < 4)?1:0)) {
-
 
1271
			warning("cannot read afm file %s", afmpath);
-
 
1272
			freeFontFamily(fontfamily);
-
 
1273
			fontfamily = NULL;
-
 
1274
			break;		
-
 
1275
		    }
-
 
1276
		}
-
 
1277
		/*
-
 
1278
		 * Add font
-
 
1279
		 */
-
 
1280
		if (fontfamily) 
-
 
1281
		    fontfamily = addLoadedFont(fontfamily);
-
 
1282
	    }
-
 
1283
	}
-
 
1284
    } else 
-
 
1285
	fontfamily = NULL;
-
 
1286
    return fontfamily;
-
 
1287
}
-
 
1288
 
-
 
1289
/*
-
 
1290
 * Add a default font family/encoding to the list of loaded fonts ...
-
 
1291
 *
-
 
1292
 * ... using a set of AFM paths ...
-
 
1293
 *
-
 
1294
 * ... and return the new font
-
 
1295
 */
-
 
1296
static type1fontfamily addDefaultFontFromAFMs(char *encpath, char **afmpaths,
-
 
1297
					      Rboolean isPDF)
-
 
1298
{
-
 
1299
    encodinginfo encoding;
-
 
1300
    type1fontfamily fontfamily = makeFontFamily();
-
 
1301
    if (fontfamily) {
-
 
1302
	int i;
-
 
1303
	if (!(encoding = findEncoding(encpath)))
-
 
1304
	    encoding = addEncoding(encpath, isPDF);
-
 
1305
	if (!encoding) {
-
 
1306
	    freeFontFamily(fontfamily);
-
 
1307
	    fontfamily = NULL;
-
 
1308
	} else {
-
 
1309
	    /*
-
 
1310
	     * This is the device default font, so set the
-
 
1311
	     * graphics engine font family name to ""
-
 
1312
	     */
-
 
1313
	    fontfamily->name[0] ='\0';
-
 
1314
	    /* 
-
 
1315
	     * Load font info
-
 
1316
	     */
-
 
1317
	    fontfamily->encoding = encoding;
-
 
1318
	    for(i = 0; i < 5 ; i++) {
-
 
1319
		type1fontinfo font = makeType1Font();
-
 
1320
		if (!font) {
-
 
1321
		    freeFontFamily(fontfamily);
-
 
1322
		    fontfamily = NULL;
-
 
1323
		    break;
-
 
1324
		}
-
 
1325
		fontfamily->fonts[i] = font;
-
 
1326
		if (!PostScriptLoadFontMetrics(afmpaths[i], 
-
 
1327
					       &(fontfamily->fonts[i]->metrics),
-
 
1328
					       fontfamily->fonts[i]->name,
-
 
1329
					       fontfamily->fonts[i]->charnames,
-
 
1330
					       /* 
-
 
1331
						* Reencode all but
-
 
1332
						* symbol face
-
 
1333
						*/
-
 
1334
					       encoding->encnames,
-
 
1335
					       (i < 4)?1:0)) {
-
 
1336
		    warning("cannot read afm file %s", afmpaths[i]);
-
 
1337
		    freeFontFamily(fontfamily);
-
 
1338
		    fontfamily = NULL;
-
 
1339
		    break;		
-
 
1340
		}
-
 
1341
	    }
-
 
1342
	    /*
-
 
1343
	     * Add font
-
 
1344
	     */
-
 
1345
	    if (fontfamily) 
-
 
1346
		fontfamily = addLoadedFont(fontfamily);
-
 
1347
	}
-
 
1348
    } else 
-
 
1349
	fontfamily = NULL;
-
 
1350
    return fontfamily;
-
 
1351
}
-
 
1352
 
-
 
1353
/*
-
 
1354
 * Add a default font family/encoding to the list of loaded fonts ...
-
 
1355
 *
-
 
1356
 * ... using an index into the internal list of Type 1 font families ...
-
 
1357
 *
-
 
1358
 * ... and return the new font
-
 
1359
 */
-
 
1360
static type1fontfamily addDefaultFontFromFamily(char *encpath, int family,
-
 
1361
				      Rboolean isPDF)
-
 
1362
{
-
 
1363
    encodinginfo encoding;
-
 
1364
    type1fontfamily fontfamily = makeFontFamily();
-
 
1365
    if (fontfamily) {
-
 
1366
	int i;
-
 
1367
	if (!(encoding = findEncoding(encpath)))
-
 
1368
	    encoding = addEncoding(encpath, isPDF);
-
 
1369
	if (!encoding) {
-
 
1370
	    freeFontFamily(fontfamily);
-
 
1371
	    fontfamily = NULL;
-
 
1372
	} else {
-
 
1373
	    /*
-
 
1374
	     * This is the device default font, so set the
-
 
1375
	     * graphics engine font family name to ""
-
 
1376
	     */
-
 
1377
	    fontfamily->name[0] ='\0';
-
 
1378
	    /* 
-
 
1379
	     * Load font info
-
 
1380
	     */
-
 
1381
	    fontfamily->encoding = encoding;
-
 
1382
	    for(i = 0; i < 5 ; i++) {
-
 
1383
		type1fontinfo font = makeType1Font();
-
 
1384
		if (!font) {
-
 
1385
		    freeFontFamily(fontfamily);
-
 
1386
		    fontfamily = NULL;
-
 
1387
		    break;
-
 
1388
		}
-
 
1389
		fontfamily->fonts[i] = font;
-
 
1390
		if (!PostScriptLoadFontMetrics(Family[family].afmfile[i],
-
 
1391
					       &(fontfamily->fonts[i]->metrics),
-
 
1392
					       fontfamily->fonts[i]->name,
-
 
1393
					       fontfamily->fonts[i]->charnames,
-
 
1394
					       /* 
-
 
1395
						* Reencode all but
-
 
1396
						* symbol face
-
 
1397
						*/
-
 
1398
					       encoding->encnames,
-
 
1399
					       (i < 4)?1:0)) {
-
 
1400
		    warning("cannot read afm file %s", 
-
 
1401
			    Family[family].afmfile[i]);
-
 
1402
		    freeFontFamily(fontfamily);
-
 
1403
		    fontfamily = NULL;
-
 
1404
		    break;		
-
 
1405
		}
-
 
1406
	    }
-
 
1407
	    /*
-
 
1408
	     * Add font
-
 
1409
	     */
-
 
1410
	    if (fontfamily) 
-
 
1411
		fontfamily = addLoadedFont(fontfamily);
-
 
1412
	}
-
 
1413
    } else 
-
 
1414
	fontfamily = NULL;
-
 
1415
    return fontfamily;
-
 
1416
}
-
 
1417
 
-
 
1418
/*
-
 
1419
 * Add a graphics engine font family/encoding to a list of device fonts ...
-
 
1420
 *
-
 
1421
 * ... and return the new font list
-
 
1422
 */
-
 
1423
static type1fontlist addDeviceFont(type1fontfamily font,
-
 
1424
				   type1fontlist devFonts,
-
 
1425
				   int *index)
-
 
1426
{
-
 
1427
    type1fontlist newfont = makeFontList();
-
 
1428
    *index = 0;
-
 
1429
    if (!newfont) {
-
 
1430
	devFonts = NULL;
-
 
1431
    } else {
-
 
1432
	type1fontlist fontlist = devFonts;
-
 
1433
	newfont->family = font;
-
 
1434
	*index = 1;
-
 
1435
	if (!devFonts) {
-
 
1436
	    devFonts = newfont;
-
 
1437
	} else {
-
 
1438
	    while (fontlist->next) {
-
 
1439
		fontlist = fontlist->next;
-
 
1440
		*index = *index + 1;
-
 
1441
	    }
-
 
1442
	    fontlist->next = newfont;
-
 
1443
	}
-
 
1444
    }
-
 
1445
    return devFonts;
-
 
1446
}
-
 
1447
 
-
 
1448
/*
-
 
1449
***********************************************************
-
 
1450
*/
-
 
1451
 
-
 
1452
/* Part 2.  Device Driver State. */
-
 
1453
 
-
 
1454
typedef struct {
-
 
1455
    char filename[PATH_MAX];
-
 
1456
    int open_type;
-
 
1457
 
-
 
1458
    char papername[64];	/* paper name */
-
 
1459
    int paperwidth;	/* paper width in big points (1/72 in) */
-
 
1460
    int paperheight;	/* paper height in big points */
-
 
1461
    Rboolean landscape;	/* landscape mode */
-
 
1462
    int pageno;		/* page number */
-
 
1463
 
-
 
1464
    int maxpointsize;
-
 
1465
 
-
 
1466
    double width;	/* plot width in inches */
-
 
1467
    double height;	/* plot height in inches */
-
 
1468
    double pagewidth;	/* page width in inches */
-
 
1469
    double pageheight;	/* page height in inches */
-
 
1470
    Rboolean pagecentre;/* centre image on page? */
-
 
1471
    Rboolean printit;	/* print page at close? */
-
 
1472
    char command[PATH_MAX];
-
 
1473
    char title[1024];
-
 
1474
 
-
 
1475
    FILE *psfp;		/* output file */
-
 
1476
 
-
 
1477
    Rboolean onefile;	/* EPSF header etc*/
-
 
1478
    Rboolean paperspecial;	/* suppress %%Orientation */
-
 
1479
 
-
 
1480
    /* This group of variables track the current device status.
-
 
1481
     * They should only be set by routines that emit PostScript code. */
-
 
1482
    struct {
-
 
1483
	double lwd;		 /* line width */
-
 
1484
	int lty;		 /* line type */
-
 
1485
	int font;
-
 
1486
	int fontstyle;	         /* font style, R, B, I, BI, S */
669
	/* use different ps fragment for CM fonts */
1487
	int fontsize;	         /* font size in points */
-
 
1488
	rcolor col;		 /* color */
-
 
1489
	rcolor fill;	         /* fill color */
-
 
1490
    } current;
-
 
1491
 
-
 
1492
    /*
-
 
1493
     * Fonts and encodings used on the device
-
 
1494
     */
-
 
1495
    type1fontlist fonts;
-
 
1496
    encodinglist encodings;
-
 
1497
}
-
 
1498
PostScriptDesc;
-
 
1499
 
-
 
1500
/*  Part 3.  Graphics Support Code.  */
-
 
1501
 
-
 
1502
static const char * const TypeFaceDef[] = { "R", "B", "I", "BI", "S" };
-
 
1503
 
-
 
1504
static void specialCaseCM(FILE *fp, type1fontfamily family)
-
 
1505
{
670
	fprintf(fp, "%% begin encoding\n");
1506
	fprintf(fp, "%% begin encoding\n");
671
	fprintf(fp, "/SymbolEncoding [\n");
1507
	fprintf(fp, "/SymbolEncoding [\n");
672
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
1508
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
673
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
1509
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
674
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
1510
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
Line 745... Line 1581...
745
	fprintf(fp, "  end\n");
1581
	fprintf(fp, "  end\n");
746
	fprintf(fp, "} def\n");
1582
	fprintf(fp, "} def\n");
747
	fprintf(fp, "%%%%IncludeResource: font CMR10\n");
1583
	fprintf(fp, "%%%%IncludeResource: font CMR10\n");
748
	fprintf(fp, "%%%%IncludeResource: font CMSY10\n");
1584
	fprintf(fp, "%%%%IncludeResource: font CMSY10\n");
749
	fprintf(fp, "[ /%s findfont /CMSY10 findfont ] %s mergefonts\n", 
1585
	fprintf(fp, "[ /%s findfont /CMSY10 findfont ] %s mergefonts\n", 
750
		familyname[0], encname);
1586
		family->fonts[0]->name, family->encoding->name);
751
	fprintf(fp, "/Font1 exch definefont pop\n");
1587
	fprintf(fp, "/Font1 exch definefont pop\n");
752
	fprintf(fp, "%%%%IncludeResource: font CMBX10\n");
1588
	fprintf(fp, "%%%%IncludeResource: font CMBX10\n");
753
	fprintf(fp, "%%%%IncludeResource: font CMBSY10\n");
1589
	fprintf(fp, "%%%%IncludeResource: font CMBSY10\n");
754
	fprintf(fp, "[ /%s findfont /CMBSY10 findfont ] %s mergefonts\n",
1590
	fprintf(fp, "[ /%s findfont /CMBSY10 findfont ] %s mergefonts\n",
755
		familyname[1], encname);
1591
		family->fonts[1]->name, family->encoding->name);
756
	fprintf(fp, "/Font2 exch definefont pop\n");
1592
	fprintf(fp, "/Font2 exch definefont pop\n");
757
	fprintf(fp, "%%%%IncludeResource: font CMSL10\n");
1593
	fprintf(fp, "%%%%IncludeResource: font CMSL10\n");
758
	fprintf(fp, "[ /%s findfont /CMSY10 findfont ] %s mergefonts\n",
1594
	fprintf(fp, "[ /%s findfont /CMSY10 findfont ] %s mergefonts\n",
759
		familyname[2], encname);
1595
		family->fonts[2]->name, family->encoding->name);
760
	fprintf(fp, "/Font3 exch definefont pop\n");
1596
	fprintf(fp, "/Font3 exch definefont pop\n");
761
	fprintf(fp, "%%%%IncludeResource: font CMBXSL10\n");
1597
	fprintf(fp, "%%%%IncludeResource: font CMBXSL10\n");
762
	fprintf(fp, "[ /%s findfont /CMBSY10 findfont ] %s mergefonts\n", 
1598
	fprintf(fp, "[ /%s findfont /CMBSY10 findfont ] %s mergefonts\n", 
763
		familyname[3], encname);
1599
		family->fonts[3]->name, family->encoding->name);
764
	fprintf(fp, "/Font4 exch definefont pop\n");
1600
	fprintf(fp, "/Font4 exch definefont pop\n");
765
	fprintf(fp, "%%%%IncludeResource: font CMMI10\n");
1601
	fprintf(fp, "%%%%IncludeResource: font CMMI10\n");
766
	fprintf(fp, "[ /CMR10 findfont /CMSY10 findfont /CMMI10 findfont ] SymbolEncoding mergefonts\n");
1602
	fprintf(fp, "[ /CMR10 findfont /CMSY10 findfont /CMMI10 findfont ] SymbolEncoding mergefonts\n");
767
	fprintf(fp, "/Font5 exch definefont pop\n");
1603
	fprintf(fp, "/Font5 exch definefont pop\n");
-
 
1604
}
-
 
1605
 
-
 
1606
static void PSEncodeFonts(FILE *fp, PostScriptDesc *pd)
-
 
1607
{
-
 
1608
    type1fontlist fonts = pd->fonts;
-
 
1609
    int familynum = 1;
-
 
1610
 
-
 
1611
    while (fonts) {
-
 
1612
	int dontcare;
-
 
1613
	/*
-
 
1614
	 * Has the encoding already been used on the device?
-
 
1615
	 */
-
 
1616
	encodinginfo encoding = 
-
 
1617
	    findDeviceEncoding(fonts->family->encoding->encpath, 
-
 
1618
			       pd->encodings, &dontcare);
-
 
1619
	if (!encoding) {
-
 
1620
	    /* 
-
 
1621
	     * The encoding should have been loaded when the font was loaded
-
 
1622
	     */
-
 
1623
	    encoding = findEncoding(fonts->family->encoding->encpath);
-
 
1624
	    if (!encoding) 
-
 
1625
		warning("Corrupt loaded encodings;  encoding not recorded");
768
    } else {
1626
	    else {
-
 
1627
		/*
-
 
1628
		 * Record encoding on device's list of encodings so
-
 
1629
		 * don't write same encoding more than once
-
 
1630
		 */
-
 
1631
		encodinglist enclist = addDeviceEncoding(encoding, 
-
 
1632
							 pd->encodings);
-
 
1633
		if (enclist)
-
 
1634
		    pd->encodings = enclist;
-
 
1635
		else
-
 
1636
		    warning("Failed to record device encoding");
-
 
1637
	    }
-
 
1638
	    /* 
-
 
1639
	     * Include encoding unless it is ISOLatin1Encoding, 
-
 
1640
	     * which is predefined 
-
 
1641
	     */
-
 
1642
	    if (strcmp(fonts->family->encoding->name, "ISOLatin1Encoding"))
-
 
1643
		fprintf(fp, "%% begin encoding\n%s def\n%% end encoding\n", 
-
 
1644
			fonts->family->encoding->enccode);
-
 
1645
	}
-
 
1646
	if(strcmp(fonts->family->fonts[4]->name, 
-
 
1647
		  "CMSY10 CMBSY10 CMMI10") == 0) {
-
 
1648
	    /* use different ps fragment for CM fonts */
-
 
1649
	    specialCaseCM(fp, fonts->family);
-
 
1650
	} else {
-
 
1651
	    int i;
769
  	for (i = 0; i < 4 ; i++) {
1652
	    for (i = 0; i < 4 ; i++) {
-
 
1653
		fprintf(fp, "%%%%IncludeResource: font %s\n", 
-
 
1654
			fonts->family->fonts[i]->name);
-
 
1655
		fprintf(fp, "/%s findfont\n", 
-
 
1656
			fonts->family->fonts[i]->name);
-
 
1657
		fprintf(fp, "dup length dict begin\n");
-
 
1658
		fprintf(fp, "  {1 index /FID ne {def} {pop pop} ifelse} forall\n");
-
 
1659
		fprintf(fp, "  /Encoding %s def\n", 
-
 
1660
			fonts->family->encoding->name);
-
 
1661
		fprintf(fp, "  currentdict\n");
-
 
1662
		fprintf(fp, "  end\n");
-
 
1663
		fprintf(fp, "/Font%d exch definefont pop\n", 
-
 
1664
			(familynum - 1)*5 + i + 1);
-
 
1665
	    }
770
	    fprintf(fp, "%%%%IncludeResource: font %s\n", familyname[i]);
1666
	    fprintf(fp, "%%%%IncludeResource: font %s\n",
-
 
1667
		    fonts->family->fonts[4]->name);
771
	    fprintf(fp, "/%s findfont\n", familyname[i]);
1668
	    fprintf(fp, "/%s findfont\n", 
-
 
1669
		    fonts->family->fonts[4]->name);
772
	    fprintf(fp, "dup length dict begin\n");
1670
	    fprintf(fp, "dup length dict begin\n");
773
	    fprintf(fp, "  {1 index /FID ne {def} {pop pop} ifelse} forall\n");
1671
	    fprintf(fp, "  {1 index /FID ne {def} {pop pop} ifelse} forall\n");
774
	    fprintf(fp, "  /Encoding %s def\n", encname);
-
 
775
	    fprintf(fp, "  currentdict\n");
1672
	    fprintf(fp, "  currentdict\n");
776
	    fprintf(fp, "  end\n");
1673
	    fprintf(fp, "  end\n");
777
	    fprintf(fp, "/Font%d exch definefont pop\n", i + 1);
1674
	    fprintf(fp, "/Font%d exch definefont pop\n",
-
 
1675
		    (familynum - 1)*5 + 5);
-
 
1676
	}
778
   	}
1677
    
779
	fprintf(fp, "%%%%IncludeResource: font %s\n", familyname[4]);
-
 
780
   	fprintf(fp, "/%s findfont\n", familyname[4]);
-
 
781
   	fprintf(fp, "dup length dict begin\n");
-
 
782
   	fprintf(fp, "  {1 index /FID ne {def} {pop pop} ifelse} forall\n");
-
 
783
   	fprintf(fp, "  currentdict\n");
1678
	familynum++;
784
   	fprintf(fp, "  end\n");
1679
	fonts = fonts->next;
785
   	fprintf(fp, "/Font5 exch definefont pop\n");
-
 
786
    }
1680
    }
787
}
1681
}
788
 
1682
 
789
/* The variables "paperwidth" and "paperheight" give the dimensions */
1683
/* The variables "paperwidth" and "paperheight" give the dimensions */
790
/* of the (unrotated) printer page in points whereas the graphics */
1684
/* of the (unrotated) printer page in points whereas the graphics */
791
/* region box is for the rotated page. */
1685
/* region box is for the rotated page. */
792
 
1686
 
793
static void PSFileHeader(FILE *fp, char* encname,
1687
static void PSFileHeader(FILE *fp, 
794
			 char *papername, double paperwidth,
1688
			 char *papername, double paperwidth,
795
			 double paperheight, Rboolean landscape,
1689
			 double paperheight, Rboolean landscape,
796
			 int EPSFheader, Rboolean paperspecial,
1690
			 int EPSFheader, Rboolean paperspecial,
797
			 double left, double bottom, double right, double top,
1691
			 double left, double bottom, double right, double top,
798
			 char *title)
1692
			 char *title,
-
 
1693
			 PostScriptDesc *pd)
799
{
1694
{
800
    int i;
1695
    int i;
801
    SEXP prolog;
1696
    SEXP prolog;
-
 
1697
    type1fontlist fonts = pd->fonts;
-
 
1698
    int firstfont = 1;
802
 
1699
 
803
    if(EPSFheader)
1700
    if(EPSFheader)
804
	fprintf(fp, "%%!PS-Adobe-3.0 EPSF-3.0\n");
1701
	fprintf(fp, "%%!PS-Adobe-3.0 EPSF-3.0\n");
805
    else
1702
    else
806
	fprintf(fp, "%%!PS-Adobe-3.0\n");
1703
	fprintf(fp, "%%!PS-Adobe-3.0\n");
-
 
1704
    /*
807
    fprintf(fp, "%%%%DocumentNeededResources: font %s\n", familyname[0]);
1705
     * DocumentNeededResources names all fonts
-
 
1706
     */
-
 
1707
    while (fonts) {
808
    for (i = 1; i < 5; i++)
1708
	for (i=0; i<5; i++) 
-
 
1709
	    if (firstfont) {
-
 
1710
		fprintf(fp, "%%%%DocumentNeededResources: font %s\n", 
-
 
1711
			fonts->family->fonts[0]->name);
-
 
1712
		firstfont = 0;
-
 
1713
	    } else
809
	fprintf(fp, "%%%%+ font %s\n", familyname[i]);
1714
	fprintf(fp, "%%%%+ font %s\n", fonts->family->fonts[i]->name);
-
 
1715
	fonts = fonts->next;
-
 
1716
    }
810
 
1717
 
811
    if(!EPSFheader)
1718
    if(!EPSFheader)
812
	fprintf(fp, "%%%%DocumentMedia: %s %.0f %.0f 0 () ()\n",
1719
	fprintf(fp, "%%%%DocumentMedia: %s %.0f %.0f 0 () ()\n",
813
		papername, paperwidth, paperheight);
1720
		papername, paperwidth, paperheight);
814
    fprintf(fp, "%%%%Title: %s\n", title);
1721
    fprintf(fp, "%%%%Title: %s\n", title);
Line 829... Line 1736...
829
    else
1736
    else
830
	fprintf(fp, "/bp  { gs gs } def\n");
1737
	fprintf(fp, "/bp  { gs gs } def\n");
831
    prolog = findVar(install(".ps.prolog"), R_GlobalEnv);
1738
    prolog = findVar(install(".ps.prolog"), R_GlobalEnv);
832
    if(prolog == R_UnboundValue) {
1739
    if(prolog == R_UnboundValue) {
833
	/* if no object is visible, look in the graphics namespace */
1740
	/* if no object is visible, look in the graphics namespace */
834
	SEXP graphicsNS = R_FindNamespace(ScalarString(mkChar("graphics")));
1741
	SEXP graphicsNS = R_FindNamespace(ScalarString(mkChar("grDevices")));
835
	prolog = findVar(install(".ps.prolog"), graphicsNS);
1742
	prolog = findVar(install(".ps.prolog"), graphicsNS);
-
 
1743
	/* under lazy loading this will be a promise on first use */
-
 
1744
	if(TYPEOF(prolog) == PROMSXP) {
-
 
1745
	    PROTECT(prolog);
-
 
1746
	    prolog = eval(prolog, graphicsNS);
-
 
1747
	    UNPROTECT(1);
-
 
1748
	}
836
    }
1749
    }
837
    if(!isString(prolog))
1750
    if(!isString(prolog))
838
	error("Object .ps.prolog is not a character vector");
1751
	error("Object .ps.prolog is not a character vector");
839
    fprintf(fp, "%% begin .ps.prolog\n");
1752
    fprintf(fp, "%% begin .ps.prolog\n");
840
    for (i = 0; i < length(prolog); i++)
1753
    for (i = 0; i < length(prolog); i++)
841
	fprintf(fp, "%s\n", CHAR(STRING_ELT(prolog, i)));
1754
	fprintf(fp, "%s\n", CHAR(STRING_ELT(prolog, i)));
842
    fprintf(fp, "%% end   .ps.prolog\n");
1755
    fprintf(fp, "%% end   .ps.prolog\n");
843
    PSEncodeFont(fp, encname);
1756
    PSEncodeFonts(fp, pd);
844
    fprintf(fp, "%%%%EndProlog\n");
1757
    fprintf(fp, "%%%%EndProlog\n");
845
}
1758
}
846
 
1759
 
847
static void PostScriptFileTrailer(FILE *fp, int pageno)
1760
static void PostScriptFileTrailer(FILE *fp, int pageno)
848
{
1761
{
Line 872... Line 1785...
872
static void PostScriptSetLineWidth(FILE *fp, double linewidth)
1785
static void PostScriptSetLineWidth(FILE *fp, double linewidth)
873
{
1786
{
874
    fprintf(fp, "%.2f setlinewidth\n", linewidth);
1787
    fprintf(fp, "%.2f setlinewidth\n", linewidth);
875
}
1788
}
876
 
1789
 
877
static void PostScriptSetFont(FILE *fp, int typeface, double size)
1790
static void PostScriptSetFont(FILE *fp, int fontnum, double size)
878
{
1791
{
879
    fprintf(fp, "/ps %.0f def %s %.0f s\n", size, TypeFaceDef[typeface], size);
1792
    fprintf(fp, "/ps %.0f def /Font%d findfont %.0f s\n", size, fontnum, size);
880
}
1793
}
881
 
1794
 
882
static void
1795
static void
883
PostScriptSetLineTexture(FILE *fp, char *dashlist, int nlty, double lwd)
1796
PostScriptSetLineTexture(FILE *fp, char *dashlist, int nlty, double lwd)
884
{
1797
{
Line 994... Line 1907...
994
 
1907
 
995
    fprintf(fp, " t\n");
1908
    fprintf(fp, " t\n");
996
}
1909
}
997
 
1910
 
998
 
1911
 
999
/* Part 3.  Device Driver State. */
-
 
1000
 
-
 
1001
typedef struct {
-
 
1002
    char filename[PATH_MAX];
-
 
1003
    int open_type;
-
 
1004
 
-
 
1005
    char papername[64];	/* paper name */
-
 
1006
    int paperwidth;	/* paper width in big points (1/72 in) */
-
 
1007
    int paperheight;	/* paper height in big points */
-
 
1008
    Rboolean landscape;	/* landscape mode */
-
 
1009
    int pageno;		/* page number */
-
 
1010
 
-
 
1011
    int fontfamily;	/* font family */
-
 
1012
    char encpath[PATH_MAX]; /* font encoding file */
-
 
1013
    char encname[100]; /* font encoding */
-
 
1014
    char **afmpaths;	/* for user-specified family */
-
 
1015
    int maxpointsize;
-
 
1016
 
-
 
1017
    double width;	/* plot width in inches */
-
 
1018
    double height;	/* plot height in inches */
-
 
1019
    double pagewidth;	/* page width in inches */
-
 
1020
    double pageheight;	/* page height in inches */
-
 
1021
    Rboolean pagecentre;/* centre image on page? */
-
 
1022
    Rboolean printit;	/* print page at close? */
-
 
1023
    char command[PATH_MAX];
-
 
1024
    char title[1024];
-
 
1025
 
-
 
1026
    FILE *psfp;		/* output file */
-
 
1027
 
-
 
1028
    Rboolean onefile;	/* EPSF header etc*/
-
 
1029
    Rboolean paperspecial;	/* suppress %%Orientation */
-
 
1030
 
-
 
1031
    /* This group of variables track the current device status.
-
 
1032
     * They should only be set by routines that emit PostScript code. */
-
 
1033
    struct {
-
 
1034
	double lwd;		 /* line width */
-
 
1035
	int lty;		 /* line type */
-
 
1036
	int fontstyle;	         /* font style, R, B, I, BI, S */
-
 
1037
	int fontsize;	         /* font size in points */
-
 
1038
	rcolor col;		 /* color */
-
 
1039
	rcolor fill;	         /* fill color */
-
 
1040
    } current;
-
 
1041
 
-
 
1042
    FontMetricInfo metrics[5];	/* font metrics */
-
 
1043
}
-
 
1044
PostScriptDesc;
-
 
1045
 
-
 
1046
 
-
 
1047
/* Device Driver Actions */
1912
/* Device Driver Actions */
1048
 
1913
 
1049
static void PS_Activate(NewDevDesc *dd);
1914
static void PS_Activate(NewDevDesc *dd);
1050
static void PS_Circle(double x, double y, double r,
1915
static void PS_Circle(double x, double y, double r,
1051
		      R_GE_gcontext *gc,
1916
		      R_GE_gcontext *gc,
Line 1129... Line 1994...
1129
static void SetFont(int, int, NewDevDesc*);
1994
static void SetFont(int, int, NewDevDesc*);
1130
static void SetLineStyle(int newlty, double newlwd, NewDevDesc *dd);
1995
static void SetLineStyle(int newlty, double newlwd, NewDevDesc *dd);
1131
static void Invalidate(NewDevDesc*);
1996
static void Invalidate(NewDevDesc*);
1132
static int  MatchFamily(char *name);
1997
static int  MatchFamily(char *name);
1133
 
1998
 
1134
 
-
 
1135
static Rboolean
1999
static Rboolean
1136
innerPSDeviceDriver(NewDevDesc *dd, char *file, char *paper, char *family,
2000
innerPSDeviceDriver(NewDevDesc *dd, char *file, char *paper, char *family,
1137
		    char **afmpaths, char *encoding,
2001
		    char **afmpaths, char *encoding,
1138
		    char *bg, char *fg,
2002
		    char *bg, char *fg,
1139
		    double width, double height,
2003
		    double width, double height,
1140
		    Rboolean horizontal, double ps,
2004
		    Rboolean horizontal, double ps,
1141
		    Rboolean onefile, Rboolean pagecentre,
2005
		    Rboolean onefile, Rboolean pagecentre,
1142
		    Rboolean printit, char *cmd, char *title)
2006
		    Rboolean printit, char *cmd, char *title,
-
 
2007
		    SEXP fonts)
1143
{
2008
{
1144
    /* If we need to bail out with some sort of "error"
2009
    /* If we need to bail out with some sort of "error"
1145
       then we must free(dd) */
2010
       then we must free(dd) */
1146
 
2011
 
1147
    double xoff, yoff, pointsize;
2012
    double xoff, yoff, pointsize;
1148
    rcolor setbg, setfg;
2013
    rcolor setbg, setfg;
-
 
2014
    type1fontfamily font;
-
 
2015
    int gotFont;
1149
 
2016
 
1150
    PostScriptDesc *pd;
2017
    PostScriptDesc *pd;
1151
 
2018
 
1152
    /* Check and extract the device parameters */
2019
    /* Check and extract the device parameters */
1153
 
2020
 
Line 1165... Line 2032...
1165
 
2032
 
1166
    /* initialise postscript device description */
2033
    /* initialise postscript device description */
1167
    strcpy(pd->filename, file);
2034
    strcpy(pd->filename, file);
1168
    strcpy(pd->papername, paper);
2035
    strcpy(pd->papername, paper);
1169
    strncpy(pd->title, title, 1024);
2036
    strncpy(pd->title, title, 1024);
1170
    pd->fontfamily = strcmp(family, "User") ? MatchFamily(family) : USERAFM;
-
 
-
 
2037
 
1171
    if(strlen(encoding) > PATH_MAX - 1) {
2038
    if(strlen(encoding) > PATH_MAX - 1) {
1172
	free(dd);
2039
	free(dd);
1173
	free(pd);
2040
	free(pd);
1174
	error("encoding path is too long");
2041
	error("encoding path is too long");
1175
    }
2042
    }
1176
    strcpy(pd->encpath, encoding);
-
 
1177
    pd->afmpaths = afmpaths;
-
 
1178
 
2043
 
-
 
2044
    pd->encodings = NULL;
-
 
2045
    pd->fonts = NULL;
-
 
2046
 
-
 
2047
    gotFont = 0;
-
 
2048
    /*
-
 
2049
     * If user specified afms then assume the font hasn't been loaded
-
 
2050
     * Could lead to redundant extra loading of a font, but not often(?)
-
 
2051
     */
-
 
2052
    if (!strcmp(family, "User")) {
-
 
2053
	font = addDefaultFontFromAFMs(encoding, afmpaths, 0);
-
 
2054
    } else { 
-
 
2055
	if (!(font = findDefaultLoadedFont(encoding, family, 0))) {
-
 
2056
	    font = addDefaultFontFromFamily(encoding, MatchFamily(family), 0);
-
 
2057
	}
-
 
2058
    }
-
 
2059
    if (font)
-
 
2060
	pd->fonts = addDeviceFont(font, pd->fonts, &gotFont);
-
 
2061
    if (!gotFont) {
-
 
2062
	free(dd);
-
 
2063
	free(pd);
-
 
2064
	error("Failed to initialise default PostScript font");
-
 
2065
    }
-
 
2066
		
-
 
2067
    /* 
-
 
2068
     * Load the font names sent in via the fonts arg
-
 
2069
     * NOTE that these are the font names specified at the 
-
 
2070
     * R-level, NOT the translated font names.  
-
 
2071
     */
-
 
2072
    if (!isNull(fonts)) {
-
 
2073
	int i, dontcare, gotFonts = 0, nfonts = LENGTH(fonts);
-
 
2074
	type1fontlist fontlist;
-
 
2075
	for (i=0; i<nfonts; i++) {
-
 
2076
	    int index;
-
 
2077
	    char *name = CHAR(STRING_ELT(fonts, i));
-
 
2078
	    if (findDeviceFont(name, pd->fonts, &index))
-
 
2079
		gotFonts++;
-
 
2080
	    else {
-
 
2081
		if (!(font = findLoadedFont(name)))
-
 
2082
		    font = addFont(name, 0);
-
 
2083
		if (font)
-
 
2084
		    if ((fontlist = addDeviceFont(font, pd->fonts, 
-
 
2085
						  &dontcare))) {
-
 
2086
			pd->fonts = fontlist;
-
 
2087
			gotFonts++;
-
 
2088
		    } 
-
 
2089
	    }
-
 
2090
	}
-
 
2091
	if (gotFonts < nfonts) {
-
 
2092
	    freeDeviceFontList(pd->fonts);
-
 
2093
	    pd->fonts = NULL;
-
 
2094
	    free(dd);
-
 
2095
	    free(pd);
-
 
2096
	    error("Failed to initialise additional PostScript fonts");
-
 
2097
	}
-
 
2098
    }
-
 
2099
					  
1179
    setbg = str2col(bg);
2100
    setbg = str2col(bg);
1180
    setfg = str2col(fg);
2101
    setfg = str2col(fg);
1181
 
2102
 
1182
    pd->width = width;
2103
    pd->width = width;
1183
    pd->height = height;
2104
    pd->height = height;
1184
    pd->landscape = horizontal;
2105
    pd->landscape = horizontal;
1185
    pointsize = floor(ps);
2106
    pointsize = floor(ps);
1186
    if(setbg == NA_INTEGER && setfg == NA_INTEGER) {
2107
    if(setbg == NA_INTEGER && setfg == NA_INTEGER) {
-
 
2108
	freeDeviceFontList(pd->fonts);
-
 
2109
	pd->fonts = NULL;
1187
	free(dd);
2110
	free(dd);
1188
	free(pd);
2111
	free(pd);
1189
	error("invalid foreground/background color (postscript)");
2112
	error("invalid foreground/background color (postscript)");
1190
    }
2113
    }
1191
    pd->printit = printit;
2114
    pd->printit = printit;
1192
    if(strlen(cmd) > PATH_MAX - 1) {
2115
    if(strlen(cmd) > PATH_MAX - 1) {
-
 
2116
	freeDeviceFontList(pd->fonts);
-
 
2117
	pd->fonts = NULL;
1193
	free(dd);
2118
	free(dd);
1194
	free(pd);
2119
	free(pd);
1195
	error("`command' is too long");
2120
	error("`command' is too long");
1196
    }
2121
    }
1197
    strcpy(pd->command, cmd);
2122
    strcpy(pd->command, cmd);
Line 1239... Line 2164...
1239
	    pd->pageheight = height;
2164
	    pd->pageheight = height;
1240
	}
2165
	}
1241
	pd->paperspecial = TRUE;
2166
	pd->paperspecial = TRUE;
1242
    }
2167
    }
1243
    else {
2168
    else {
-
 
2169
	freeDeviceFontList(pd->fonts);
-
 
2170
	pd->fonts = NULL;
1244
	free(dd);
2171
	free(dd);
1245
	free(pd);
2172
	free(pd);
1246
	error("invalid page type `%s' (postscript)", pd->papername);
2173
	error("invalid page type `%s' (postscript)", pd->papername);
1247
    }
2174
    }
1248
    pd->pagecentre = pagecentre;
2175
    pd->pagecentre = pagecentre;
Line 1324... Line 2251...
1324
 
2251
 
1325
    /*	Start the driver */
2252
    /*	Start the driver */
1326
 
2253
 
1327
    pd->pageno = 0;
2254
    pd->pageno = 0;
1328
    if(!PS_Open(dd, pd)) {
2255
    if(!PS_Open(dd, pd)) {
-
 
2256
	freeDeviceFontList(pd->fonts);
-
 
2257
	freeDeviceEncList(pd->encodings);
-
 
2258
	pd->fonts = NULL;
-
 
2259
	pd->encodings = NULL;
-
 
2260
	free(dd);
1329
	free(pd);
2261
	free(pd);
1330
	return FALSE;
2262
	return FALSE;
1331
    }
2263
    }
1332
 
2264
 
1333
    dd->newDevStruct = 1;
2265
    dd->newDevStruct = 1;
Line 1365... Line 2297...
1365
	       char **afmpaths, char *encoding,
2297
	       char **afmpaths, char *encoding,
1366
	       char *bg, char *fg,
2298
	       char *bg, char *fg,
1367
	       double width, double height,
2299
	       double width, double height,
1368
	       Rboolean horizontal, double ps,
2300
	       Rboolean horizontal, double ps,
1369
	       Rboolean onefile, Rboolean pagecentre,
2301
	       Rboolean onefile, Rboolean pagecentre,
1370
	       Rboolean printit, char *cmd, char *title)
2302
	       Rboolean printit, char *cmd, char *title,
-
 
2303
	       SEXP fonts)
1371
{
2304
{
1372
    return innerPSDeviceDriver((NewDevDesc*) dd, file, paper, family,
2305
    return innerPSDeviceDriver((NewDevDesc*) dd, file, paper, family,
1373
			       afmpaths, encoding, bg, fg, width, height,
2306
			       afmpaths, encoding, bg, fg, width, height,
1374
			       horizontal, ps, onefile, pagecentre,
2307
			       horizontal, ps, onefile, pagecentre,
1375
			       printit, cmd, title);
2308
			       printit, cmd, title, fonts);
1376
}
2309
}
1377
 
2310
 
1378
static int MatchFamily(char *name)
2311
static int MatchFamily(char *name)
1379
{
2312
{
1380
    int i;
2313
    int i;
Line 1428... Line 2361...
1428
	}
2361
	}
1429
	PostScriptSetLineTexture(pd->psfp, dashlist, i, newlwd * 0.75);
2362
	PostScriptSetLineTexture(pd->psfp, dashlist, i, newlwd * 0.75);
1430
    }
2363
    }
1431
}
2364
}
1432
 
2365
 
1433
static void SetFont(int style, int size, NewDevDesc *dd)
2366
static void SetFont(int font, int size, NewDevDesc *dd)
1434
{
2367
{
1435
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
2368
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1436
    if(style < 1 || style > 5) {
-
 
1437
	warning("attempt to use invalid font %d replaced by font 1", style);
-
 
1438
	style = 1;
-
 
1439
    }
-
 
1440
    if(size < 1 || size > pd->maxpointsize)
2369
    if(size < 1 || size > pd->maxpointsize)
1441
	size = 10;
2370
	size = 10;
1442
    if(size != pd->current.fontsize || style != pd->current.fontstyle) {
2371
    if (size != pd->current.fontsize || font != pd->current.font) {
1443
	PostScriptSetFont(pd->psfp, style-1, size);
2372
	PostScriptSetFont(pd->psfp, font, size);
1444
	pd->current.fontsize = size;
2373
	pd->current.fontsize = size;
1445
	pd->current.fontstyle = style;
2374
	pd->current.font = font;
1446
    }
2375
    }
1447
}
2376
}
1448
 
2377
 
1449
#ifdef Win32
2378
#ifdef Win32
1450
/* exists, but does not work on GUI processes */
2379
/* exists, but does not work on GUI processes */
Line 1452... Line 2381...
1452
#endif
2381
#endif
1453
 
2382
 
1454
static Rboolean PS_Open(NewDevDesc *dd, PostScriptDesc *pd)
2383
static Rboolean PS_Open(NewDevDesc *dd, PostScriptDesc *pd)
1455
{
2384
{
1456
    char buf[512];
2385
    char buf[512];
1457
    int i;
-
 
1458
 
-
 
1459
    if (!LoadEncoding(pd->encpath, pd->encname, FALSE)) {
-
 
1460
	warning("problem loading encoding file");
-
 
1461
	return FALSE;
-
 
1462
    }
-
 
1463
    for(i = 0; i < 5 ; i++) {
-
 
1464
        char const *p;
-
 
1465
	if(pd->fontfamily == USERAFM) p = pd->afmpaths[i];
-
 
1466
	else p = Family[pd->fontfamily].afmfile[i];
-
 
1467
	if(!PostScriptLoadFontMetrics(p, &(pd->metrics[i]),
-
 
1468
				      familyname[i], (i < 4)?1:0)) {
-
 
1469
	    warning("cannot read afm file %s", p);
-
 
1470
	    return FALSE;
-
 
1471
	}
-
 
1472
    }
-
 
1473
 
2386
 
1474
    if (strlen(pd->filename) == 0) {
2387
    if (strlen(pd->filename) == 0) {
1475
#ifndef HAVE_POPEN
2388
#ifndef HAVE_POPEN
1476
	warning("printing via file = \"\" is not implemented in this version");
2389
	warning("printing via file = \"\" is not implemented in this version");
1477
	return FALSE;
2390
	return FALSE;
Line 1508... Line 2421...
1508
	return FALSE;
2421
	return FALSE;
1509
    }
2422
    }
1510
 
2423
 
1511
    if(pd->landscape)
2424
    if(pd->landscape)
1512
	PSFileHeader(pd->psfp,
2425
	PSFileHeader(pd->psfp,
1513
		     pd->encname,
-
 
1514
		     pd->papername,
2426
		     pd->papername,
1515
		     pd->paperwidth,
2427
		     pd->paperwidth,
1516
		     pd->paperheight,
2428
		     pd->paperheight,
1517
		     pd->landscape,
2429
		     pd->landscape,
1518
		     !(pd->onefile),
2430
		     !(pd->onefile),
1519
		     pd->paperspecial,
2431
		     pd->paperspecial,
1520
		     dd->bottom,
2432
		     dd->bottom,
1521
		     dd->left,
2433
		     dd->left,
1522
		     dd->top,
2434
		     dd->top,
1523
		     dd->right,
2435
		     dd->right,
1524
		     pd->title);
2436
		     pd->title,
-
 
2437
		     pd);
1525
    else
2438
    else
1526
	PSFileHeader(pd->psfp,
2439
	PSFileHeader(pd->psfp,
1527
		     pd->encname,
-
 
1528
		     pd->papername,
2440
		     pd->papername,
1529
		     pd->paperwidth,
2441
		     pd->paperwidth,
1530
		     pd->paperheight,
2442
		     pd->paperheight,
1531
		     pd->landscape,
2443
		     pd->landscape,
1532
		     !(pd->onefile),
2444
		     !(pd->onefile),
1533
		     pd->paperspecial,
2445
		     pd->paperspecial,
1534
		     dd->left,
2446
		     dd->left,
1535
		     dd->bottom,
2447
		     dd->bottom,
1536
		     dd->right,
2448
		     dd->right,
1537
		     dd->top,
2449
		     dd->top,
1538
		     pd->title);
2450
		     pd->title,
-
 
2451
		     pd);
1539
 
2452
 
1540
    return TRUE;
2453
    return TRUE;
1541
}
2454
}
1542
 
2455
 
1543
/* The driver keeps track of the current values of colors, fonts and
2456
/* The driver keeps track of the current values of colors, fonts and
Line 1549... Line 2462...
1549
 
2462
 
1550
static void Invalidate(NewDevDesc *dd)
2463
static void Invalidate(NewDevDesc *dd)
1551
{
2464
{
1552
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
2465
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1553
 
2466
 
-
 
2467
    pd->current.font = -1;
1554
    pd->current.fontsize = -1;
2468
    pd->current.fontsize = -1;
1555
    pd->current.fontstyle = -1;
2469
    pd->current.fontstyle = -1;
1556
    pd->current.lwd = -1;
2470
    pd->current.lwd = -1;
1557
    pd->current.lty = -1;
2471
    pd->current.lty = -1;
1558
    pd->current.col = INVALID_COL;
2472
    pd->current.col = INVALID_COL;
Line 1640... Line 2554...
1640
static void PS_Close(NewDevDesc *dd)
2554
static void PS_Close(NewDevDesc *dd)
1641
{
2555
{
1642
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
2556
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1643
 
2557
 
1644
    PostScriptClose(dd);
2558
    PostScriptClose(dd);
-
 
2559
    freeDeviceFontList(pd->fonts);
-
 
2560
    freeDeviceEncList(pd->encodings);
-
 
2561
    pd->fonts = NULL;
-
 
2562
    pd->encodings = NULL;
1645
    free(pd);
2563
    free(pd);
1646
}
2564
}
1647
 
2565
 
1648
static void PS_Activate(NewDevDesc *dd) {}
2566
static void PS_Activate(NewDevDesc *dd) {}
1649
static void PS_Deactivate(NewDevDesc *dd) {}
2567
static void PS_Deactivate(NewDevDesc *dd) {}
1650
 
2568
 
-
 
2569
static FontMetricInfo *metricInfo(char *family, int face, 
-
 
2570
				  PostScriptDesc *pd) {
-
 
2571
    FontMetricInfo *result = NULL;
-
 
2572
    int fontIndex;
-
 
2573
    type1fontfamily fontfamily = findDeviceFont(family, pd->fonts, &fontIndex);
-
 
2574
    if (fontfamily) {
-
 
2575
	result = &(fontfamily->fonts[face-1]->metrics);
-
 
2576
    } else {
-
 
2577
	error("family %s not included in PostScript device", family);
-
 
2578
    }
-
 
2579
    return result;
-
 
2580
}
-
 
2581
 
1651
static double PS_StrWidth(char *str,
2582
static double PS_StrWidth(char *str,
1652
			  R_GE_gcontext *gc,
2583
			  R_GE_gcontext *gc,
1653
			  NewDevDesc *dd)
2584
			  NewDevDesc *dd)
1654
{
2585
{
1655
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
2586
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1656
    int face = gc->fontface;
2587
    int face = gc->fontface;
1657
 
2588
 
1658
    if(face < 1 || face > 5) face = 1;
2589
    if(face < 1 || face > 5) face = 1;
1659
    return floor(gc->cex * gc->ps + 0.5) *
2590
    return floor(gc->cex * gc->ps + 0.5) *
1660
	PostScriptStringWidth((unsigned char *)str,
2591
	PostScriptStringWidth((unsigned char *)str,
1661
			      &(pd->metrics[face-1]));
2592
			      metricInfo(gc->fontfamily, face, pd));
1662
}
2593
}
1663
 
2594
 
1664
static void PS_MetricInfo(int c, 
2595
static void PS_MetricInfo(int c, 
1665
			  R_GE_gcontext *gc,
2596
			  R_GE_gcontext *gc,
1666
			  double* ascent, double* descent,
2597
			  double* ascent, double* descent,
Line 1670... Line 2601...
1670
    int face = gc->fontface;
2601
    int face = gc->fontface;
1671
 
2602
 
1672
    if(face < 1 || face > 5) face = 1;
2603
    if(face < 1 || face > 5) face = 1;
1673
 
2604
 
1674
    PostScriptMetricInfo(c, ascent, descent, width,
2605
    PostScriptMetricInfo(c, ascent, descent, width,
1675
			 &(pd->metrics[face-1]));
2606
			 metricInfo(gc->fontfamily, face, pd));
1676
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
2607
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
1677
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
2608
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
1678
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
2609
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
1679
}
2610
}
1680
 
2611
 
Line 1809... Line 2740...
1809
	}
2740
	}
1810
	fprintf(pd->psfp, "o\n");
2741
	fprintf(pd->psfp, "o\n");
1811
    }
2742
    }
1812
}
2743
}
1813
 
2744
 
-
 
2745
static int translateFont(char* family, int style, PostScriptDesc *pd) 
-
 
2746
{
-
 
2747
    int result = style;
-
 
2748
    type1fontfamily fontfamily;
-
 
2749
    int fontIndex;
-
 
2750
    if(style < 1 || style > 5) {
-
 
2751
	warning("attempt to use invalid font %d replaced by font 1", style);
-
 
2752
	style = 1;
-
 
2753
    }
-
 
2754
    fontfamily = findDeviceFont(family, pd->fonts, &fontIndex);
-
 
2755
    if (fontfamily) {
-
 
2756
	result = (fontIndex - 1)*5 + style;
-
 
2757
    } else {
-
 
2758
	warning("family %s not included in PostScript device", family);
-
 
2759
    }
-
 
2760
    return result;
-
 
2761
}
1814
 
2762
 
1815
static void PS_Text(double x, double y, char *str,
2763
static void PS_Text(double x, double y, char *str,
1816
		    double rot, double hadj,
2764
		    double rot, double hadj,
1817
		    R_GE_gcontext *gc,
2765
		    R_GE_gcontext *gc,
1818
		    NewDevDesc *dd)
2766
		    NewDevDesc *dd)
1819
{
2767
{
1820
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
2768
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1821
 
2769
 
-
 
2770
    SetFont(translateFont(gc->fontfamily, gc->fontface, pd), 
1822
    SetFont(gc->fontface, (int)floor(gc->cex * gc->ps + 0.5), dd);
2771
	    (int)floor(gc->cex * gc->ps + 0.5),dd);
1823
    if(R_ALPHA(gc->col) == 0) {
2772
    if(R_ALPHA(gc->col) == 0) {
1824
	SetColor(gc->col, dd);
2773
	SetColor(gc->col, dd);
1825
	PostScriptText(pd->psfp, x, y, str, hadj, 0.0, rot);
2774
	PostScriptText(pd->psfp, x, y, str, hadj, 0.0, rot);
1826
    }
2775
    }
1827
}
2776
}
Line 1856... Line 2805...
1856
    int paperwidth;	 /* paper width in big points (1/72 in) */
2805
    int paperwidth;	 /* paper width in big points (1/72 in) */
1857
    int paperheight;	 /* paper height in big points */
2806
    int paperheight;	 /* paper height in big points */
1858
    Rboolean landscape;	 /* landscape mode */
2807
    Rboolean landscape;	 /* landscape mode */
1859
    int pageno;		 /* page number */
2808
    int pageno;		 /* page number */
1860
 
2809
 
1861
    int fontfamily;	 /* font family */
-
 
1862
    int fontnum;	 /* font number in XFig */
2810
    int fontnum;	 /* font number in XFig */
1863
    int fontstyle;	 /* font style, R, B, I, BI, S */
-
 
1864
    int fontsize;	 /* font size in points */
-
 
1865
    int maxpointsize;
2811
    int maxpointsize;
1866
 
2812
 
1867
    double width;	 /* plot width in inches */
2813
    double width;	 /* plot width in inches */
1868
    double height;	 /* plot height in inches */
2814
    double height;	 /* plot height in inches */
1869
    double pagewidth;	 /* page width in inches */
2815
    double pagewidth;	 /* page width in inches */
Line 1883... Line 2829...
1883
    char tmpname[PATH_MAX];
2829
    char tmpname[PATH_MAX];
1884
 
2830
 
1885
    Rboolean onefile;
2831
    Rboolean onefile;
1886
    int ymax;            /* used to invert coord system */
2832
    int ymax;            /* used to invert coord system */
1887
 
2833
 
-
 
2834
    /*
1888
    FontMetricInfo metrics[5];	/* font metrics */
2835
     * Fonts and encodings used on the device
1889
 
2836
     *
-
 
2837
     * ASSUME ONLY ONE (DEFAULT) FOR NOW
-
 
2838
     */
-
 
2839
    type1fontlist fonts;
-
 
2840
    encodinglist encodings;
1890
} XFigDesc;
2841
} XFigDesc;
1891
 
2842
 
1892
static void
2843
static void
1893
XF_FileHeader(FILE *fp, char *papername, Rboolean landscape, Rboolean onefile)
2844
XF_FileHeader(FILE *fp, char *papername, Rboolean landscape, Rboolean onefile)
1894
{
2845
{
Line 2035... Line 2986...
2035
		      Rboolean onefile, Rboolean pagecentre)
2986
		      Rboolean onefile, Rboolean pagecentre)
2036
{
2987
{
2037
    /* If we need to bail out with some sort of "error" */
2988
    /* If we need to bail out with some sort of "error" */
2038
    /* then we must free(dd) */
2989
    /* then we must free(dd) */
2039
 
2990
 
-
 
2991
    int gotFont;
2040
    double xoff, yoff, pointsize;
2992
    double xoff, yoff, pointsize;
2041
    XFigDesc *pd;
2993
    XFigDesc *pd;
-
 
2994
    type1fontfamily font;
2042
 
2995
 
2043
    /* Check and extract the device parameters */
2996
    /* Check and extract the device parameters */
2044
 
2997
 
2045
    if(strlen(file) > PATH_MAX - 1) {
2998
    if(strlen(file) > PATH_MAX - 1) {
2046
	free(dd);
2999
	free(dd);
Line 2055... Line 3008...
2055
    /* free(pd) */
3008
    /* free(pd) */
2056
 
3009
 
2057
    /* initialize xfig device description */
3010
    /* initialize xfig device description */
2058
    strcpy(pd->filename, file);
3011
    strcpy(pd->filename, file);
2059
    strcpy(pd->papername, paper);
3012
    strcpy(pd->papername, paper);
2060
    pd->fontfamily = MatchFamily(family);
-
 
2061
    pd->fontnum = XFig_basenums[pd->fontfamily];
3013
    pd->fontnum = XFig_basenums[MatchFamily(family)];
2062
    pd->bg = str2col(bg);
3014
    pd->bg = str2col(bg);
2063
    pd->col = str2col(fg);
3015
    pd->col = str2col(fg);
2064
    pd->fill = NA_INTEGER;
3016
    pd->fill = NA_INTEGER;
2065
    pd->width = width;
3017
    pd->width = width;
2066
    pd->height = height;
3018
    pd->height = height;
Line 2070... Line 3022...
2070
	free(dd);
3022
	free(dd);
2071
	free(pd);
3023
	free(pd);
2072
	error("invalid foreground/background color (xfig)");
3024
	error("invalid foreground/background color (xfig)");
2073
    }
3025
    }
2074
 
3026
 
-
 
3027
    pd->encodings = NULL;
-
 
3028
    pd->fonts = NULL;
2075
 
3029
 
-
 
3030
    gotFont = 0;
-
 
3031
    if (!(font = findDefaultLoadedFont("ISOLatin1.enc", family, 0))) {
-
 
3032
	font = addDefaultFontFromFamily("ISOLatin1.enc", 
-
 
3033
					MatchFamily(family), 0);
-
 
3034
    }
-
 
3035
    if (font)
-
 
3036
	pd->fonts = addDeviceFont(font, pd->fonts, &gotFont);
-
 
3037
    if (!gotFont) {
-
 
3038
	free(dd);
-
 
3039
	free(pd);
-
 
3040
	error("Failed to initialise default PostScript font");
-
 
3041
    }
-
 
3042
		
2076
    /* Deal with paper and plot size and orientation */
3043
    /* Deal with paper and plot size and orientation */
2077
 
3044
 
2078
    if(!strcmp(pd->papername, "Default") ||
3045
    if(!strcmp(pd->papername, "Default") ||
2079
       !strcmp(pd->papername, "default")) {
3046
       !strcmp(pd->papername, "default")) {
2080
	SEXP s = STRING_ELT(GetOption(install("papersize"), R_NilValue), 0);
3047
	SEXP s = STRING_ELT(GetOption(install("papersize"), R_NilValue), 0);
Line 2099... Line 3066...
2099
	strcpy(pd->papername, "Legal");
3066
	strcpy(pd->papername, "Legal");
2100
	pd->pagewidth  =  8.5;
3067
	pd->pagewidth  =  8.5;
2101
	pd->pageheight = 14.0;
3068
	pd->pageheight = 14.0;
2102
    }
3069
    }
2103
    else {
3070
    else {
-
 
3071
	freeDeviceFontList(pd->fonts);
-
 
3072
	freeDeviceEncList(pd->encodings);
-
 
3073
	pd->fonts = NULL;
-
 
3074
	pd->encodings = NULL;
2104
	free(dd);
3075
	free(dd);
2105
	free(pd);
3076
	free(pd);
2106
	error("invalid page type `%s' (xfig)", pd->papername);
3077
	error("invalid page type `%s' (xfig)", pd->papername);
2107
    }
3078
    }
2108
    pd->pagecentre = pagecentre;
3079
    pd->pagecentre = pagecentre;
Line 2188... Line 3159...
2188
    pd->nXFigColors = 32;
3159
    pd->nXFigColors = 32;
2189
 
3160
 
2190
    /*	Start the driver */
3161
    /*	Start the driver */
2191
 
3162
 
2192
    if(!XFig_Open(dd, pd)) {
3163
    if(!XFig_Open(dd, pd)) {
-
 
3164
	freeDeviceFontList(pd->fonts);
-
 
3165
	freeDeviceEncList(pd->encodings);
-
 
3166
	pd->fonts = NULL;
-
 
3167
	pd->encodings = NULL;
-
 
3168
	free(dd);
2193
	free(pd);
3169
	free(pd);
2194
	return 0;
3170
	return 0;
2195
    }
3171
    }
2196
 
3172
 
2197
    dd->newDevStruct = 1;
3173
    dd->newDevStruct = 1;
Line 2232... Line 3208...
2232
				 ps, onefile, pagecentre);
3208
				 ps, onefile, pagecentre);
2233
}
3209
}
2234
 
3210
 
2235
static Rboolean XFig_Open(NewDevDesc *dd, XFigDesc *pd)
3211
static Rboolean XFig_Open(NewDevDesc *dd, XFigDesc *pd)
2236
{
3212
{
2237
    char buf[512], name[50];
3213
    char buf[512], *tmp;
2238
    int i;
-
 
2239
 
-
 
2240
    if (!LoadEncoding("ISOLatin1.enc", buf, FALSE))
-
 
2241
	error("problem loading encoding file");
-
 
2242
    for(i = 0; i < 4 ; i++) {
-
 
2243
	if(!PostScriptLoadFontMetrics(Family[pd->fontfamily].afmfile[i],
-
 
2244
				      &(pd->metrics[i]), name, 1)) {
-
 
2245
	    warning("cannot read afm file %s",
-
 
2246
		    Family[pd->fontfamily].afmfile[i]);
-
 
2247
	    return FALSE;
-
 
2248
	}
-
 
2249
    }
-
 
2250
    if(!PostScriptLoadFontMetrics("sy______.afm",
-
 
2251
				  &(pd->metrics[4]), name, 0)) {
-
 
2252
	warning("cannot read afm file sy______.afm");
-
 
2253
	return FALSE;
-
 
2254
    }
-
 
2255
 
3214
 
2256
    if (strlen(pd->filename) == 0) {
3215
    if (strlen(pd->filename) == 0) {
2257
	error("empty file name");
3216
	error("empty file name");
2258
	return FALSE;
3217
	return FALSE;
2259
    } else {
3218
    } else {
2260
	snprintf(buf, 512, pd->filename, pd->pageno + 1); /* page 1 to start */
3219
	snprintf(buf, 512, pd->filename, pd->pageno + 1); /* page 1 to start */
2261
	pd->psfp = R_fopen(R_ExpandFileName(buf), "w");
3220
	pd->psfp = R_fopen(R_ExpandFileName(buf), "w");
2262
    }
3221
    }
2263
    if (!pd->psfp) return FALSE;
3222
    if (!pd->psfp) return FALSE;
2264
    /* assume tmpname is less than PATH_MAX */
3223
    /* assume tmpname is less than PATH_MAX */
2265
    strcpy(pd->tmpname, R_tmpnam("Rxfig", R_TempDir));
3224
    tmp = R_tmpnam("Rxfig", R_TempDir);
-
 
3225
    strcpy(pd->tmpname, tmp);
-
 
3226
    free(tmp);
2266
    pd->tmpfp = R_fopen(pd->tmpname, "w");
3227
    pd->tmpfp = R_fopen(pd->tmpname, "w");
2267
    if (!pd->tmpfp) {
3228
    if (!pd->tmpfp) {
2268
	fclose(pd->psfp);
3229
	fclose(pd->psfp);
2269
	return FALSE;
3230
	return FALSE;
2270
    }
3231
    }
2271
    XF_FileHeader(pd->psfp, pd->papername, pd->landscape, pd->onefile);
3232
    XF_FileHeader(pd->psfp, pd->papername, pd->landscape, pd->onefile);
2272
    pd->fontstyle = 1;
-
 
2273
    pd->fontsize = 10;
-
 
2274
    pd->pageno = 0;
3233
    pd->pageno = 0;
2275
    return TRUE;
3234
    return TRUE;
2276
}
3235
}
2277
 
3236
 
2278
 
3237
 
Line 2514... Line 3473...
2514
 
3473
 
2515
    if(style < 1 || style > 5) {
3474
    if(style < 1 || style > 5) {
2516
	warning("attempt to use invalid font %d replaced by font 1", style);
3475
	warning("attempt to use invalid font %d replaced by font 1", style);
2517
	style = 1;
3476
	style = 1;
2518
    }
3477
    }
2519
    pd->fontsize = size;
-
 
2520
    pd->fontstyle = style;
-
 
2521
    if(style == 5) fontnum = 32;
3478
    if(style == 5) fontnum = 32;
2522
    else fontnum = pd->fontnum + styles[style-1];
3479
    else fontnum = pd->fontnum + styles[style-1];
2523
 
3480
 
2524
    XFconvert(&x, &y, pd);
3481
    XFconvert(&x, &y, pd);
2525
    if(R_ALPHA(gc->col) == 0) {
3482
    if(R_ALPHA(gc->col) == 0) {
Line 2566... Line 3523...
2566
 
3523
 
2567
    if(face < 1 || face > 5) face = 1;
3524
    if(face < 1 || face > 5) face = 1;
2568
 
3525
 
2569
    return floor(gc->cex * gc->ps + 0.5) *
3526
    return floor(gc->cex * gc->ps + 0.5) *
2570
	PostScriptStringWidth((unsigned char *)str,
3527
	PostScriptStringWidth((unsigned char *)str,
2571
			      &(pd->metrics[face-1]));
3528
			      &(pd->fonts->family->fonts[face-1]->metrics));
2572
}
3529
}
2573
 
3530
 
2574
static void XFig_MetricInfo(int c, 
3531
static void XFig_MetricInfo(int c, 
2575
			    R_GE_gcontext *gc,
3532
			    R_GE_gcontext *gc,
2576
			    double* ascent, double* descent,
3533
			    double* ascent, double* descent,
Line 2580... Line 3537...
2580
    int face = gc->fontface;
3537
    int face = gc->fontface;
2581
 
3538
 
2582
    if(face < 1 || face > 5) face = 1;
3539
    if(face < 1 || face > 5) face = 1;
2583
 
3540
 
2584
    PostScriptMetricInfo(c, ascent, descent, width,
3541
    PostScriptMetricInfo(c, ascent, descent, width,
2585
			 &(pd->metrics[face-1]));
3542
			 &(pd->fonts->family->fonts[face-1]->metrics));
2586
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
3543
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
2587
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
3544
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
2588
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
3545
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
2589
}
3546
}
2590
 
3547
 
Line 2597... Line 3554...
2597
 
3554
 
2598
/* TODO
3555
/* TODO
2599
   Flate encoding?
3556
   Flate encoding?
2600
*/
3557
*/
2601
 
3558
 
2602
 
-
 
2603
typedef struct {
3559
typedef struct {
2604
    char filename[PATH_MAX];
3560
    char filename[PATH_MAX];
2605
 
3561
 
2606
    int pageno;		/* page number */
3562
    int pageno;		/* page number */
2607
    int fileno;		/* file number */
3563
    int fileno;		/* file number */
2608
 
3564
 
2609
    int fontfamily;	/* font family */
-
 
2610
    char encpath[PATH_MAX]; /* font encoding */
-
 
2611
    char encname[100];
-
 
2612
    char **afmpaths;	/* for user-specified family */
-
 
2613
    int maxpointsize;
3565
    int maxpointsize;
2614
 
3566
 
2615
    double width;	/* plot width in inches */
3567
    double width;	/* plot width in inches */
2616
    double height;	/* plot height in inches */
3568
    double height;	/* plot height in inches */
2617
    Rboolean onefile;	/* one file or one file per page? */
3569
    Rboolean onefile;	/* one file or one file per page? */
2618
 
3570
 
2619
    FILE *pdffp;		/* output file */
3571
    FILE *pdffp;		/* output file */
2620
 
3572
 
2621
    FontMetricInfo metrics[5];	/* font metrics */
-
 
2622
 
-
 
2623
    /* This group of variables track the current device status.
3573
    /* This group of variables track the current device status.
2624
     * They should only be set by routines that emit PDF. */
3574
     * They should only be set by routines that emit PDF. */
2625
    struct {
3575
    struct {
2626
	double lwd;		 /* line width */
3576
	double lwd;		 /* line width */
2627
	int lty;		 /* line type */
3577
	int lty;		 /* line type */
Line 2630... Line 3580...
2630
	rcolor col;		 /* color */
3580
	rcolor col;		 /* color */
2631
	rcolor fill;	         /* fill color */
3581
	rcolor fill;	         /* fill color */
2632
	rcolor bg;		 /* color */
3582
	rcolor bg;		 /* color */
2633
    } current;
3583
    } current;
2634
 
3584
 
-
 
3585
    /*
-
 
3586
     * This is a record of the alpha transparency levels used during
-
 
3587
     * drawing to the device.
-
 
3588
     * Only allow 256 different alpha levels 
-
 
3589
     * (because R uses 8-bit alpha channel).
-
 
3590
     * "alphas" is a record of alphas used so far (unused set to -1)
-
 
3591
     * There are separate alpha levels for stroking and filling 
-
 
3592
     * (i.e., col and fill)
-
 
3593
     */
-
 
3594
    short colAlpha[256];
-
 
3595
    short fillAlpha[256];
-
 
3596
 
-
 
3597
    /*
-
 
3598
     * What version of PDF are we trying to work with?
-
 
3599
     * This is used (so far) for implementing transparency
-
 
3600
     * Alphas are only used if version is at least 1.4
-
 
3601
     */
-
 
3602
    int versionMajor;
-
 
3603
    int versionMinor;
-
 
3604
 
2635
    int nobjs;  /* number of objects */
3605
    int nobjs;  /* number of objects */
2636
    int *pos; /* object positions */
3606
    int *pos; /* object positions */
2637
    int *pageobj; /* page object numbers */
3607
    int *pageobj; /* page object numbers */
2638
    int pagemax;
3608
    int pagemax;
2639
    int startstream; /* position of start of current stream */
3609
    int startstream; /* position of start of current stream */
2640
    Rboolean inText;
3610
    Rboolean inText;
2641
    char title[1024];
3611
    char title[1024];
-
 
3612
 
-
 
3613
    /*
-
 
3614
     * Fonts and encodings used on the device
-
 
3615
     */
-
 
3616
    type1fontlist fonts;
-
 
3617
    encodinglist encodings;
2642
}
3618
}
2643
PDFDesc;
3619
PDFDesc;
2644
 
3620
 
2645
/* Device Driver Actions */
3621
/* Device Driver Actions */
2646
 
3622
 
Line 2682... Line 3658...
2682
static void PDF_Text(double x, double y, char *str,
3658
static void PDF_Text(double x, double y, char *str,
2683
		     double rot, double hadj,
3659
		     double rot, double hadj,
2684
		     R_GE_gcontext *gc,
3660
		     R_GE_gcontext *gc,
2685
		     NewDevDesc *dd);
3661
		     NewDevDesc *dd);
2686
 
3662
 
-
 
3663
/*
-
 
3664
 * Add a graphics engine font family to the list of fonts used on a 
-
 
3665
 * PDF device ...
-
 
3666
 *
-
 
3667
 * ... AND add the font encoding to the list of encodings used on the
-
 
3668
 * device (if necessary)
-
 
3669
 */
-
 
3670
static Rboolean addPDFfont(type1fontfamily family,
-
 
3671
			   PDFDesc *pd,
-
 
3672
			   int *fontIndex)
-
 
3673
{
-
 
3674
    Rboolean result = FALSE;
-
 
3675
    type1fontlist fontlist = addDeviceFont(family, pd->fonts, fontIndex);
-
 
3676
    if (fontlist) {
-
 
3677
	int dontcare;
-
 
3678
	encodinginfo encoding = 
-
 
3679
	    findDeviceEncoding(family->encoding->encpath, 
-
 
3680
			       pd->encodings, &dontcare);
-
 
3681
	if (encoding) {
-
 
3682
	    pd->fonts = fontlist;
-
 
3683
	    result = TRUE;
-
 
3684
        } else {
-
 
3685
	    /* 
-
 
3686
	     * The encoding should have been loaded when the font was loaded
-
 
3687
	     */
-
 
3688
	    encoding = findEncoding(family->encoding->encpath);
-
 
3689
	    if (!encoding) {
-
 
3690
		warning("Corrupt loaded encodings;  font not added");
-
 
3691
	    } else {
-
 
3692
		encodinglist enclist = addDeviceEncoding(encoding, 
-
 
3693
							 pd->encodings);
-
 
3694
		if (enclist) {
-
 
3695
		    pd->fonts = fontlist;
-
 
3696
		    pd->encodings = enclist;
-
 
3697
		    result = TRUE;
-
 
3698
		} else
-
 
3699
		    warning("Failed to record device encoding; font not added");
-
 
3700
	    }
-
 
3701
	}
-
 
3702
    }
-
 
3703
    return result;
-
 
3704
}
-
 
3705
 
2687
static Rboolean
3706
static Rboolean
2688
innerPDFDeviceDriver(NewDevDesc* dd, char *file, char *family, char *encoding,
3707
innerPDFDeviceDriver(NewDevDesc* dd, char *file, char *family, char *encoding,
2689
		     char *bg, char *fg, double width, double height,
3708
		     char *bg, char *fg, double width, double height,
2690
		     double ps, int onefile, char *title)
3709
		     double ps, int onefile, char *title, SEXP fonts,
-
 
3710
		     int versionMajor, int versionMinor)
2691
{
3711
{
2692
    /* If we need to bail out with some sort of "error" */
3712
    /* If we need to bail out with some sort of "error" */
2693
    /* then we must free(dd) */
3713
    /* then we must free(dd) */
2694
 
3714
 
-
 
3715
    int i, gotFont;
2695
    double xoff = 0.0, yoff = 0.0, pointsize;
3716
    double xoff = 0.0, yoff = 0.0, pointsize;
2696
    rcolor setbg, setfg;
3717
    rcolor setbg, setfg;
-
 
3718
    type1fontfamily font;
2697
 
3719
 
2698
    PDFDesc *pd;
3720
    PDFDesc *pd;
2699
 
3721
 
2700
    /* Check and extract the device parameters */
3722
    /* Check and extract the device parameters */
2701
 
3723
 
Line 2708... Line 3730...
2708
    if (!(pd = (PDFDesc *) malloc(sizeof(PDFDesc))))
3730
    if (!(pd = (PDFDesc *) malloc(sizeof(PDFDesc))))
2709
	return 0;
3731
	return 0;
2710
    /* from here on, if need to bail out with "error", must also */
3732
    /* from here on, if need to bail out with "error", must also */
2711
    /* free(pd) */
3733
    /* free(pd) */
2712
 
3734
 
-
 
3735
    pd->versionMajor = versionMajor;
-
 
3736
    pd->versionMinor = versionMinor;
-
 
3737
 
2713
    pd->pos = (int *) calloc(350, sizeof(int));
3738
    pd->pos = (int *) calloc(350, sizeof(int));
2714
    if(!pd->pos) {
3739
    if(!pd->pos) {
2715
	free(pd); free(dd);
3740
	free(pd); free(dd);
2716
	error("cannot allocate pd->pos");
3741
	error("cannot allocate pd->pos");
2717
    }
3742
    }
Line 2724... Line 3749...
2724
 
3749
 
2725
 
3750
 
2726
    /* initialize PDF device description */
3751
    /* initialize PDF device description */
2727
    strcpy(pd->filename, file);
3752
    strcpy(pd->filename, file);
2728
    strncpy(pd->title, title, 1024);
3753
    strncpy(pd->title, title, 1024);
2729
    pd->fontfamily = MatchFamily(family);
-
 
-
 
3754
 
2730
    if(strlen(encoding) > PATH_MAX - 1) {
3755
    if(strlen(encoding) > PATH_MAX - 1) {
2731
	free(dd);
3756
	free(dd);
2732
	free(pd->pos); free(pd->pageobj); free(pd);
3757
	free(pd->pos); free(pd->pageobj); free(pd);
2733
	error("encoding path is too long");
3758
	error("encoding path is too long");
2734
    }
3759
    }
-
 
3760
 
-
 
3761
    pd->encodings = NULL;
-
 
3762
    pd->fonts = NULL;
-
 
3763
 
-
 
3764
    gotFont = 0;
-
 
3765
    if (!(font = findDefaultLoadedFont(encoding, family, 0))) {
-
 
3766
	font = addDefaultFontFromFamily(encoding, MatchFamily(family), 0);
-
 
3767
    }
-
 
3768
    if (font)
-
 
3769
	addPDFfont(font, pd, &gotFont);
-
 
3770
    if (!gotFont) {
-
 
3771
	free(dd);
-
 
3772
	free(pd);
-
 
3773
	error("Failed to initialise default PostScript font");
-
 
3774
    }
-
 
3775
		
-
 
3776
    /* 
-
 
3777
     * Load the font names sent in via the fonts arg
-
 
3778
     * NOTE that these are the font names specified at the 
-
 
3779
     * R-level, NOT the translated font names.  
-
 
3780
     */
-
 
3781
    if (!isNull(fonts)) {
-
 
3782
	int i, dontcare, gotFonts = 0, nfonts = LENGTH(fonts);
-
 
3783
	for (i=0; i<nfonts; i++) {
-
 
3784
	    int index;
-
 
3785
	    char *name = CHAR(STRING_ELT(fonts, i));
-
 
3786
	    if (findDeviceFont(name, pd->fonts, &index))
-
 
3787
		gotFonts++;
-
 
3788
	    else {
-
 
3789
		if (!(font = findLoadedFont(name)))
-
 
3790
		    font = addFont(name, 0);
-
 
3791
		if (font)
-
 
3792
		    if (addPDFfont(font, pd, &dontcare)) {
-
 
3793
			gotFonts++;
-
 
3794
		    } 
-
 
3795
	    }
-
 
3796
	}
-
 
3797
	if (gotFonts < nfonts) {
-
 
3798
	    freeDeviceFontList(pd->fonts);
2735
    strcpy(pd->encpath, encoding);
3799
	    freeDeviceEncList(pd->encodings);
-
 
3800
	    pd->fonts = NULL;
-
 
3801
	    pd->encodings = NULL;
-
 
3802
	    free(dd);
-
 
3803
	    free(pd);
-
 
3804
	    error("Failed to initialise additional PostScript fonts");
-
 
3805
	}
-
 
3806
    }
-
 
3807
					  
2736
    setbg = str2col(bg);
3808
    setbg = str2col(bg);
2737
    setfg = str2col(fg);
3809
    setfg = str2col(fg);
2738
 
3810
 
-
 
3811
    /*
-
 
3812
     * Initialise all alphas to -1
-
 
3813
     */
-
 
3814
    for (i=0; i<256; i++) {
-
 
3815
	pd->colAlpha[i] = -1;
-
 
3816
	pd->fillAlpha[i] = -1;
-
 
3817
    }
-
 
3818
 
2739
    pd->width = width;
3819
    pd->width = width;
2740
    pd->height = height;
3820
    pd->height = height;
2741
    pointsize = floor(ps);
3821
    pointsize = floor(ps);
2742
    if(setbg == NA_INTEGER && setfg  == NA_INTEGER) {
3822
    if(setbg == NA_INTEGER && setfg  == NA_INTEGER) {
-
 
3823
	freeDeviceFontList(pd->fonts);
-
 
3824
	freeDeviceEncList(pd->encodings);
-
 
3825
	pd->fonts = NULL;
-
 
3826
	pd->encodings = NULL;
2743
	free(dd);
3827
	free(dd);
2744
	free(pd->pos); free(pd->pageobj); free(pd);
3828
	free(pd->pos); free(pd->pageobj); free(pd);
2745
	error("invalid foreground/background color (pdf)");
3829
	error("invalid foreground/background color (pdf)");
2746
    }
3830
    }
2747
 
3831
 
Line 2796... Line 3880...
2796
    dd->canChangeGamma = FALSE;
3880
    dd->canChangeGamma = FALSE;
2797
 
3881
 
2798
    /*	Start the driver */
3882
    /*	Start the driver */
2799
 
3883
 
2800
    if(!PDF_Open(dd, pd)) {
3884
    if(!PDF_Open(dd, pd)) {
-
 
3885
	freeDeviceFontList(pd->fonts);
-
 
3886
	freeDeviceEncList(pd->encodings);
-
 
3887
	pd->fonts = NULL;
-
 
3888
	pd->encodings = NULL;
-
 
3889
	free(dd);
2801
	free(pd->pos); free(pd->pageobj); free(pd);
3890
	free(pd->pos); free(pd->pageobj); free(pd);
2802
	return 0;
3891
	return 0;
2803
    }
3892
    }
2804
 
3893
 
2805
    dd->newDevStruct = 1;
3894
    dd->newDevStruct = 1;
Line 2852... Line 3941...
2852
}
3941
}
2853
 
3942
 
2854
Rboolean
3943
Rboolean
2855
PDFDeviceDriver(DevDesc* dd, char *file, char *family, char *encoding,
3944
PDFDeviceDriver(DevDesc* dd, char *file, char *family, char *encoding,
2856
		char *bg, char *fg, double width, double height, double ps,
3945
		char *bg, char *fg, double width, double height, double ps,
2857
		int onefile, char *title)
3946
		int onefile, char *title, SEXP fonts,
-
 
3947
		int versionMajor, int versionMinor)
2858
{
3948
{
2859
    return innerPDFDeviceDriver((NewDevDesc*) dd, file, family, encoding,
3949
    return innerPDFDeviceDriver((NewDevDesc*) dd, file, family, encoding,
2860
				bg, fg, width, height, ps, onefile, title);
3950
				bg, fg, width, height, ps, onefile, title,
-
 
3951
				fonts, versionMajor, versionMinor);
-
 
3952
}
-
 
3953
 
-
 
3954
/*
-
 
3955
 * Search through the alphas used so far and return
-
 
3956
 * existing index if there is one.
-
 
3957
 * Otherwise, add alpha to the list and return new index
-
 
3958
 */
-
 
3959
static int alphaIndex(int alpha, short *alphas) {
-
 
3960
    int i, found = 0;
-
 
3961
    for (i=0; i<256 && !found; i++) {
-
 
3962
	if (alphas[i] < 0) {
-
 
3963
	    alphas[i] = alpha;
-
 
3964
	    found = 1;
-
 
3965
	}
-
 
3966
	if (alpha == alphas[i]) 
-
 
3967
	    found = 1;
-
 
3968
    }
-
 
3969
    if (!found)
-
 
3970
	error("Invalid alpha value in PDF");
-
 
3971
    return i;
-
 
3972
}
-
 
3973
 
-
 
3974
/*
-
 
3975
 * colAlpha graphics state parameter dictionaries are named
-
 
3976
 * /GS1 to /GS256
-
 
3977
 * fillAlpha graphics state parameter dictionaries are named
-
 
3978
 * /GS257 to /GS512
-
 
3979
 */
-
 
3980
static int colAlphaIndex(int alpha, PDFDesc *pd) {
-
 
3981
    return alphaIndex(alpha, pd->colAlpha);
-
 
3982
}
-
 
3983
 
-
 
3984
static int fillAlphaIndex(int alpha, PDFDesc *pd) {
-
 
3985
    return alphaIndex(alpha, pd->fillAlpha) + 256;
-
 
3986
}
-
 
3987
 
-
 
3988
/*
-
 
3989
 * Does the version support alpha transparency?
-
 
3990
 */
-
 
3991
static int alphaVersion(PDFDesc *pd) {
-
 
3992
    return (pd->versionMajor > 1  ||
-
 
3993
	    (pd->versionMajor == 1 && pd->versionMinor >= 4));
-
 
3994
}
-
 
3995
 
-
 
3996
/*
-
 
3997
 * Do we need to bother with semi-transparency?
-
 
3998
 */
-
 
3999
static int semiTransparent(int col)
-
 
4000
{
-
 
4001
    return !(R_OPAQUE(col) || R_TRANSPARENT(col));
2861
}
4002
}
2862
 
4003
 
2863
static void PDF_SetLineColor(int color, NewDevDesc *dd)
4004
static void PDF_SetLineColor(int color, NewDevDesc *dd)
2864
{
4005
{
2865
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
4006
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
2866
 
4007
 
2867
    if(color != pd->current.col) {
4008
    if(color != pd->current.col) {
-
 
4009
	if (alphaVersion(pd)) {
-
 
4010
	    /* 
-
 
4011
	     * Apply graphics state parameter dictionary 
-
 
4012
	     * to set alpha
-
 
4013
	     */
-
 
4014
	    fprintf(pd->pdffp, "/GS%i gs\n", 
-
 
4015
		    colAlphaIndex(R_ALPHA(color), pd));
-
 
4016
	}
2868
	fprintf(pd->pdffp, "%.3f %.3f %.3f RG\n",
4017
	fprintf(pd->pdffp, "%.3f %.3f %.3f RG\n",
2869
		R_RED(color)/255.0,
4018
		R_RED(color)/255.0,
2870
		R_GREEN(color)/255.0,
4019
		R_GREEN(color)/255.0,
2871
		R_BLUE(color)/255.0);
4020
		R_BLUE(color)/255.0);
2872
	pd->current.col = color;
4021
	pd->current.col = color;
Line 2875... Line 4024...
2875
 
4024
 
2876
static void PDF_SetFill(int color, NewDevDesc *dd)
4025
static void PDF_SetFill(int color, NewDevDesc *dd)
2877
{
4026
{
2878
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
4027
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
2879
    if(color != pd->current.fill) {
4028
    if(color != pd->current.fill) {
-
 
4029
	if (alphaVersion(pd)) {
-
 
4030
	    /* 
-
 
4031
	     * Apply graphics state parameter dictionary 
-
 
4032
	     * to set alpha
-
 
4033
	     */
-
 
4034
	    fprintf(pd->pdffp, "/GS%i gs\n", 
-
 
4035
		    fillAlphaIndex(R_ALPHA(color), pd));
-
 
4036
	}
2880
	fprintf(pd->pdffp, "%.3f %.3f %.3f rg\n",
4037
	fprintf(pd->pdffp, "%.3f %.3f %.3f rg\n",
2881
		   R_RED(color)/255.0,
4038
		   R_RED(color)/255.0,
2882
		   R_GREEN(color)/255.0,
4039
		   R_GREEN(color)/255.0,
2883
		   R_BLUE(color)/255.0);
4040
		   R_BLUE(color)/255.0);
2884
	pd->current.fill = color;
4041
	pd->current.fill = color;
Line 2920... Line 4077...
2920
{
4077
{
2921
    fprintf(pd->pdffp, "ET\n");
4078
    fprintf(pd->pdffp, "ET\n");
2922
    pd->inText = FALSE;
4079
    pd->inText = FALSE;
2923
}
4080
}
2924
 
4081
 
2925
static void PDF_EncodeFont(PDFDesc *pd, int nobj)
4082
static void PDF_Encodings(PDFDesc *pd)
2926
{
4083
{
2927
    char *encname = pd->encname;
4084
    encodinglist enclist = pd->encodings;
2928
 
4085
 
-
 
4086
    while (enclist) {
-
 
4087
	encodinginfo encoding = enclist->encoding;
-
 
4088
	pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
-
 
4089
 
2929
    fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Encoding\n", nobj);
4090
	fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Encoding\n", pd->nobjs);
2930
    if (strcmp(encname, "WinAnsiEncoding") == 0 ||
4091
	if (strcmp(encoding->name, "WinAnsiEncoding") == 0 ||
2931
	strcmp(encname, "MacRomanEncoding") == 0 ||
4092
	    strcmp(encoding->name, "MacRomanEncoding") == 0 ||
2932
	strcmp(encname, "PDFDocEncoding") == 0) {
4093
	    strcmp(encoding->name, "PDFDocEncoding") == 0) {
2933
	fprintf(pd->pdffp, "/BaseEncoding /%s\n", encname);
4094
	    fprintf(pd->pdffp, "/BaseEncoding /%s\n", encoding->name);
2934
	fprintf(pd->pdffp, "/Differences [ 45/minus ]\n");
4095
	    fprintf(pd->pdffp, "/Differences [ 45/minus ]\n");
2935
    } else if (strcmp(encname, "ISOLatin1Encoding") == 0) {
4096
	} else if (strcmp(encoding->name, "ISOLatin1Encoding") == 0) {
2936
	fprintf(pd->pdffp, "/BaseEncoding /PDFDocEncoding\n");
4097
	    fprintf(pd->pdffp, "/BaseEncoding /PDFDocEncoding\n");
2937
	fprintf(pd->pdffp, "/Differences [ 45/minus 96/quoteleft\n144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent\n/dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space]\n");
4098
	    fprintf(pd->pdffp, "/Differences [ 45/minus 96/quoteleft\n144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent\n/dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space]\n");
2938
    } else {
4099
	} else {
2939
	fprintf(pd->pdffp, "/BaseEncoding /PDFDocEncoding\n");
4100
	    fprintf(pd->pdffp, "/BaseEncoding /PDFDocEncoding\n");
2940
	fprintf(pd->pdffp, "/Differences [ 0 %s ]\n", enccode);
4101
	    fprintf(pd->pdffp, "/Differences [ 0 %s ]\n", encoding->enccode);
-
 
4102
	}
-
 
4103
	fprintf(pd->pdffp, ">>\nendobj\n");
-
 
4104
	
-
 
4105
	enclist = enclist->next;
2941
    }
4106
    }
2942
    fprintf(pd->pdffp, ">>\nendobj\n");
-
 
2943
}
4107
}
2944
 
4108
 
2945
#include <time.h>
4109
#include <time.h>
2946
#include <Rversion.h>
4110
#include <Rversion.h>
2947
 
4111
 
2948
static void PDF_startfile(PDFDesc *pd)
4112
static void PDF_startfile(PDFDesc *pd)
2949
{
4113
{
2950
    int i;
-
 
2951
    struct tm *ltm;
4114
    struct tm *ltm;
2952
    time_t ct;
4115
    time_t ct;
2953
 
4116
 
2954
    pd->nobjs = 0;
4117
    pd->nobjs = 0;
2955
    pd->pageno = 0;
4118
    pd->pageno = 0;
2956
    fprintf(pd->pdffp, "%%PDF-1.1\n%%âãÏÓ\r\n");
4119
    fprintf(pd->pdffp, "%%PDF-%i.%i\n%%âãÏÓ\r\n", 
-
 
4120
	    pd->versionMajor, pd->versionMinor);
2957
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
4121
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2958
 
4122
 
2959
    /* Object 1 is Info node. Date format is from the PDF manual */
4123
    /* Object 1 is Info node. Date format is from the PDF manual */
2960
 
4124
 
2961
    ct = time(NULL);
4125
    ct = time(NULL);
Line 2976... Line 4140...
2976
 
4140
 
2977
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
4141
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2978
    fprintf(pd->pdffp, "2 0 obj\n<<\n/Type /Catalog\n/Pages 3 0 R\n>>\nendobj\n");
4142
    fprintf(pd->pdffp, "2 0 obj\n<<\n/Type /Catalog\n/Pages 3 0 R\n>>\nendobj\n");
2979
 
4143
 
2980
    /* Object 3 will be at the end */
4144
    /* Object 3 will be at the end */
2981
 
-
 
2982
    /* Object 4 is the standard resources dict for each page */
-
 
2983
 
4145
    
2984
    ++pd->nobjs;
4146
    ++pd->nobjs;
2985
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
-
 
2986
    fprintf(pd->pdffp,
-
 
2987
	    "4 0 obj\n<<\n/ProcSet [/PDF /Text]\n/Font << %s %s %s %s %s %s >>\n>>\nendobj\n",
-
 
2988
	    "/F1 6 0 R","/F2 7 0 R","/F3 8 0 R","/F4 9 0 R","/F5 10 0 R",
-
 
2989
	    "/F6 11 0 R");
-
 
2990
 
4147
 
2991
    /* Object 5 is the encoding for text fonts */
4148
    /* Object 4 will be at the end */
2992
 
4149
 
2993
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
-
 
2994
    PDF_EncodeFont(pd, pd->nobjs);
4150
    ++pd->nobjs;
2995
 
4151
 
2996
    /* Objects 6, 7, 8, 9 are the fonts for the text family */
-
 
2997
    /* Object 10 is the Symbol font */
-
 
2998
    /* Object 11 is Dingbats, used for (small) circles */
4152
    /* Object 5 is Dingbats, used for (small) circles */
2999
 
4153
 
3000
    for (i = 0; i < 4; i++) {
-
 
3001
	pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
-
 
3002
	fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F%d\n/BaseFont /%s\n/Encoding 5 0 R\n>>\nendobj\n",
-
 
3003
		i+6, i+1, familyname[i]);
-
 
3004
    }
-
 
3005
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
-
 
3006
    fprintf(pd->pdffp, "10 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F5\n/BaseFont /Symbol\n>>\nendobj\n");
-
 
3007
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
4154
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
3008
    fprintf(pd->pdffp, "11 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F6\n/BaseFont /ZapfDingbats\n>>\nendobj\n");
4155
    fprintf(pd->pdffp, "5 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F1\n/BaseFont /ZapfDingbats\n>>\nendobj\n");
3009
}
4156
}
3010
 
4157
 
3011
static void PDF_endfile(PDFDesc *pd)
4158
static void PDF_endfile(PDFDesc *pd)
3012
{
4159
{
3013
    int i, startxref;
4160
    int i, startxref, tempnobj, nenc, nfonts, firstencobj;
3014
    /* object 3 lists all the pages */
4161
    /* object 3 lists all the pages */
3015
 
4162
 
3016
    pd->pos[3] = (int) ftell(pd->pdffp);
4163
    pd->pos[3] = (int) ftell(pd->pdffp);
3017
    fprintf(pd->pdffp, "3 0 obj\n<<\n/Type /Pages\n/Kids [\n");
4164
    fprintf(pd->pdffp, "3 0 obj\n<<\n/Type /Pages\n/Kids [\n");
3018
    for(i = 0; i < pd->pageno; i++)
4165
    for(i = 0; i < pd->pageno; i++)
Line 3021... Line 4168...
3021
    fprintf(pd->pdffp,
4168
    fprintf(pd->pdffp,
3022
	    "]\n/Count %d\n/MediaBox [0 0 %d %d]\n>>\nendobj\n",
4169
	    "]\n/Count %d\n/MediaBox [0 0 %d %d]\n>>\nendobj\n",
3023
	    pd->pageno,
4170
	    pd->pageno,
3024
	    (int) (0.5 + 72*pd->width), (int) (0.5 + 72*pd->height));
4171
	    (int) (0.5 + 72*pd->width), (int) (0.5 + 72*pd->height));
3025
 
4172
 
-
 
4173
    /* Object 4 is the standard resources dict for each page */
-
 
4174
 
-
 
4175
    pd->pos[4] = (int) ftell(pd->pdffp);
-
 
4176
    /* fonts */
-
 
4177
    /* Dingbats always first */
-
 
4178
    fprintf(pd->pdffp,
-
 
4179
	    "4 0 obj\n<<\n/ProcSet [/PDF /Text]\n/Font << /F1 5 0 R ");
-
 
4180
    /* Count how many encodings will be included 
-
 
4181
     * fonts come after encodings */
-
 
4182
    nenc = 0;
-
 
4183
    if (pd->encodings) {
-
 
4184
	encodinglist enclist = pd->encodings;
-
 
4185
	while (enclist) {
-
 
4186
	    nenc++;
-
 
4187
	    enclist = enclist->next;
-
 
4188
	}
-
 
4189
    }
-
 
4190
    /* Should be a default text font at least, plus possibly others */
-
 
4191
    nfonts = 0;
-
 
4192
    tempnobj = pd->nobjs + nenc;
-
 
4193
    if (pd->fonts) {
-
 
4194
	type1fontlist fontlist = pd->fonts;
-
 
4195
	while (fontlist) {
-
 
4196
	    for (i=0; i<5; i++) {
-
 
4197
		fprintf(pd->pdffp, "/F%d %d 0 R ",
-
 
4198
			/* /F1 is dingbats */
-
 
4199
			nfonts + 2, ++tempnobj);	    
-
 
4200
		nfonts++;
-
 
4201
	    }
-
 
4202
	    fontlist = fontlist->next;
-
 
4203
	}
-
 
4204
    }
-
 
4205
    fprintf(pd->pdffp, ">>\n");
-
 
4206
    /* graphics state parameter dictionaries */
-
 
4207
    fprintf(pd->pdffp, "/ExtGState << ");
-
 
4208
    tempnobj = pd->nobjs + nenc + nfonts;
-
 
4209
    for (i = 0; i < 256 && pd->colAlpha[i] >= 0; i++) {
-
 
4210
	fprintf(pd->pdffp, "/GS%i %d 0 R ", i + 1, ++tempnobj);
-
 
4211
    }
-
 
4212
    for (i = 0; i < 256 && pd->fillAlpha[i] >= 0; i++) {
-
 
4213
	fprintf(pd->pdffp, "/GS%i %d 0 R ", i + 257, ++tempnobj);
-
 
4214
    }
-
 
4215
    fprintf(pd->pdffp, ">>\n");
-
 
4216
 
-
 
4217
    fprintf(pd->pdffp, ">>\nendobj\n");
-
 
4218
 
-
 
4219
    /* 
-
 
4220
     * Write out objects representing the encodings
-
 
4221
     */
-
 
4222
 
-
 
4223
    firstencobj = pd->nobjs;
-
 
4224
    PDF_Encodings(pd);
-
 
4225
 
-
 
4226
    /* 
-
 
4227
     * Write out objects representing the fonts
-
 
4228
     */
-
 
4229
 
-
 
4230
    nfonts = 0;
-
 
4231
    if (pd->fonts) {
-
 
4232
	type1fontlist fontlist = pd->fonts;
-
 
4233
	while (fontlist) {
-
 
4234
	    /*
-
 
4235
	     * Find the index of the device encoding
-
 
4236
	     * This really should be there
-
 
4237
	     */
-
 
4238
	    int encIndex;
-
 
4239
	    encodinginfo encoding = 
-
 
4240
		findDeviceEncoding(fontlist->family->encoding->encpath,
-
 
4241
				   pd->encodings, &encIndex);
-
 
4242
	    if (!encoding)
-
 
4243
		error("Corrupt encodings in PDF device");
-
 
4244
	    for (i=0; i<4; i++) {
-
 
4245
		pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
-
 
4246
		fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F%d\n/BaseFont /%s\n/Encoding %d 0 R\n>>\nendobj\n",
-
 
4247
			pd->nobjs,  
-
 
4248
			nfonts + 2, 
-
 
4249
			fontlist->family->fonts[i]->name,
-
 
4250
			/* Encodings come after dingbats font which is 
-
 
4251
			 * object 5 */
-
 
4252
			encIndex + firstencobj);	    
-
 
4253
		nfonts++;
-
 
4254
	    }
-
 
4255
	    /* Symbol face does not use encoding */
-
 
4256
	    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
-
 
4257
	    fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F%d\n/BaseFont /%s\n>>\nendobj\n",
-
 
4258
		    pd->nobjs,  
-
 
4259
		    nfonts + 2, 
-
 
4260
		    fontlist->family->fonts[4]->name);
-
 
4261
	    nfonts++;
-
 
4262
 
-
 
4263
	    fontlist = fontlist->next;
-
 
4264
	}
-
 
4265
    }
-
 
4266
 
-
 
4267
    /* 
-
 
4268
     * Write out objects representing the graphics state parameter 
-
 
4269
     * dictionaries for alpha transparency
-
 
4270
     *
-
 
4271
     * NOTE:  R considers alpha=0 opaque, in PDF it is transparent
-
 
4272
     * so we must take 1 - alpha value
-
 
4273
     */
-
 
4274
    for (i = 0; i < 256 && pd->colAlpha[i] >= 0; i++) {
-
 
4275
	pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
-
 
4276
	fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /ExtGState\n/CA %1.3f >>\nendobj\n", 
-
 
4277
		pd->nobjs, 1 - pd->colAlpha[i]/255.0);
-
 
4278
    }
-
 
4279
    for (i = 0; i < 256 && pd->fillAlpha[i] >= 0; i++) {
-
 
4280
	pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
-
 
4281
	fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /ExtGState\n/ca %1.3f\n>>\nendobj\n", 
-
 
4282
		pd->nobjs, 1 - pd->fillAlpha[i]/255.0);
-
 
4283
    }
-
 
4284
 
3026
    /* write out xref table */
4285
    /* write out xref table */
3027
 
4286
 
3028
    startxref = (int) ftell(pd->pdffp);
4287
    startxref = (int) ftell(pd->pdffp);
3029
    /* items here must be exactly 20 bytes including terminator */
4288
    /* items here must be exactly 20 bytes including terminator */
3030
    fprintf(pd->pdffp, "xref\n0 %d\n", pd->nobjs+1);
4289
    fprintf(pd->pdffp, "xref\n0 %d\n", pd->nobjs+1);
Line 3042... Line 4301...
3042
 
4301
 
3043
 
4302
 
3044
static Rboolean PDF_Open(NewDevDesc *dd, PDFDesc *pd)
4303
static Rboolean PDF_Open(NewDevDesc *dd, PDFDesc *pd)
3045
{
4304
{
3046
    char buf[512];
4305
    char buf[512];
3047
    int i;
-
 
3048
 
-
 
3049
    if (!LoadEncoding(pd->encpath, pd->encname, TRUE)) {
-
 
3050
	warning("problem loading encoding file");
-
 
3051
	return FALSE;
-
 
3052
    }
-
 
3053
    for(i = 0; i < 4 ; i++) {
-
 
3054
	char const *p = Family[pd->fontfamily].afmfile[i];
-
 
3055
	if(!PostScriptLoadFontMetrics(p, &(pd->metrics[i]),
-
 
3056
				      familyname[i], 1)) {
-
 
3057
	    warning("cannot read afm file %s", p);
-
 
3058
	    return FALSE;
-
 
3059
	}
-
 
3060
    }
-
 
3061
    if(!PostScriptLoadFontMetrics("sy______.afm", &(pd->metrics[4]),
-
 
3062
				  familyname[4], 0)) {
-
 
3063
	warning("cannot read afm file sy______.afm");
-
 
3064
	return FALSE;
-
 
3065
    }
-
 
3066
 
4306
 
3067
    /* NB: this must be binary to get tell positions and line endings right */
4307
    /* NB: this must be binary to get tell positions and line endings right */
3068
 
4308
 
3069
    snprintf(buf, 512, pd->filename, pd->fileno + 1); /* file 1 to start */
4309
    snprintf(buf, 512, pd->filename, pd->fileno + 1); /* file 1 to start */
3070
    pd->pdffp = R_fopen(R_ExpandFileName(buf), "wb");
4310
    pd->pdffp = R_fopen(R_ExpandFileName(buf), "wb");
Line 3163... Line 4403...
3163
{
4403
{
3164
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
4404
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3165
 
4405
 
3166
    if(pd->pageno > 0) PDF_endpage(pd);
4406
    if(pd->pageno > 0) PDF_endpage(pd);
3167
    PDF_endfile(pd);
4407
    PDF_endfile(pd);
-
 
4408
    freeDeviceFontList(pd->fonts);
-
 
4409
    freeDeviceEncList(pd->encodings);
-
 
4410
    pd->fonts = NULL;
-
 
4411
    pd->encodings = NULL;
3168
    free(pd->pos); free(pd->pageobj); free(pd);
4412
    free(pd->pos); free(pd->pageobj); free(pd);
3169
}
4413
}
3170
 
4414
 
3171
static void PDF_Activate(NewDevDesc *dd) {}
4415
static void PDF_Activate(NewDevDesc *dd) {}
3172
static void PDF_Deactivate(NewDevDesc *dd) {}
4416
static void PDF_Deactivate(NewDevDesc *dd) {}
Line 3176... Line 4420...
3176
		     NewDevDesc *dd)
4420
		     NewDevDesc *dd)
3177
{
4421
{
3178
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
4422
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3179
    int code;
4423
    int code;
3180
 
4424
 
-
 
4425
    /*
3181
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
4426
     * Only try to do real transparency if version at least 1.4
3182
    if (code) {
4427
     */
-
 
4428
    if ((semiTransparent(gc->col) ||
-
 
4429
	 semiTransparent(gc->fill)) &&
-
 
4430
	alphaVersion(pd)) {
3183
	if(pd->inText) textoff(pd);
4431
	if(pd->inText) textoff(pd);
-
 
4432
	PDF_SetFill(gc->fill, dd);
-
 
4433
	PDF_SetLineColor(gc->col, dd);
-
 
4434
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
-
 
4435
	fprintf(pd->pdffp, "%.2f %.2f %.2f %.2f re B\n", x0, y0, x1-x0, y1-y0);
-
 
4436
    } else {
-
 
4437
	code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
-
 
4438
	if (code) {
-
 
4439
	    if(pd->inText) textoff(pd);
3184
	if(code & 2)
4440
	    if(code & 2)
3185
	    PDF_SetFill(gc->fill, dd);
4441
		PDF_SetFill(gc->fill, dd);
3186
	if(code & 1) {
4442
	    if(code & 1) {
3187
	    PDF_SetLineColor(gc->col, dd);
4443
		PDF_SetLineColor(gc->col, dd);
3188
	    PDF_SetLineStyle(gc->lty, gc->lwd, dd);
4444
		PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3189
	}
4445
	    }
3190
	fprintf(pd->pdffp, "%.2f %.2f %.2f %.2f re", x0, y0, x1-x0, y1-y0);
4446
	    fprintf(pd->pdffp, "%.2f %.2f %.2f %.2f re", x0, y0, x1-x0, y1-y0);
3191
	switch(code){
4447
	    switch(code){
3192
	case 1: fprintf(pd->pdffp, " S\n"); break;
4448
	    case 1: fprintf(pd->pdffp, " S\n"); break;
3193
	case 2: fprintf(pd->pdffp, " f\n"); break;
4449
	    case 2: fprintf(pd->pdffp, " f\n"); break;
3194
	case 3: fprintf(pd->pdffp, " B\n"); break;
4450
	    case 3: fprintf(pd->pdffp, " B\n"); break;
-
 
4451
	    }
3195
	}
4452
	}
3196
    }
4453
    }
3197
}
4454
}
3198
 
4455
 
3199
/* r is in device coords */
4456
/* r is in device coords */
Line 3203... Line 4460...
3203
{
4460
{
3204
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
4461
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3205
    int code, tr;
4462
    int code, tr;
3206
    double xx, yy, a;
4463
    double xx, yy, a;
3207
 
4464
 
-
 
4465
    /*
3208
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
4466
     * Only try to do real transparency if version at least 1.4
3209
 
4467
     */
3210
    if (code) {
4468
    if ((semiTransparent(gc->col) ||
-
 
4469
	 semiTransparent(gc->fill)) &&
3211
	if(code & 2)
4470
	alphaVersion(pd)) {
3212
	    PDF_SetFill(gc->fill, dd);
4471
	PDF_SetFill(gc->fill, dd);
3213
	if(code & 1) {
-
 
3214
	    PDF_SetLineColor(gc->col, dd);
4472
	PDF_SetLineColor(gc->col, dd);
3215
	    PDF_SetLineStyle(gc->lty, gc->lwd, dd);
4473
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3216
	}
4474
	/*
3217
	if(r > 10) { /* somewhat arbitrary, use font up to 20pt */
4475
	 * Due to possible bug in Acrobat Reader for rendering
3218
            /* Use four Bezier curves, hand-fitted to quadrants */
4476
	 * semi-transparent text, only every draw Bezier curves
-
 
4477
	 * regardless of circle size.
-
 
4478
	 */
-
 
4479
	{ 
3219
	    double s = 0.55 * r;
4480
	    double s = 0.55 * r;
3220
	    if(pd->inText) textoff(pd);
4481
	    if(pd->inText) textoff(pd);
3221
	    fprintf(pd->pdffp, "  %.2f %.2f m\n", x - r, y);
4482
	    fprintf(pd->pdffp, "  %.2f %.2f m\n", x - r, y);
3222
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
4483
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3223
		   x - r, y + s, x - s, y + r, x, y + r);
4484
		    x - r, y + s, x - s, y + r, x, y + r);
3224
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
4485
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3225
		   x + s, y + r, x + r, y + s, x + r, y);
4486
		    x + s, y + r, x + r, y + s, x + r, y);
3226
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
4487
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3227
		   x + r, y - s, x + s, y - r, x, y - r);
4488
		    x + r, y - s, x + s, y - r, x, y - r);
3228
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
4489
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3229
		   x - s, y - r, x - r, y - s, x - r, y);
4490
		    x - s, y - r, x - r, y - s, x - r, y);
-
 
4491
	    fprintf(pd->pdffp, "B\n"); 
-
 
4492
	} 
-
 
4493
    } else {
-
 
4494
	code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
-
 
4495
	if (code) {
-
 
4496
	    if(code & 2)
-
 
4497
		PDF_SetFill(gc->fill, dd);
-
 
4498
	    if(code & 1) {
-
 
4499
		PDF_SetLineColor(gc->col, dd);
-
 
4500
		PDF_SetLineStyle(gc->lty, gc->lwd, dd);
-
 
4501
	    }
-
 
4502
	    if(r > 10) { /* somewhat arbitrary, use font up to 20pt */
-
 
4503
		/* Use four Bezier curves, hand-fitted to quadrants */
-
 
4504
		double s = 0.55 * r;
-
 
4505
		if(pd->inText) textoff(pd);
-
 
4506
		fprintf(pd->pdffp, "  %.2f %.2f m\n", x - r, y);
-
 
4507
		fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
-
 
4508
			x - r, y + s, x - s, y + r, x, y + r);
-
 
4509
		fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
-
 
4510
			x + s, y + r, x + r, y + s, x + r, y);
-
 
4511
		fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
-
 
4512
			x + r, y - s, x + s, y - r, x, y - r);
-
 
4513
		fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
-
 
4514
			x - s, y - r, x - r, y - s, x - r, y);
3230
	    switch(code){
4515
		switch(code){
3231
	    case 1: fprintf(pd->pdffp, "S\n"); break;
4516
		case 1: fprintf(pd->pdffp, "S\n"); break;
3232
	    case 2: fprintf(pd->pdffp, "f\n"); break;
4517
		case 2: fprintf(pd->pdffp, "f\n"); break;
3233
	    case 3: fprintf(pd->pdffp, "B\n"); break;
4518
		case 3: fprintf(pd->pdffp, "B\n"); break;
-
 
4519
		}
-
 
4520
	    } else {
-
 
4521
		/* Use char 108 in Dingbats, which is a solid disc
-
 
4522
		   afm is C 108 ; WX 791 ; N a71 ; B 35 -14 757 708 ;
-
 
4523
		   so diameter = 0.722 * size
-
 
4524
		   centre = (0.396, 0.347) * size
-
 
4525
		*/
-
 
4526
		a = 2./0.722 * r;
-
 
4527
		xx = x - 0.396*a;
-
 
4528
		yy = y - 0.347*a;
-
 
4529
		tr = (R_ALPHA(gc->fill) == 0) + 
-
 
4530
		    2 * (R_ALPHA(gc->col) == 0) - 1;
-
 
4531
		if(!pd->inText) texton(pd);
-
 
4532
		fprintf(pd->pdffp,
-
 
4533
			"/F1 1 Tf %d Tr %.2f 0 0 %.2f %.2f %.2f Tm",
-
 
4534
			tr, a, a, xx, yy);
-
 
4535
		fprintf(pd->pdffp, " (l) Tj 0 Tr\n");
3234
	    }
4536
	    }
3235
	} else {
-
 
3236
	    /* Use char 108 in Dingbats, which is a solid disc
-
 
3237
	       afm is C 108 ; WX 791 ; N a71 ; B 35 -14 757 708 ;
-
 
3238
	       so diameter = 0.722 * size
-
 
3239
	       centre = (0.396, 0.347) * size
-
 
3240
	    */
-
 
3241
	    a = 2./0.722 * r;
-
 
3242
	    xx = x - 0.396*a;
-
 
3243
	    yy = y - 0.347*a;
-
 
3244
	    tr = (R_ALPHA(gc->fill) == 0) + 2 * (R_ALPHA(gc->col) == 0) - 1;
-
 
3245
	    if(!pd->inText) texton(pd);
-
 
3246
	    fprintf(pd->pdffp,
-
 
3247
		    "/F6 1 Tf %d Tr %.2f 0 0 %.2f %.2f %.2f Tm",
-
 
3248
		    tr, a, a, xx, yy);
-
 
3249
	    fprintf(pd->pdffp, " (l) Tj 0 Tr\n");
-
 
3250
	}
4537
	}
3251
    }
4538
    }
3252
}
4539
}
3253
 
4540
 
3254
static void PDF_Line(double x1, double y1, double x2, double y2,
4541
static void PDF_Line(double x1, double y1, double x2, double y2,
3255
		     R_GE_gcontext *gc,
4542
		     R_GE_gcontext *gc,
3256
		     NewDevDesc *dd)
4543
		     NewDevDesc *dd)
3257
{
4544
{
3258
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
4545
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3259
 
4546
 
-
 
4547
    /*
-
 
4548
     * Only try to do real transparency if version at least 1.4
-
 
4549
     */
-
 
4550
    if ((semiTransparent(gc->col) && alphaVersion(pd)) ||
3260
    if(R_ALPHA(gc->col) == 0) {
4551
	(R_ALPHA(gc->col) == 0)) {
3261
	PDF_SetLineColor(gc->col, dd);
4552
	PDF_SetLineColor(gc->col, dd);
3262
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
4553
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3263
	if(pd->inText) textoff(pd);
4554
	if(pd->inText) textoff(pd);
3264
	fprintf(pd->pdffp, "%.2f %.2f m %.2f %.2f l S\n", x1, y1, x2, y2);
4555
	fprintf(pd->pdffp, "%.2f %.2f m %.2f %.2f l S\n", x1, y1, x2, y2);
3265
    }
4556
    }
Line 3271... Line 4562...
3271
{
4562
{
3272
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
4563
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3273
    double xx, yy;
4564
    double xx, yy;
3274
    int i, code;
4565
    int i, code;
3275
 
4566
 
-
 
4567
    /*
3276
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
4568
     * Only try to do real transparency if version at least 1.4
3277
 
4569
     */
-
 
4570
    if ((semiTransparent(gc->col) ||
-
 
4571
	 semiTransparent(gc->fill)) &&
3278
    if (code) {
4572
	alphaVersion(pd)) {
3279
	if(pd->inText) textoff(pd);
4573
	if(pd->inText) textoff(pd);
3280
	if(code & 2)
-
 
3281
	    PDF_SetFill(gc->fill, dd);
4574
	PDF_SetFill(gc->fill, dd);
3282
	if(code & 1) {
-
 
3283
	    PDF_SetLineColor(gc->col, dd);
4575
	PDF_SetLineColor(gc->col, dd);
3284
	    PDF_SetLineStyle(gc->lty, gc->lwd, dd);
4576
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3285
	}
-
 
3286
	xx = x[0];
4577
	xx = x[0];
3287
	yy = y[0];
4578
	yy = y[0];
3288
	fprintf(pd->pdffp, "  %.2f %.2f m\n", xx, yy);
4579
	fprintf(pd->pdffp, "  %.2f %.2f m\n", xx, yy);
3289
	for(i = 1 ; i < n ; i++) {
4580
	for(i = 1 ; i < n ; i++) {
3290
	    xx = x[i];
4581
	    xx = x[i];
3291
	    yy = y[i];
4582
	    yy = y[i];
3292
	    fprintf(pd->pdffp, "  %.2f %.2f l\n", xx, yy);
4583
	    fprintf(pd->pdffp, "  %.2f %.2f l\n", xx, yy);
3293
	}
4584
	}
-
 
4585
	fprintf(pd->pdffp, "b\n"); 
-
 
4586
    } else {
-
 
4587
	code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
-
 
4588
	if (code) {
-
 
4589
	    if(pd->inText) textoff(pd);
-
 
4590
	    if(code & 2)
-
 
4591
		PDF_SetFill(gc->fill, dd);
-
 
4592
	    if(code & 1) {
-
 
4593
		PDF_SetLineColor(gc->col, dd);
-
 
4594
		PDF_SetLineStyle(gc->lty, gc->lwd, dd);
-
 
4595
	    }
-
 
4596
	    xx = x[0];
-
 
4597
	    yy = y[0];
-
 
4598
	    fprintf(pd->pdffp, "  %.2f %.2f m\n", xx, yy);
-
 
4599
	    for(i = 1 ; i < n ; i++) {
-
 
4600
		xx = x[i];
-
 
4601
		yy = y[i];
-
 
4602
		fprintf(pd->pdffp, "  %.2f %.2f l\n", xx, yy);
-
 
4603
	    }
3294
	switch(code){
4604
	    switch(code){
3295
	case 1: fprintf(pd->pdffp, "s\n"); break;
4605
	    case 1: fprintf(pd->pdffp, "s\n"); break;
3296
	case 2: fprintf(pd->pdffp, "h f\n"); break;
4606
	    case 2: fprintf(pd->pdffp, "h f\n"); break;
3297
	case 3: fprintf(pd->pdffp, "b\n"); break;
4607
	    case 3: fprintf(pd->pdffp, "b\n"); break;
-
 
4608
	    }
3298
	}
4609
	}
3299
    }
4610
    }
3300
 
-
 
3301
}
4611
}
3302
 
4612
 
3303
static void PDF_Polyline(int n, double *x, double *y,
4613
static void PDF_Polyline(int n, double *x, double *y,
3304
			 R_GE_gcontext *gc,
4614
			 R_GE_gcontext *gc,
3305
			 NewDevDesc *dd)
4615
			 NewDevDesc *dd)
3306
{
4616
{
3307
    PDFDesc *pd = (PDFDesc*) dd->deviceSpecific;
4617
    PDFDesc *pd = (PDFDesc*) dd->deviceSpecific;
3308
    double xx, yy;
4618
    double xx, yy;
3309
    int i;
4619
    int i;
3310
 
4620
 
-
 
4621
    /*
-
 
4622
     * Only try to do real transparency if version at least 1.4
-
 
4623
     */
3311
    if(pd->inText) textoff(pd);
4624
    if ((semiTransparent(gc->col) ||
3312
    if(R_ALPHA(gc->col) == 0) {
4625
	 semiTransparent(gc->fill)) &&
-
 
4626
	alphaVersion(pd)) {
-
 
4627
	if(pd->inText) textoff(pd);
3313
	PDF_SetLineColor(gc->col, dd);
4628
	PDF_SetLineColor(gc->col, dd);
3314
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
4629
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3315
	xx = x[0];
4630
	xx = x[0];
3316
	yy = y[0];
4631
	yy = y[0];
3317
	fprintf(pd->pdffp, "%.2f %.2f m\n", xx, yy);
4632
	fprintf(pd->pdffp, "%.2f %.2f m\n", xx, yy);
Line 3319... Line 4634...
3319
	    xx = x[i];
4634
	    xx = x[i];
3320
	    yy = y[i];
4635
	    yy = y[i];
3321
	    fprintf(pd->pdffp, "%.2f %.2f l\n", xx, yy);
4636
	    fprintf(pd->pdffp, "%.2f %.2f l\n", xx, yy);
3322
	}
4637
	}
3323
	fprintf(pd->pdffp, "S\n");
4638
	fprintf(pd->pdffp, "S\n");
-
 
4639
    } else {
-
 
4640
	if(pd->inText) textoff(pd);
-
 
4641
	if(R_ALPHA(gc->col) == 0) {
-
 
4642
	    PDF_SetLineColor(gc->col, dd);
-
 
4643
	    PDF_SetLineStyle(gc->lty, gc->lwd, dd);
-
 
4644
	    xx = x[0];
-
 
4645
	    yy = y[0];
-
 
4646
	    fprintf(pd->pdffp, "%.2f %.2f m\n", xx, yy);
-
 
4647
	    for(i = 1 ; i < n ; i++) {
-
 
4648
		xx = x[i];
-
 
4649
		yy = y[i];
-
 
4650
		fprintf(pd->pdffp, "%.2f %.2f l\n", xx, yy);
-
 
4651
	    }
-
 
4652
	    fprintf(pd->pdffp, "S\n");
-
 
4653
	}
3324
    }
4654
    }
3325
}
4655
}
3326
 
4656
 
-
 
4657
static int PDFfontNumber(char *family, int face, PDFDesc *pd) 
-
 
4658
{
-
 
4659
    /* DingBats is font 1 */
-
 
4660
    int num = 1 + face;
-
 
4661
    
-
 
4662
    if (strlen(family) > 0) {
-
 
4663
	int fontIndex;
-
 
4664
	/* 
-
 
4665
	 * Try to find font in already loaded fonts 
-
 
4666
	 */
-
 
4667
	type1fontfamily fontfamily = findDeviceFont(family, pd->fonts, 
-
 
4668
						    &fontIndex);
-
 
4669
	if (fontfamily)
-
 
4670
	    num = (fontIndex - 1)*5 + 1 + face;
-
 
4671
	else {
-
 
4672
	    /*
-
 
4673
	     * Try to load the font
-
 
4674
	     */
-
 
4675
	    fontfamily = addFont(family, 1);
-
 
4676
	    if (fontfamily) {
-
 
4677
		if (addPDFfont(fontfamily, pd, &fontIndex)) {
-
 
4678
		    num = (fontIndex - 1)*5 + 1 + face;
-
 
4679
		} else {
-
 
4680
		    fontfamily = NULL;
-
 
4681
		}
-
 
4682
	    }
-
 
4683
	}
-
 
4684
	if (!fontfamily)
-
 
4685
	    error("Failed to find or load PDF font");
-
 
4686
    } 
-
 
4687
    return num;
-
 
4688
}
3327
 
4689
 
3328
static void PDF_Text(double x, double y, char *str,
4690
static void PDF_Text(double x, double y, char *str,
3329
		     double rot, double hadj,
4691
		     double rot, double hadj,
3330
		     R_GE_gcontext *gc,
4692
		     R_GE_gcontext *gc,
3331
		     NewDevDesc *dd)
4693
		     NewDevDesc *dd)
Line 3341... Line 4703...
3341
    }
4703
    }
3342
    rot1 = rot * DEG2RAD;
4704
    rot1 = rot * DEG2RAD;
3343
    a = size * cos(rot1);
4705
    a = size * cos(rot1);
3344
    b = size * sin(rot1);
4706
    b = size * sin(rot1);
3345
    if(!pd->inText) texton(pd);
4707
    if(!pd->inText) texton(pd);
-
 
4708
    /*
-
 
4709
     * Only try to do real transparency if version at least 1.4
-
 
4710
     */
-
 
4711
    if ((pd->versionMajor >= 1 && pd->versionMinor >= 4) || 
3346
    if(R_ALPHA(gc->col) == 0) {
4712
	(R_ALPHA(gc->col) == 0)) {
3347
	PDF_SetFill(gc->col, dd);
4713
	PDF_SetFill(gc->col, dd);
3348
	fprintf(pd->pdffp, "/F%d 1 Tf %.2f %.2f %.2f %.2f %.2f %.2f Tm ",
4714
	fprintf(pd->pdffp, "/F%d 1 Tf %.2f %.2f %.2f %.2f %.2f %.2f Tm ",
-
 
4715
		PDFfontNumber(gc->fontfamily, face, pd), 
3349
		face, a, b, -b, a, x, y);
4716
		a, b, -b, a, x, y);
3350
	PostScriptWriteString(pd->pdffp, str);
4717
	PostScriptWriteString(pd->pdffp, str);
3351
	fprintf(pd->pdffp, " Tj\n");
4718
	fprintf(pd->pdffp, " Tj\n");
3352
    }
4719
    }
3353
}
4720
}
3354
 
4721
 
Line 3363... Line 4730...
3363
 
4730
 
3364
static void PDF_Hold(NewDevDesc *dd)
4731
static void PDF_Hold(NewDevDesc *dd)
3365
{
4732
{
3366
}
4733
}
3367
 
4734
 
-
 
4735
static FontMetricInfo *PDFmetricInfo(char *family, int face,
-
 
4736
				     PDFDesc *pd) 
-
 
4737
{
-
 
4738
    FontMetricInfo *result = &(pd->fonts->family->fonts[face-1]->metrics);
-
 
4739
    if (strlen(family) > 0) {
-
 
4740
	int dontcare;
-
 
4741
	/*
-
 
4742
	 * Find the family in pd->fonts
-
 
4743
	 */
-
 
4744
	type1fontfamily fontfamily = findDeviceFont(family, pd->fonts,
-
 
4745
						    &dontcare);
-
 
4746
	if (fontfamily)
-
 
4747
	    result = &(fontfamily->fonts[face-1]->metrics);
-
 
4748
	else {
-
 
4749
	    /*
-
 
4750
	     * Try to load the font
-
 
4751
	     */
-
 
4752
	    fontfamily = addFont(family, 1);
-
 
4753
	    if (fontfamily) {
-
 
4754
		if (addPDFfont(fontfamily, pd, &dontcare)) {
-
 
4755
		    result = &(fontfamily->fonts[face-1]->metrics);
-
 
4756
		} else {
-
 
4757
		    fontfamily = NULL;
-
 
4758
		}
-
 
4759
	    }
-
 
4760
	}
-
 
4761
	if (!fontfamily)
-
 
4762
	    error("Failed to find or load PDF font");
-
 
4763
    }
-
 
4764
    return result;
-
 
4765
}
-
 
4766
 
3368
static double PDF_StrWidth(char *str,
4767
static double PDF_StrWidth(char *str,
3369
			   R_GE_gcontext *gc,
4768
			   R_GE_gcontext *gc,
3370
			   NewDevDesc *dd)
4769
			   NewDevDesc *dd)
3371
{
4770
{
3372
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
4771
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3373
 
4772
 
3374
    if(gc->fontface < 1 || gc->fontface > 5) gc->fontface = 1;
4773
    if(gc->fontface < 1 || gc->fontface > 5) gc->fontface = 1;
3375
    return floor(gc->cex * gc->ps + 0.5) *
4774
    return floor(gc->cex * gc->ps + 0.5) *
3376
	PostScriptStringWidth((unsigned char *)str,
4775
	PostScriptStringWidth((unsigned char *)str,
3377
			      &(pd->metrics[gc->fontface-1]));
4776
			      PDFmetricInfo(gc->fontfamily, 
-
 
4777
					    gc->fontface, pd));
3378
}
4778
}
3379
 
4779
 
3380
static void PDF_MetricInfo(int c, 
4780
static void PDF_MetricInfo(int c, 
3381
			   R_GE_gcontext *gc,
4781
			   R_GE_gcontext *gc,
3382
			   double* ascent, double* descent,
4782
			   double* ascent, double* descent,
Line 3384... Line 4784...
3384
{
4784
{
3385
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
4785
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3386
 
4786
 
3387
    if(gc->fontface < 1 || gc->fontface > 5) gc->fontface = 1;
4787
    if(gc->fontface < 1 || gc->fontface > 5) gc->fontface = 1;
3388
    PostScriptMetricInfo(c, ascent, descent, width,
4788
    PostScriptMetricInfo(c, ascent, descent, width,
3389
			 &(pd->metrics[gc->fontface-1]));
4789
			 PDFmetricInfo(gc->fontfamily, 
-
 
4790
				       gc->fontface, pd));
3390
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
4791
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
3391
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
4792
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
3392
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
4793
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
3393
}
4794
}