1 /* Copyright (C) 2000-2008 by George Williams */
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <sys/types.h>
44 char *TTFFoundry
=NULL
;
46 /* This file produces a ttf file given a splinefont. */
48 /* ************************************************************************** */
53 hhea horizontal metrics header data
54 hmtx horizontal metrics (widths, lsidebearing)
55 maxp various maxima in the font
56 name various names associated with the font
57 post postscript names and other stuff
58 Required by windows but not mac
61 loca pointers to the glyphs
63 Required for OpenType (Postscript)
64 CFF A complete postscript CFF font here with all its internal tables
67 bloc/EBLC pointers to bitmaps
68 bhed for apple bitmap only fonts, replaces head
70 EBSC bitmap scaling table (used in windows "bitmap-only" fonts)
72 GPOS (opentype, if kern,anchor data are present)
73 GSUB (opentype, if ligature (other subs) data are present)
74 GDEF (opentype, if anchor data are present)
76 MATH (MS proposal, if math data present)
79 gasp to control when things should be hinted
80 fpgm for hinting (currently only copied and dumped verbatim)
81 prep for hinting (currently only copied and dumped verbatim)
85 TeX TeX specific info (stuff that used to live in tfm files)
88 const char *ttfstandardnames
[258] = {
350 void putshort(FILE *file
,int sval
) {
351 putc((sval
>>8)&0xff,file
);
352 putc(sval
&0xff,file
);
355 void putlong(FILE *file
,int val
) {
356 putc((val
>>24)&0xff,file
);
357 putc((val
>>16)&0xff,file
);
358 putc((val
>>8)&0xff,file
);
361 #define dumpabsoffset putlong
363 static void dumpoffset(FILE *file
,int offsize
,int val
) {
366 else if ( offsize
==2 )
368 else if ( offsize
==3 ) {
369 putc((val
>>16)&0xff,file
);
370 putc((val
>>8)&0xff,file
);
376 void putfixed(FILE *file
,real dval
) {
381 mant
= floor(65536.*(dval
-val
));
382 val
= (val
<<16) | mant
;
386 int ttfcopyfile(FILE *ttf
, FILE *other
, int pos
, char *tab_name
) {
390 if ( ferror(ttf
) || ferror(other
)) {
391 IError("Disk error of some nature. Perhaps no space on device?\nGenerated font will be unusable" );
392 } else if ( pos
!=ftell(ttf
)) {
393 IError("File Offset wrong for ttf table (%s), %d expected %d", tab_name
, ftell(ttf
), pos
);
396 while (( ch
= getc(other
))!=EOF
)
398 if ( ferror(other
)) ret
= 0;
399 if ( fclose(other
)) ret
= 0;
403 static void FigureFullMetricsEnd(SplineFont
*sf
,struct glyphinfo
*gi
, int istt
) {
404 /* We can reduce the size of the width array by removing a run at the end */
405 /* of the same width. So start at the end, find the width of the last */
406 /* character we'll output, then run backwards as long as we've got the */
408 /* (do same thing for vertical metrics too */
409 int i
, lasti
, lastv
, lastdefault
= istt
? 3 : 1;
412 lasti
= lastv
= gi
->gcnt
-1;
413 for ( i
=gi
->gcnt
-1; i
>lastdefault
&& gi
->bygid
[i
]==-1; --i
);
414 if ( i
>=lastdefault
) {
415 width
= sf
->glyphs
[gi
->bygid
[i
]]->width
;
416 vwidth
= sf
->glyphs
[gi
->bygid
[i
]]->vwidth
;
418 for ( i
=lasti
-1; i
>=lastdefault
; --i
) {
419 if ( SCWorthOutputting(sf
->glyphs
[gi
->bygid
[i
]]) ) {
420 if ( sf
->glyphs
[gi
->bygid
[i
]]->width
!=width
)
426 gi
->lasthwidth
= lasti
;
427 if ( sf
->hasvmetrics
) {
428 for ( i
=lastv
-1; i
>=lastdefault
; --i
) {
429 if ( SCWorthOutputting(sf
->glyphs
[gi
->bygid
[i
]]) ) {
430 if ( sf
->glyphs
[gi
->bygid
[i
]]->vwidth
!=vwidth
)
436 gi
->lastvwidth
= lastv
;
452 int RefDepth(RefChar
*ref
,int layer
) {
454 SplineChar
*sc
= ref
->sc
;
456 if ( sc
->layers
[layer
].refs
==NULL
|| sc
->layers
[layer
].splines
!=NULL
)
459 for ( ref
= sc
->layers
[layer
].refs
; ref
!=NULL
; ref
=ref
->next
) {
460 if ( ref
->transform
[0]>=-2 || ref
->transform
[0]<=1.999939 ||
461 ref
->transform
[1]>=-2 || ref
->transform
[1]<=1.999939 ||
462 ref
->transform
[2]>=-2 || ref
->transform
[2]<=1.999939 ||
463 ref
->transform
[3]>=-2 || ref
->transform
[3]<=1.999939 ) {
464 temp
= RefDepth(ref
,layer
);
465 if ( temp
>rd
) rd
= temp
;
471 void SFDummyUpCIDs(struct glyphinfo
*gi
,SplineFont
*sf
) {
476 for ( k
=0; k
<sf
->subfontcnt
; ++k
)
477 if ( sf
->subfonts
[k
]->glyphcnt
>max
) max
= sf
->subfonts
[k
]->glyphcnt
;
481 sf
->glyphs
= gcalloc(max
,sizeof(SplineChar
*));
482 sf
->glyphcnt
= sf
->glyphmax
= max
;
484 for ( k
=0; k
<sf
->subfontcnt
; ++k
)
485 for ( i
=0; i
<sf
->subfonts
[k
]->glyphcnt
; ++i
) if ( sf
->subfonts
[k
]->glyphs
[i
]!=NULL
)
486 sf
->glyphs
[i
] = sf
->subfonts
[k
]->glyphs
[i
];
491 bygid
= galloc((sf
->glyphcnt
+3)*sizeof(int));
492 memset(bygid
,0xff, (sf
->glyphcnt
+3)*sizeof(int));
495 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
) {
496 if ( bygid
[0]== -1 && strcmp(sf
->glyphs
[i
]->name
,".notdef")==0 ) {
497 sf
->glyphs
[i
]->ttf_glyph
= 0;
499 } else if ( SCWorthOutputting(sf
->glyphs
[i
])) {
500 sf
->glyphs
[i
]->ttf_glyph
= j
;
508 static void AssignNotdefNull(SplineFont
*sf
,int *bygid
, int iscff
) {
511 /* The first three glyphs are magic, glyph 0 is .notdef */
512 /* glyph 1 is .null and glyph 2 is nonmarking return */
513 /* We may generate them automagically */
515 bygid
[0] = bygid
[1] = bygid
[2] = -1;
516 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
) {
517 if ( bygid
[0]== -1 && strcmp(sf
->glyphs
[i
]->name
,".notdef")==0 ) {
518 sf
->glyphs
[i
]->ttf_glyph
= 0;
520 } else if ( !iscff
&& bygid
[1]== -1 &&
521 (strcmp(sf
->glyphs
[i
]->name
,".null")==0 ||
522 strcmp(sf
->glyphs
[i
]->name
,"uni0000")==0 ||
523 (i
==1 && strcmp(sf
->glyphs
[1]->name
,"glyph1")==0)) ) {
524 sf
->glyphs
[i
]->ttf_glyph
= 1;
526 } else if ( !iscff
&& bygid
[2]== -1 &&
527 (strcmp(sf
->glyphs
[i
]->name
,"nonmarkingreturn")==0 ||
528 strcmp(sf
->glyphs
[i
]->name
,"uni000D")==0 ||
529 (i
==2 && strcmp(sf
->glyphs
[2]->name
,"glyph2")==0)) ) {
530 sf
->glyphs
[i
]->ttf_glyph
= 2;
536 static int AssignTTFGlyph(struct glyphinfo
*gi
,SplineFont
*sf
,EncMap
*map
,int iscff
) {
537 int *bygid
= galloc((sf
->glyphcnt
+3)*sizeof(int));
540 memset(bygid
,0xff, (sf
->glyphcnt
+3)*sizeof(int));
542 AssignNotdefNull(sf
,bygid
,iscff
);
545 for ( i
=0; i
<map
->enccount
; ++i
) if ( map
->map
[i
]!=-1 ) {
546 SplineChar
*sc
= sf
->glyphs
[map
->map
[i
]];
547 if ( SCWorthOutputting(sc
) && sc
->ttf_glyph
==-1
549 && (!iscff
|| !sc
->compositionunit
)
553 bygid
[j
++] = sc
->orig_pos
;
557 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
) {
558 SplineChar
*sc
= sf
->glyphs
[i
];
559 if ( SCWorthOutputting(sc
) && sc
->ttf_glyph
==-1
561 && (!iscff
|| !sc
->compositionunit
)
573 /* Standard names for cff */
574 extern const char *cffnames
[];
575 extern const int nStdStrings
;
577 static int storesid(struct alltabs
*at
,char *str
) {
583 if ( str
!=NULL
) { /* NULL is the magic string at end of array */
584 for ( i
=0; cffnames
[i
]!=NULL
; ++i
) {
585 if ( strcmp(cffnames
[i
],str
)==0 )
590 pos
= ftell(at
->sidf
)+1;
591 if ( pos
>=65536 && !at
->sidlongoffset
) {
592 at
->sidlongoffset
= true;
595 for ( i
=0; i
<at
->sidcnt
; ++i
)
596 putlong(news
,getushort(at
->sidh
));
600 if ( at
->sidlongoffset
)
601 putlong(at
->sidh
,pos
);
603 putshort(at
->sidh
,pos
);
606 for ( pt
=str
; *pt
; ++pt
)
609 return( at
->sidcnt
++ + nStdStrings
);
612 static void dumpint(FILE *cfff
,int num
) {
614 if ( num
>=-107 && num
<=107 )
616 else if ( num
>=108 && num
<=1131 ) {
618 putc((num
>>8)+247,cfff
);
620 } else if ( num
>=-1131 && num
<=-108 ) {
623 putc((num
>>8)+251,cfff
);
625 } else if ( num
>=-32768 && num
<32768 ) {
629 } else { /* In dict data we have 4 byte ints, in type2 strings we don't */
631 putc((num
>>24)&0xff,cfff
);
632 putc((num
>>16)&0xff,cfff
);
633 putc((num
>>8)&0xff,cfff
);
638 static void dumpdbl(FILE *cfff
,double d
) {
639 if ( d
-rint(d
)>-.00001 && d
-rint(d
)<.00001 )
640 dumpint(cfff
,(int) d
);
642 /* The type2 strings have a fixed format, but the dict data does not */
643 char buffer
[20], *pt
;
645 sprintf( buffer
, "%g", d
);
647 putc(30,cfff
); /* Start a double */
648 for ( pt
=buffer
; *pt
; ++pt
) {
655 else if (( *pt
=='E' || *pt
=='e') && pt
[1]=='-' ) {
658 } else if ( *pt
=='E' || *pt
=='e')
661 n
= 0; /* Should never happen */
674 putc(sofar
|0xf,cfff
);
678 static void dumpoper(FILE *cfff
,int oper
) {
682 putc(oper
&0xff,cfff
);
686 static void dumpdbloper(FILE *cfff
,double d
, int oper
) {
691 static void dumpintoper(FILE *cfff
,int v
, int oper
) {
696 static void dumpsizedint(FILE *cfff
,int big
,int num
, int oper
) {
699 putc((num
>>24)&0xff,cfff
);
700 putc((num
>>16)&0xff,cfff
);
701 putc((num
>>8)&0xff,cfff
);
711 static void dumpsid(FILE *cfff
,struct alltabs
*at
,char *str
,int oper
) {
714 dumpint(cfff
,storesid(at
,str
));
718 static void DumpStrDouble(char *pt
,FILE *cfff
,int oper
) {
720 if ( *pt
=='[' ) ++pt
; /* For StdHW, StdVW */
722 dumpdbloper(cfff
,d
,oper
);
725 static void DumpDblArray(real
*arr
,int n
,FILE *cfff
, int oper
) {
728 for ( mi
=n
-1; mi
>=0 && arr
[mi
]==0; --mi
);
731 dumpdbl(cfff
,arr
[0]);
732 for ( i
=1; i
<=mi
; ++i
)
733 dumpdbl(cfff
,arr
[i
]-arr
[i
-1]);
737 static void DumpStrArray(char *pt
,FILE *cfff
,int oper
) {
741 while ( *pt
==' ' ) ++pt
;
744 if ( *pt
=='[' ) ++pt
;
745 while ( *pt
==' ' ) ++pt
;
746 while ( *pt
!=']' && *pt
!='\0' ) {
748 if ( pt
==end
) /* User screwed up. Should be a number */
750 dumpdbl(cfff
,d
-last
);
753 while ( *pt
==' ' ) ++pt
;
758 static void dumpcffheader(SplineFont
*sf
,FILE *cfff
) {
759 putc('\1',cfff
); /* Major version: 1 */
760 putc('\0',cfff
); /* Minor version: 0 */
761 putc('\4',cfff
); /* Header size in bytes */
762 putc('\4',cfff
); /* Absolute Offset size. */
763 /* I don't think there are any absolute offsets that aren't encoded */
764 /* in a dict as numbers (ie. inherently variable sized items) */
767 static void dumpcffnames(SplineFont
*sf
,FILE *cfff
) {
770 putshort(cfff
,1); /* One font name */
771 putc('\1',cfff
); /* Offset size */
772 putc('\1',cfff
); /* Offset to first name */
773 putc('\1'+strlen(sf
->fontname
),cfff
);
774 for ( pt
=sf
->fontname
; *pt
; ++pt
)
778 static void dumpcffcharset(SplineFont
*sf
,struct alltabs
*at
) {
781 at
->gn_sid
= gcalloc(at
->gi
.gcnt
,sizeof(uint32
));
783 /* I always use a format 0 charset. ie. an array of SIDs in random order */
785 /* First element must be ".notdef" and is omitted */
787 for ( i
=1; i
<at
->gi
.gcnt
; ++i
)
788 if ( at
->gi
.bygid
[i
]!=-1 && SCWorthOutputting(sf
->glyphs
[at
->gi
.bygid
[i
]])) {
789 at
->gn_sid
[i
] = storesid(at
,sf
->glyphs
[at
->gi
.bygid
[i
]]->name
);
790 putshort(at
->charset
,at
->gn_sid
[i
]);
794 static void dumpcffcidset(SplineFont
*sf
,struct alltabs
*at
) {
799 start
= -1; /* Glyph 0 always maps to CID 0, and is omitted */
800 for ( gid
= 1; gid
<at
->gi
.gcnt
; ++gid
) {
803 else if ( at
->gi
.bygid
[gid
]-at
->gi
.bygid
[start
]!=gid
-start
) {
804 putshort(at
->charset
,at
->gi
.bygid
[start
]);
805 putshort(at
->charset
,at
->gi
.bygid
[gid
-1]-at
->gi
.bygid
[start
]);
810 putshort(at
->charset
,at
->gi
.bygid
[start
]);
811 putshort(at
->charset
,at
->gi
.bygid
[gid
-1]-at
->gi
.bygid
[start
]);
815 static void dumpcfffdselect(SplineFont
*sf
,struct alltabs
*at
) {
816 int cid
, k
, lastfd
, cnt
;
819 putc(3,at
->fdselect
);
820 putshort(at
->fdselect
,0); /* number of ranges, fill in later */
822 for ( k
=0; k
<sf
->subfontcnt
; ++k
)
823 if ( SCWorthOutputting(sf
->subfonts
[k
]->glyphs
[0]))
825 if ( k
==sf
->subfontcnt
) --k
; /* If CID 0 not defined, put it in last font */
826 putshort(at
->fdselect
,0);
827 putc(k
,at
->fdselect
);
830 for ( gid
= 1; gid
<at
->gi
.gcnt
; ++gid
) {
831 cid
= at
->gi
.bygid
[gid
];
832 for ( k
=0; k
<sf
->subfontcnt
; ++k
) {
833 if ( cid
<sf
->subfonts
[k
]->glyphcnt
&&
834 SCWorthOutputting(sf
->subfonts
[k
]->glyphs
[cid
]) )
837 if ( k
==sf
->subfontcnt
)
838 /* Doesn't map to a glyph, irrelevant */;
841 putshort(at
->fdselect
,gid
);
842 putc(k
,at
->fdselect
);
848 putshort(at
->fdselect
,gid
);
849 fseek(at
->fdselect
,1,SEEK_SET
);
850 putshort(at
->fdselect
,cnt
);
851 fseek(at
->fdselect
,0,SEEK_END
);
854 static void dumpcffencoding(SplineFont
*sf
,struct alltabs
*at
) {
856 uint32 start_pos
= ftell(at
->encoding
);
858 EncMap
*map
= at
->map
;
860 putc(0,at
->encoding
);
861 /* I always use a format 0 encoding. ie. an array of glyph indexes */
862 putc(0xff,at
->encoding
); /* fixup later */
864 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
)
865 sf
->glyphs
[i
]->ticked
= false;
869 for ( i
=0; i
<256 && i
<map
->enccount
; ++i
) if ( map
->map
[i
]!=-1 && (sc
=sf
->glyphs
[map
->map
[i
]])!=NULL
) {
870 if ( sc
->ttf_glyph
>255 )
874 } else if ( sc
->ttf_glyph
>0 ) {
877 putc(i
,at
->encoding
);
883 fseek(at
->encoding
,start_pos
,SEEK_SET
);
884 putc(0x80,at
->encoding
);
885 putc(cnt
,at
->encoding
);
886 fseek(at
->encoding
,0,SEEK_END
);
887 putc(anydups
,at
->encoding
);
889 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
)
890 sf
->glyphs
[i
]->ticked
= false;
891 for ( i
=0; i
<256 && i
<map
->enccount
; ++i
) if ( map
->map
[i
]!=-1 && (sc
=sf
->glyphs
[map
->map
[i
]])!=NULL
) {
892 if ( sc
->ttf_glyph
>255 )
895 putc(i
,at
->encoding
);
896 putshort(at
->encoding
,at
->gn_sid
[sc
->ttf_glyph
]);
901 fseek(at
->encoding
,start_pos
+1,SEEK_SET
);
902 putc(cnt
,at
->encoding
);
903 fseek(at
->encoding
,0,SEEK_END
);
909 static void _dumpcffstrings(FILE *file
, struct pschars
*strs
) {
912 /* First figure out the offset size */
914 for ( i
=0; i
<strs
->next
; ++i
)
915 len
+= strs
->lens
[i
];
917 /* Then output the index size and offsets */
918 putshort( file
, strs
->next
);
919 if ( strs
->next
!=0 ) {
920 /* presumably offsets are unsigned. But the docs don't state this in the obvious place */
921 offsize
= len
<=255?1:len
<=65535?2:len
<=0xffffff?3:4;
924 for ( i
=0; i
<strs
->next
; ++i
) {
925 dumpoffset(file
,offsize
,len
);
926 len
+= strs
->lens
[i
];
928 dumpoffset(file
,offsize
,len
);
930 /* last of all the strings */
931 for ( i
=0; i
<strs
->next
; ++i
) {
932 uint8
*pt
= strs
->values
[i
], *end
= pt
+strs
->lens
[i
];
939 static FILE *dumpcffstrings(struct pschars
*strs
) {
940 FILE *file
= tmpfile();
941 _dumpcffstrings(file
,strs
);
946 int SFFigureDefWidth(SplineFont
*sf
, int *_nomwid
) {
947 uint16
*widths
; uint32
*cumwid
;
948 int nomwid
, defwid
, i
, sameval
=(int) 0x80000000, maxw
=0, allsame
=true;
951 for ( i
=0; i
<sf
->glyphcnt
; ++i
)
952 if ( SCWorthOutputting(sf
->glyphs
[i
]) ) {
953 if ( maxw
<sf
->glyphs
[i
]->width
) maxw
= sf
->glyphs
[i
]->width
;
954 if ( sameval
== 0x8000000 )
955 sameval
= sf
->glyphs
[i
]->width
;
956 else if ( sameval
!=sf
->glyphs
[i
]->width
)
960 nomwid
= defwid
= sameval
;
963 if ( maxw
>65535 ) maxw
= 3*(sf
->ascent
+sf
->descent
);
964 widths
= gcalloc(maxw
,sizeof(uint16
));
965 cumwid
= gcalloc(maxw
,sizeof(uint32
));
967 for ( i
=0; i
<sf
->glyphcnt
; ++i
)
968 if ( SCWorthOutputting(sf
->glyphs
[i
]) &&
969 sf
->glyphs
[i
]->width
>=0 &&
970 sf
->glyphs
[i
]->width
<maxw
)
971 if ( ++widths
[sf
->glyphs
[i
]->width
] > cnt
) {
972 defwid
= sf
->glyphs
[i
]->width
;
973 cnt
= widths
[defwid
];
976 for ( i
=0; i
<maxw
; ++i
)
977 for ( j
=-107; j
<=107; ++j
)
978 if ( i
+j
>=0 && i
+j
<maxw
)
979 cumwid
[i
] += widths
[i
+j
];
981 for ( i
=0; i
<maxw
; ++i
)
982 if ( cnt
<cumwid
[i
] ) {
986 free(widths
); free(cumwid
);
993 static void ATFigureDefWidth(SplineFont
*sf
, struct alltabs
*at
, int subfont
) {
996 defwid
= SFFigureDefWidth(sf
,&nomwid
);
1000 at
->fds
[subfont
].defwid
= defwid
;
1002 at
->nomwid
= nomwid
;
1004 at
->fds
[subfont
].nomwid
= nomwid
;
1007 static void dumpcffprivate(SplineFont
*sf
,struct alltabs
*at
,int subfont
,
1010 FILE *private = subfont
==-1?at
->private:at
->fds
[subfont
].private;
1012 real bluevalues
[14], otherblues
[10];
1014 real stemsnaph
[12], stemsnapv
[12];
1015 real stdhw
[1], stdvw
[1];
1016 int hasblue
=0, hash
=0, hasv
=0, bs
;
1018 EncMap
*map
= at
->map
;
1021 /* The private dict is not in an index, so no index header. Just the data */
1024 defwid
= at
->defwid
;
1026 defwid
= at
->fds
[subfont
].defwid
;
1027 dumpintoper(private,defwid
,20); /* Default Width */
1029 nomwid
= at
->nomwid
;
1031 nomwid
= at
->fds
[subfont
].nomwid
;
1032 dumpintoper(private,nomwid
,21); /* Nominative Width */
1034 bs
= SplineFontIsFlexible(sf
,at
->gi
.layer
,at
->gi
.flags
);
1035 hasblue
= PSDictHasEntry(sf
->private,"BlueValues")!=NULL
;
1036 hash
= PSDictHasEntry(sf
->private,"StdHW")!=NULL
;
1037 hasv
= PSDictHasEntry(sf
->private,"StdVW")!=NULL
;
1038 ff_progress_change_stages(2+autohint_before_generate
+!hasblue
);
1040 otherblues
[0] = otherblues
[1] = bluevalues
[0] = bluevalues
[1] = 0;
1042 FindBlues(sf
,at
->gi
.layer
,bluevalues
,otherblues
);
1043 ff_progress_next_stage();
1046 stdhw
[0] = stdvw
[0] = 0;
1048 FindHStems(sf
,stemsnaph
,snapcnt
);
1050 for ( i
=0; stemsnaph
[i
]!=0 && i
<12; ++i
)
1051 if ( mi
==-1 ) mi
= i
;
1052 else if ( snapcnt
[i
]>snapcnt
[mi
] ) mi
= i
;
1053 if ( mi
!=-1 ) stdhw
[0] = stemsnaph
[mi
];
1057 FindVStems(sf
,stemsnapv
,snapcnt
);
1059 for ( i
=0; stemsnapv
[i
]!=0 && i
<12; ++i
)
1060 if ( mi
==-1 ) mi
= i
;
1061 else if ( snapcnt
[i
]>snapcnt
[mi
] ) mi
= i
;
1062 if ( mi
!=-1 ) stdvw
[0] = stemsnapv
[mi
];
1064 ff_progress_change_line1(_("Saving OpenType Font"));
1067 DumpStrArray(PSDictHasEntry(sf
->private,"BlueValues"),private,6);
1069 DumpDblArray(bluevalues
,sizeof(bluevalues
)/sizeof(bluevalues
[0]),private,6);
1070 if ( (pt
=PSDictHasEntry(sf
->private,"OtherBlues"))!=NULL
)
1071 DumpStrArray(pt
,private,7);
1072 else if ( !hasblue
)
1073 DumpDblArray(otherblues
,sizeof(otherblues
)/sizeof(otherblues
[0]),private,7);
1074 if ( (pt
=PSDictHasEntry(sf
->private,"FamilyBlues"))!=NULL
)
1075 DumpStrArray(pt
,private,8);
1076 bluescale
= BlueScaleFigure(sf
->private,bluevalues
,otherblues
);
1077 if ( (pt
=PSDictHasEntry(sf
->private,"FamilyOtherBlues"))!=NULL
)
1078 DumpStrArray(pt
,private,9);
1079 if ( (pt
=PSDictHasEntry(sf
->private,"BlueScale"))!=NULL
)
1080 DumpStrDouble(pt
,private,(12<<8)+9);
1081 else if ( bluescale
!=-1 )
1082 dumpdbloper(private,bluescale
,(12<<8)+9);
1083 if ( (pt
=PSDictHasEntry(sf
->private,"BlueShift"))!=NULL
)
1084 DumpStrDouble(pt
,private,(12<<8)+10);
1086 dumpintoper(private,bs
,(12<<8)+10);
1087 if ( (pt
=PSDictHasEntry(sf
->private,"BlueFuzz"))!=NULL
)
1088 DumpStrDouble(pt
,private,(12<<8)+11);
1090 DumpStrDouble(PSDictHasEntry(sf
->private,"StdHW"),private,10);
1091 if ( (pt
=PSDictHasEntry(sf
->private,"StemSnapH"))!=NULL
)
1092 DumpStrArray(pt
,private,(12<<8)|12);
1095 dumpdbloper(private,stdhw
[0],10);
1096 DumpDblArray(stemsnaph
,sizeof(stemsnaph
)/sizeof(stemsnaph
[0]),private,(12<<8)|12);
1099 DumpStrDouble(PSDictHasEntry(sf
->private,"StdVW"),private,11);
1100 if ( (pt
=PSDictHasEntry(sf
->private,"StemSnapV"))!=NULL
)
1101 DumpStrArray(pt
,private,(12<<8)|13);
1104 dumpdbloper(private,stdvw
[0],11);
1105 DumpDblArray(stemsnapv
,sizeof(stemsnapv
)/sizeof(stemsnapv
[0]),private,(12<<8)|13);
1107 if ( (pt
=PSDictHasEntry(sf
->private,"ForceBold"))!=NULL
) {
1108 dumpintoper(private,*pt
=='t'||*pt
=='T',(12<<8)|14);
1109 } else if ( sf
->weight
!=NULL
&&
1110 (strstrmatch(sf
->weight
,"Bold")!=NULL
||
1111 strstrmatch(sf
->weight
,"Demi")!=NULL
||
1112 strstrmatch(sf
->weight
,"Fett")!=NULL
||
1113 strstrmatch(sf
->weight
,"Gras")!=NULL
||
1114 strstrmatch(sf
->weight
,"Heavy")!=NULL
||
1115 strstrmatch(sf
->weight
,"Black")!=NULL
))
1116 dumpintoper(private,1,(12<<8)|14);
1117 if ( (pt
=PSDictHasEntry(sf
->private,"LanguageGroup"))!=NULL
)
1118 DumpStrDouble(pt
,private,(12<<8)+17);
1119 else if ( map
->enc
->is_japanese
||
1120 map
->enc
->is_korean
||
1121 map
->enc
->is_tradchinese
||
1122 map
->enc
->is_simplechinese
)
1123 dumpintoper(private,1,(12<<8)|17);
1124 if ( (pt
=PSDictHasEntry(sf
->private,"ExpansionFactor"))!=NULL
)
1125 DumpStrDouble(pt
,private,(12<<8)+18);
1127 dumpsizedint(private,false,ftell(private)+3+1,19); /* Subrs */
1130 at
->privatelen
= ftell(private);
1132 at
->fds
[subfont
].privatelen
= ftell(private);
1135 /* When we exit this the topdict is not complete, we still need to fill in */
1136 /* values for charset,encoding,charstrings and private. Then we need to go */
1137 /* back and fill in the table length (at lenpos) */
1138 static void dumpcfftopdict(SplineFont
*sf
,struct alltabs
*at
) {
1140 FILE *cfff
= at
->cfff
;
1143 putshort(cfff
,1); /* One top dict */
1144 putc('\2',cfff
); /* Offset size */
1145 putshort(cfff
,1); /* Offset to topdict */
1146 at
->lenpos
= ftell(cfff
);
1147 putshort(cfff
,0); /* placeholder for final position (final offset in index points beyond last element) */
1148 dumpsid(cfff
,at
,sf
->version
,0);
1149 dumpsid(cfff
,at
,sf
->copyright
,1);
1150 dumpsid(cfff
,at
,sf
->fullname
?sf
->fullname
:sf
->fontname
,2);
1151 dumpsid(cfff
,at
,sf
->familyname
,3);
1152 dumpsid(cfff
,at
,sf
->weight
,4);
1153 if ( at
->gi
.fixed_width
!=-1 ) dumpintoper(cfff
,1,(12<<8)|1);
1154 if ( sf
->italicangle
!=0 ) dumpdbloper(cfff
,sf
->italicangle
,(12<<8)|2);
1155 if ( sf
->upos
!=-100 ) dumpdbloper(cfff
,sf
->upos
,(12<<8)|3);
1156 if ( sf
->uwidth
!=50 ) dumpdbloper(cfff
,sf
->uwidth
,(12<<8)|4);
1157 if ( sf
->strokedfont
) {
1158 dumpintoper(cfff
,2,(12<<8)|5);
1159 dumpdbloper(cfff
,sf
->strokewidth
,(12<<8)|8);
1161 /* We'll never set CharstringType */
1162 if ( sf
->ascent
+sf
->descent
!=1000 ) {
1163 dumpdbl(cfff
,1.0/(sf
->ascent
+sf
->descent
));
1166 dumpdbl(cfff
,1.0/(sf
->ascent
+sf
->descent
));
1168 dumpintoper(cfff
,0,(12<<8)|7);
1170 if ( sf
->uniqueid
!=-1 && sf
->use_uniqueid
)
1171 dumpintoper(cfff
, sf
->uniqueid
?sf
->uniqueid
:4000000 + (rand()&0x3ffff), 13 );
1172 SplineFontLayerFindBounds(sf
,at
->gi
.layer
,&b
);
1173 at
->gi
.xmin
= b
.minx
;
1174 at
->gi
.ymin
= b
.miny
;
1175 at
->gi
.xmax
= b
.maxx
;
1176 at
->gi
.ymax
= b
.maxy
;
1177 dumpdbl(cfff
,floor(b
.minx
));
1178 dumpdbl(cfff
,floor(b
.miny
));
1179 dumpdbl(cfff
,ceil(b
.maxx
));
1180 dumpdbloper(cfff
,ceil(b
.maxy
),5);
1181 /* We'll never set StrokeWidth */
1182 if ( sf
->xuid
!=NULL
&& sf
->use_xuid
) {
1183 pt
= sf
->xuid
; if ( *pt
=='[' ) ++pt
;
1184 while ( *pt
&& *pt
!=']' ) {
1185 dumpint(cfff
,strtol(pt
,&end
,10));
1186 if ( pt
==end
) /* garbage in XUID */
1188 for ( pt
= end
; *pt
==' '; ++pt
);
1191 if ( sf
->changed_since_xuidchanged
)
1192 SFIncrementXUID(sf
);
1194 /* Offset to charset (oper=15) needed here */
1195 /* Offset to encoding (oper=16) needed here (not for CID )*/
1196 /* Offset to charstrings (oper=17) needed here */
1197 /* Length of, and Offset to private (oper=18) needed here (not for CID )*/
1200 static int dumpcffdict(SplineFont
*sf
,struct alltabs
*at
) {
1201 FILE *fdarray
= at
->fdarray
;
1203 /* according to the PSRef Man v3, only fontname, fontmatrix and private */
1204 /* appear in this dictionary */
1206 dumpsid(fdarray
,at
,sf
->fontname
,(12<<8)|38);
1207 if ( sf
->ascent
+sf
->descent
!=1000 ) {
1208 dumpdbl(fdarray
,1.0/(sf
->ascent
+sf
->descent
));
1211 dumpdbl(fdarray
,1.0/(sf
->ascent
+sf
->descent
));
1213 dumpintoper(fdarray
,0,(12<<8)|7);
1215 pstart
= ftell(fdarray
);
1216 dumpsizedint(fdarray
,false,0,-1); /* private length */
1217 dumpsizedint(fdarray
,true,0,18); /* private offset */
1221 static void dumpcffdictindex(SplineFont
*sf
,struct alltabs
*at
) {
1225 putshort(at
->fdarray
,sf
->subfontcnt
);
1226 putc('\2',at
->fdarray
); /* DICTs aren't very big, and there are at most 255 */
1227 putshort(at
->fdarray
,1); /* Offset to first dict */
1228 for ( i
=0; i
<sf
->subfontcnt
; ++i
)
1229 putshort(at
->fdarray
,0); /* Dump offset placeholders (note there's one extra to mark the end) */
1230 pos
= ftell(at
->fdarray
)-1;
1231 for ( i
=0; i
<sf
->subfontcnt
; ++i
) {
1232 at
->fds
[i
].fillindictmark
= dumpcffdict(sf
->subfonts
[i
],at
);
1233 at
->fds
[i
].eodictmark
= ftell(at
->fdarray
);
1234 if ( at
->fds
[i
].eodictmark
>65536 )
1235 IError("The DICT INDEX got too big, result won't work");
1237 fseek(at
->fdarray
,2*sizeof(short)+sizeof(char),SEEK_SET
);
1238 for ( i
=0; i
<sf
->subfontcnt
; ++i
)
1239 putshort(at
->fdarray
,at
->fds
[i
].eodictmark
-pos
);
1240 fseek(at
->fdarray
,0,SEEK_END
);
1243 static void dumpcffcidtopdict(SplineFont
*sf
,struct alltabs
*at
) {
1245 FILE *cfff
= at
->cfff
;
1249 for ( k
=0; k
<sf
->subfontcnt
; ++k
)
1250 if ( sf
->subfonts
[k
]->glyphcnt
>cidcnt
) cidcnt
= sf
->subfonts
[k
]->glyphcnt
;
1252 putshort(cfff
,1); /* One top dict */
1253 putc('\2',cfff
); /* Offset size */
1254 putshort(cfff
,1); /* Offset to topdict */
1255 at
->lenpos
= ftell(cfff
);
1256 putshort(cfff
,0); /* placeholder for final position */
1257 dumpsid(cfff
,at
,sf
->cidregistry
,-1);
1258 dumpsid(cfff
,at
,sf
->ordering
,-1);
1259 dumpintoper(cfff
,sf
->supplement
,(12<<8)|30); /* ROS operator must be first */
1260 dumpdbloper(cfff
,sf
->cidversion
,(12<<8)|31);
1261 dumpintoper(cfff
,cidcnt
,(12<<8)|34);
1262 if ( sf
->use_uniqueid
)
1263 dumpintoper(cfff
, sf
->uniqueid
?sf
->uniqueid
:4000000 + (rand()&0x3ffff), (12<<8)|35 );
1265 dumpsid(cfff
,at
,sf
->copyright
,1);
1266 dumpsid(cfff
,at
,sf
->fullname
?sf
->fullname
:sf
->fontname
,2);
1267 dumpsid(cfff
,at
,sf
->familyname
,3);
1268 dumpsid(cfff
,at
,sf
->weight
,4);
1269 /* FontMatrix (identity here, real ones in sub fonts)*/
1270 /* Actually there is no fontmatrix in the adobe cid font I'm looking at */
1271 /* which means it should default to [.001...] but it doesn't so the */
1272 /* docs aren't completely accurate */
1273 /* I now see I've no idea what the FontMatrix means in a CID keyed font */
1274 /* it seems to be ignored everywhere */
1281 dumpintoper(cfff
,0,(12<<8)|7);
1284 CIDLayerFindBounds(sf
,at
->gi
.layer
,&b
);
1285 at
->gi
.xmin
= b
.minx
;
1286 at
->gi
.ymin
= b
.miny
;
1287 at
->gi
.xmax
= b
.maxx
;
1288 at
->gi
.ymax
= b
.maxy
;
1289 dumpdbl(cfff
,floor(b
.minx
));
1290 dumpdbl(cfff
,floor(b
.miny
));
1291 dumpdbl(cfff
,ceil(b
.maxx
));
1292 dumpdbloper(cfff
,ceil(b
.maxy
),5);
1293 /* We'll never set StrokeWidth */
1294 if ( sf
->xuid
!=NULL
&& sf
->use_xuid
) {
1295 pt
= sf
->xuid
; if ( *pt
=='[' ) ++pt
;
1296 while ( *pt
&& *pt
!=']' ) {
1297 dumpint(cfff
,strtol(pt
,&end
,10));
1298 for ( pt
= end
; *pt
==' '; ++pt
);
1301 if ( sf
->changed_since_xuidchanged
)
1302 SFIncrementXUID(sf
);
1305 /* Acrobat doesn't seem to care about a private dict here. Ghostscript */
1306 /* dies. Tech Note: 5176.CFF.PDF, top of page 23 says: */
1307 /* A Private DICT is required, but may be specified as having */
1308 /* a length of 0 if there are no non-default values to be stored*/
1309 /* No indication >where< it is required. I assumed everywhere. Perhaps */
1310 /* just in basefonts? */
1311 dumpint(cfff
,0); /* Docs say a private dict is required and they don't specifically omit CID top dicts */
1312 dumpintoper(cfff
,0,18); /* But they do say it can be zero */
1314 /* Offset to charset (oper=15) needed here */
1315 /* Offset to charstrings (oper=17) needed here */
1316 /* Offset to FDArray (oper=12,36) needed here */
1317 /* Offset to FDSelect (oper=12,37) needed here */
1320 static int isStdEncoding(SplineFont
*sf
,EncMap
*map
) {
1323 for ( i
=0; i
<256 && i
<map
->enccount
; ++i
) if ( map
->map
[i
]!=-1 && sf
->glyphs
[map
->map
[i
]]!=NULL
)
1324 if ( sf
->glyphs
[map
->map
[i
]]->unicodeenc
!=-1 )
1325 if ( sf
->glyphs
[map
->map
[i
]]->unicodeenc
!=unicode_from_adobestd
[i
] )
1331 static void finishup(SplineFont
*sf
,struct alltabs
*at
) {
1332 int strlen
, shlen
, glen
,enclen
,csetlen
,cstrlen
,prvlen
;
1333 int base
, eotop
, strhead
;
1334 int output_enc
= ( at
->format
==ff_cff
&& !isStdEncoding(sf
,at
->map
));
1336 storesid(at
,NULL
); /* end the strings index */
1337 strlen
= ftell(at
->sidf
) + (shlen
= ftell(at
->sidh
));
1338 glen
= sizeof(short); /* Single entry: 0, no globals */
1339 enclen
= ftell(at
->encoding
);
1340 csetlen
= ftell(at
->charset
);
1341 cstrlen
= ftell(at
->charstrings
);
1342 prvlen
= ftell(at
->private);
1343 base
= ftell(at
->cfff
);
1344 if ( base
+6*3+strlen
+glen
+enclen
+csetlen
+cstrlen
+prvlen
> 32767 ) {
1345 at
->cfflongoffset
= true;
1349 strhead
= 2+(at
->sidcnt
>1);
1352 dumpsizedint(at
->cfff
,at
->cfflongoffset
,base
+strlen
+glen
,15); /* Charset */
1353 if ( output_enc
) /* encoding offset */
1354 dumpsizedint(at
->cfff
,at
->cfflongoffset
,base
+strlen
+glen
+csetlen
,16); /* encoding offset */
1356 dumpsizedint(at
->cfff
,at
->cfflongoffset
,0,16);
1359 dumpsizedint(at
->cfff
,at
->cfflongoffset
,base
+strlen
+glen
+csetlen
+enclen
,17);/* charstrings */
1360 dumpsizedint(at
->cfff
,at
->cfflongoffset
,at
->privatelen
,-1);
1361 dumpsizedint(at
->cfff
,at
->cfflongoffset
,base
+strlen
+glen
+csetlen
+enclen
+cstrlen
,18); /* private size */
1362 eotop
= base
-strhead
-at
->lenpos
-1;
1363 if ( at
->cfflongoffset
) {
1364 fseek(at
->cfff
,3,SEEK_SET
);
1367 fseek(at
->cfff
,at
->lenpos
,SEEK_SET
);
1368 putshort(at
->cfff
,eotop
);
1369 fseek(at
->cfff
,0,SEEK_END
);
1372 putshort(at
->cfff
,at
->sidcnt
-1);
1373 if ( at
->sidcnt
!=1 ) { /* Everybody gets an added NULL */
1374 putc(at
->sidlongoffset
?4:2,at
->cfff
);
1375 if ( !ttfcopyfile(at
->cfff
,at
->sidh
,base
,"CFF-StringBase")) at
->error
= true;
1376 if ( !ttfcopyfile(at
->cfff
,at
->sidf
,base
+shlen
,"CFF-StringData")) at
->error
= true;
1380 putshort(at
->cfff
,0);
1383 if ( !ttfcopyfile(at
->cfff
,at
->charset
,base
+strlen
+glen
,"CFF-Charset")) at
->error
= true;
1386 if ( !ttfcopyfile(at
->cfff
,at
->encoding
,base
+strlen
+glen
+csetlen
,"CFF-Encoding")) at
->error
= true;
1389 if ( !ttfcopyfile(at
->cfff
,at
->charstrings
,base
+strlen
+glen
+csetlen
+enclen
,"CFF-CharStrings")) at
->error
= true;
1391 /* Private & Subrs */
1392 if ( !ttfcopyfile(at
->cfff
,at
->private,base
+strlen
+glen
+csetlen
+enclen
+cstrlen
,"CFF-Private")) at
->error
= true;
1395 static void finishupcid(SplineFont
*sf
,struct alltabs
*at
) {
1396 int strlen
, shlen
, glen
,csetlen
,cstrlen
,fdsellen
,fdarrlen
,prvlen
;
1397 int base
, eotop
, strhead
;
1400 storesid(at
,NULL
); /* end the strings index */
1401 strlen
= ftell(at
->sidf
) + (shlen
= ftell(at
->sidh
));
1402 glen
= ftell(at
->globalsubrs
);
1404 csetlen
= ftell(at
->charset
);
1405 fdsellen
= ftell(at
->fdselect
);
1406 cstrlen
= ftell(at
->charstrings
);
1407 fdarrlen
= ftell(at
->fdarray
);
1408 base
= ftell(at
->cfff
);
1410 at
->cfflongoffset
= true;
1411 base
+= 5*4+4+2; /* two of the opers below are two byte opers */
1412 strhead
= 2+(at
->sidcnt
>1);
1416 for ( i
=0; i
<sf
->subfontcnt
; ++i
) {
1417 fseek(at
->fdarray
,at
->fds
[i
].fillindictmark
,SEEK_SET
);
1418 dumpsizedint(at
->fdarray
,false,at
->fds
[i
].privatelen
,-1); /* Private len */
1419 dumpsizedint(at
->fdarray
,true,base
+strlen
+glen
+csetlen
+fdsellen
+cstrlen
+fdarrlen
+prvlen
,18); /* Private offset */
1420 prvlen
+= ftell(at
->fds
[i
].private); /* private & subrs */
1423 dumpsizedint(at
->cfff
,at
->cfflongoffset
,base
+strlen
+glen
,15); /* charset */
1424 dumpsizedint(at
->cfff
,at
->cfflongoffset
,base
+strlen
+glen
+csetlen
,(12<<8)|37); /* fdselect */
1425 dumpsizedint(at
->cfff
,at
->cfflongoffset
,base
+strlen
+glen
+csetlen
+fdsellen
,17); /* charstrings */
1426 dumpsizedint(at
->cfff
,at
->cfflongoffset
,base
+strlen
+glen
+csetlen
+fdsellen
+cstrlen
,(12<<8)|36); /* fdarray */
1427 eotop
= base
-strhead
-at
->lenpos
-1;
1428 fseek(at
->cfff
,at
->lenpos
,SEEK_SET
);
1429 putshort(at
->cfff
,eotop
);
1430 fseek(at
->cfff
,0,SEEK_END
);
1433 putshort(at
->cfff
,at
->sidcnt
-1);
1434 if ( at
->sidcnt
!=1 ) { /* Everybody gets an added NULL */
1435 putc(at
->sidlongoffset
?4:2,at
->cfff
);
1436 if ( !ttfcopyfile(at
->cfff
,at
->sidh
,base
,"CFF-StringBase")) at
->error
= true;
1437 if ( !ttfcopyfile(at
->cfff
,at
->sidf
,base
+shlen
,"CFF-StringData")) at
->error
= true;
1441 if ( !ttfcopyfile(at
->cfff
,at
->globalsubrs
,base
+strlen
,"CFF-GlobalSubrs")) at
->error
= true;
1444 if ( !ttfcopyfile(at
->cfff
,at
->charset
,base
+strlen
+glen
,"CFF-Charset")) at
->error
= true;
1447 if ( !ttfcopyfile(at
->cfff
,at
->fdselect
,base
+strlen
+glen
+csetlen
,"CFF-FDSelect")) at
->error
= true;
1450 if ( !ttfcopyfile(at
->cfff
,at
->charstrings
,base
+strlen
+glen
+csetlen
+fdsellen
,"CFF-CharStrings")) at
->error
= true;
1452 /* FDArray (DICT Index) */
1453 if ( !ttfcopyfile(at
->cfff
,at
->fdarray
,base
+strlen
+glen
+csetlen
+fdsellen
+cstrlen
,"CFF-FDArray")) at
->error
= true;
1455 /* Private & Subrs */
1457 for ( i
=0; i
<sf
->subfontcnt
; ++i
) {
1458 int temp
= ftell(at
->fds
[i
].private);
1459 if ( !ttfcopyfile(at
->cfff
,at
->fds
[i
].private,
1460 base
+strlen
+glen
+csetlen
+fdsellen
+cstrlen
+fdarrlen
+prvlen
,"CFF-PrivateSubrs")) at
->error
= true;
1467 static int dumpcffhmtx(struct alltabs
*at
,SplineFont
*sf
,int bitmaps
) {
1471 int dovmetrics
= sf
->hasvmetrics
;
1472 int width
= at
->gi
.fixed_width
;
1474 at
->gi
.hmtx
= tmpfile();
1476 at
->gi
.vmtx
= tmpfile();
1477 FigureFullMetricsEnd(sf
,&at
->gi
,bitmaps
); /* Bitmap fonts use ttf convention of 3 magic glyphs */
1478 if ( at
->gi
.bygid
[0]!=-1 && (sf
->glyphs
[at
->gi
.bygid
[0]]->width
==width
|| width
==-1 )) {
1479 putshort(at
->gi
.hmtx
,sf
->glyphs
[at
->gi
.bygid
[0]]->width
);
1480 SplineCharLayerFindBounds(sf
->glyphs
[at
->gi
.bygid
[0]],at
->gi
.layer
,&b
);
1481 putshort(at
->gi
.hmtx
,b
.minx
);
1483 putshort(at
->gi
.vmtx
,sf
->glyphs
[at
->gi
.bygid
[0]]->vwidth
);
1484 putshort(at
->gi
.vmtx
,/*sf->vertical_origin-*/b
.miny
);
1487 putshort(at
->gi
.hmtx
,width
==-1?(sf
->ascent
+sf
->descent
)/2:width
);
1488 putshort(at
->gi
.hmtx
,0);
1490 putshort(at
->gi
.vmtx
,sf
->ascent
+sf
->descent
);
1491 putshort(at
->gi
.vmtx
,0);
1496 if ( width
==-1 ) width
= (sf
->ascent
+sf
->descent
)/3;
1497 putshort(at
->gi
.hmtx
,width
);
1498 putshort(at
->gi
.hmtx
,0);
1500 putshort(at
->gi
.vmtx
,sf
->ascent
+sf
->descent
);
1501 putshort(at
->gi
.vmtx
,0);
1503 putshort(at
->gi
.hmtx
,width
);
1504 putshort(at
->gi
.hmtx
,0);
1506 putshort(at
->gi
.vmtx
,sf
->ascent
+sf
->descent
);
1507 putshort(at
->gi
.vmtx
,0);
1512 for ( i
=cnt
; i
<at
->gi
.gcnt
; ++i
) if ( at
->gi
.bygid
[i
]!=-1 ) {
1513 sc
= sf
->glyphs
[at
->gi
.bygid
[i
]];
1514 if ( SCWorthOutputting(sc
) ) {
1515 if ( i
<=at
->gi
.lasthwidth
)
1516 putshort(at
->gi
.hmtx
,sc
->width
);
1517 SplineCharLayerFindBounds(sc
,at
->gi
.layer
,&b
);
1518 putshort(at
->gi
.hmtx
,b
.minx
);
1520 if ( i
<=at
->gi
.lastvwidth
)
1521 putshort(at
->gi
.vmtx
,sc
->vwidth
);
1522 putshort(at
->gi
.vmtx
,/*sf->vertical_origin-*/b
.maxy
);
1525 if ( i
==at
->gi
.lasthwidth
)
1526 at
->gi
.hfullcnt
= cnt
;
1527 if ( i
==at
->gi
.lastvwidth
)
1528 at
->gi
.vfullcnt
= cnt
;
1531 at
->gi
.hmtxlen
= ftell(at
->gi
.hmtx
);
1532 if ( at
->gi
.hmtxlen
&2 ) putshort(at
->gi
.hmtx
,0);
1534 at
->gi
.vmtxlen
= ftell(at
->gi
.vmtx
);
1535 if ( at
->gi
.vmtxlen
&2 ) putshort(at
->gi
.vmtx
,0);
1538 at
->gi
.maxp
->numGlyphs
= cnt
;
1542 static void dumpcffcidhmtx(struct alltabs
*at
,SplineFont
*_sf
) {
1545 int cid
,i
,cnt
=0,max
;
1546 SplineFont
*sf
= NULL
;
1547 int dovmetrics
= _sf
->hasvmetrics
;
1549 at
->gi
.hmtx
= tmpfile();
1551 at
->gi
.vmtx
= tmpfile();
1552 FigureFullMetricsEnd(_sf
,&at
->gi
,false);
1555 for ( i
=0; i
<_sf
->subfontcnt
; ++i
)
1556 if ( max
<_sf
->subfonts
[i
]->glyphcnt
)
1557 max
= _sf
->subfonts
[i
]->glyphcnt
;
1558 for ( cid
= 0; cid
<max
; ++cid
) {
1559 for ( i
=0; i
<_sf
->subfontcnt
; ++i
) {
1560 sf
= _sf
->subfonts
[i
];
1561 if ( cid
<sf
->glyphcnt
&& SCWorthOutputting(sf
->glyphs
[cid
]))
1564 if ( i
!=_sf
->subfontcnt
) {
1565 sc
= sf
->glyphs
[cid
];
1566 if ( sc
->ttf_glyph
<=at
->gi
.lasthwidth
)
1567 putshort(at
->gi
.hmtx
,sc
->width
);
1568 SplineCharLayerFindBounds(sc
,at
->gi
.layer
,&b
);
1569 putshort(at
->gi
.hmtx
,b
.minx
);
1571 if ( sc
->ttf_glyph
<=at
->gi
.lastvwidth
)
1572 putshort(at
->gi
.vmtx
,sc
->vwidth
);
1573 putshort(at
->gi
.vmtx
,/*sf->vertical_origin-*/b
.maxy
);
1576 if ( sc
->ttf_glyph
==at
->gi
.lasthwidth
)
1577 at
->gi
.hfullcnt
= cnt
;
1578 if ( sc
->ttf_glyph
==at
->gi
.lastvwidth
)
1579 at
->gi
.vfullcnt
= cnt
;
1580 } else if ( cid
==0 ) {
1581 /* Create a dummy entry for .notdef */
1582 sf
= _sf
->subfonts
[0];
1583 putshort(at
->gi
.hmtx
,sf
->ascent
+sf
->descent
);
1584 putshort(at
->gi
.hmtx
,0);
1587 putshort(at
->gi
.vmtx
,sf
->ascent
+sf
->descent
);
1588 putshort(at
->gi
.vmtx
,0);
1592 at
->gi
.hmtxlen
= ftell(at
->gi
.hmtx
);
1593 if ( at
->gi
.hmtxlen
&2 ) putshort(at
->gi
.hmtx
,0);
1595 at
->gi
.vmtxlen
= ftell(at
->gi
.vmtx
);
1596 if ( at
->gi
.vmtxlen
&2 ) putshort(at
->gi
.vmtx
,0);
1599 at
->gi
.maxp
->numGlyphs
= cnt
;
1602 static int dumptype2glyphs(SplineFont
*sf
,struct alltabs
*at
) {
1604 struct pschars
*subrs
, *chrs
;
1606 at
->cfff
= tmpfile();
1607 at
->sidf
= tmpfile();
1608 at
->sidh
= tmpfile();
1609 at
->charset
= tmpfile();
1610 at
->encoding
= tmpfile();
1611 at
->private = tmpfile();
1613 dumpcffheader(sf
,at
->cfff
);
1614 dumpcffnames(sf
,at
->cfff
);
1615 dumpcffcharset(sf
,at
);
1616 ff_progress_change_stages(2+at
->gi
.strikecnt
);
1618 ATFigureDefWidth(sf
,at
,-1);
1619 if ((chrs
=SplineFont2ChrsSubrs2(sf
,at
->nomwid
,at
->defwid
,at
->gi
.bygid
,at
->gi
.gcnt
,at
->gi
.flags
,&subrs
,at
->gi
.layer
))==NULL
)
1621 dumpcffprivate(sf
,at
,-1,subrs
->next
);
1622 if ( subrs
->next
!=0 )
1623 _dumpcffstrings(at
->private,subrs
);
1624 ff_progress_next_stage();
1625 at
->charstrings
= dumpcffstrings(chrs
);
1627 if ( at
->charstrings
== NULL
)
1629 if ( at
->format
==ff_cff
&& !isStdEncoding(sf
,at
->map
))
1630 dumpcffencoding(sf
,at
); /* Do this after we've assigned glyph ids */
1631 dumpcfftopdict(sf
,at
);
1634 at
->cfflen
= ftell(at
->cfff
);
1635 if ( at
->cfflen
&3 ) {
1636 for ( i
=4-(at
->cfflen
&3); i
>0; --i
)
1637 putc('\0',at
->cfff
);
1640 if ( at
->format
!=ff_cff
)
1641 dumpcffhmtx(at
,sf
,false);
1642 free(at
->gn_sid
); at
->gn_sid
=NULL
;
1646 static int dumpcidglyphs(SplineFont
*sf
,struct alltabs
*at
) {
1648 struct pschars
*glbls
= NULL
, *chrs
;
1650 at
->cfff
= tmpfile();
1651 at
->sidf
= tmpfile();
1652 at
->sidh
= tmpfile();
1653 at
->charset
= tmpfile();
1654 at
->fdselect
= tmpfile();
1655 at
->fdarray
= tmpfile();
1656 at
->globalsubrs
= tmpfile();
1658 at
->fds
= gcalloc(sf
->subfontcnt
,sizeof(struct fd2data
));
1659 for ( i
=0; i
<sf
->subfontcnt
; ++i
) {
1660 at
->fds
[i
].private = tmpfile();
1661 ATFigureDefWidth(sf
->subfonts
[i
],at
,i
);
1663 if ( (chrs
= CID2ChrsSubrs2(sf
,at
->fds
,at
->gi
.flags
,&glbls
,at
->gi
.layer
))==NULL
)
1665 for ( i
=0; i
<sf
->subfontcnt
; ++i
) {
1666 dumpcffprivate(sf
->subfonts
[i
],at
,i
,at
->fds
[i
].subrs
->next
);
1667 if ( at
->fds
[i
].subrs
->next
!=0 )
1668 _dumpcffstrings(at
->fds
[i
].private,at
->fds
[i
].subrs
);
1669 PSCharsFree(at
->fds
[i
].subrs
);
1671 _dumpcffstrings(at
->globalsubrs
,glbls
);
1674 dumpcffheader(sf
,at
->cfff
);
1675 dumpcffnames(sf
,at
->cfff
);
1676 dumpcffcidset(sf
,at
);
1677 dumpcfffdselect(sf
,at
);
1678 dumpcffdictindex(sf
,at
);
1679 if ( (at
->charstrings
= dumpcffstrings(chrs
))==NULL
)
1681 dumpcffcidtopdict(sf
,at
);
1684 at
->cfflen
= ftell(at
->cfff
);
1685 if ( at
->cfflen
&3 ) {
1686 for ( i
=4-(at
->cfflen
&3); i
>0; --i
)
1687 putc('\0',at
->cfff
);
1690 if ( at
->format
!=ff_cffcid
)
1691 dumpcffcidhmtx(at
,sf
);
1697 static void OS2WeightCheck(struct pfminfo
*pfminfo
,char *weight
) {
1698 if ( weight
==NULL
) {
1700 } else if ( strstrmatch(weight
,"medi")!=NULL
) {
1701 pfminfo
->weight
= 500;
1702 pfminfo
->panose
[2] = 6;
1703 } else if ( strstrmatch(weight
,"demi")!=NULL
||
1704 strstrmatch(weight
,"halb")!=NULL
||
1705 (strstrmatch(weight
,"semi")!=NULL
&&
1706 strstrmatch(weight
,"bold")!=NULL
) ) {
1707 pfminfo
->weight
= 600;
1708 pfminfo
->panose
[2] = 7;
1709 } else if ( strstrmatch(weight
,"bold")!=NULL
||
1710 strstrmatch(weight
,"fett")!=NULL
||
1711 strstrmatch(weight
,"gras")!=NULL
) {
1712 pfminfo
->weight
= 700;
1713 pfminfo
->panose
[2] = 8;
1714 } else if ( strstrmatch(weight
,"heavy")!=NULL
) {
1715 pfminfo
->weight
= 800;
1716 pfminfo
->panose
[2] = 9;
1717 } else if ( strstrmatch(weight
,"black")!=NULL
) {
1718 pfminfo
->weight
= 900;
1719 pfminfo
->panose
[2] = 10;
1720 } else if ( strstrmatch(weight
,"nord")!=NULL
) {
1721 pfminfo
->weight
= 950;
1722 pfminfo
->panose
[2] = 11;
1723 } else if ( strstrmatch(weight
,"thin")!=NULL
) {
1724 pfminfo
->weight
= 100;
1725 pfminfo
->panose
[2] = 2;
1726 } else if ( strstrmatch(weight
,"extra")!=NULL
||
1727 strstrmatch(weight
,"light")!=NULL
) {
1728 pfminfo
->weight
= 200;
1729 pfminfo
->panose
[2] = 3;
1730 } else if ( strstrmatch(weight
,"light")!=NULL
) {
1731 pfminfo
->weight
= 300;
1732 pfminfo
->panose
[2] = 4;
1736 void SFDefaultOS2Simple(struct pfminfo
*pfminfo
,SplineFont
*sf
) {
1737 pfminfo
->pfmfamily
= 0x11;
1738 pfminfo
->panose
[0] = 2;
1739 pfminfo
->weight
= 400;
1740 pfminfo
->panose
[2] = 5;
1742 pfminfo
->panose
[3] = 3;
1743 pfminfo
->winascent_add
= pfminfo
->windescent_add
= true;
1744 pfminfo
->hheadascent_add
= pfminfo
->hheaddescent_add
= true;
1745 pfminfo
->typoascent_add
= pfminfo
->typodescent_add
= true;
1746 pfminfo
->os2_winascent
= pfminfo
->os2_windescent
= 0;
1748 if ( sf
->subfonts
!=NULL
) sf
= sf
->subfonts
[0];
1749 pfminfo
->linegap
= pfminfo
->vlinegap
= pfminfo
->os2_typolinegap
=
1750 rint(.09*(sf
->ascent
+sf
->descent
));
1753 void SFDefaultOS2SubSuper(struct pfminfo
*pfminfo
,int emsize
,double italic_angle
) {
1754 double s
= sin(italic_angle
*3.1415926535897932/180.0);
1755 pfminfo
->os2_supysize
= pfminfo
->os2_subysize
= .7*emsize
;
1756 pfminfo
->os2_supxsize
= pfminfo
->os2_subxsize
= .65*emsize
;
1757 pfminfo
->os2_subyoff
= .14*emsize
;
1758 pfminfo
->os2_supyoff
= .48*emsize
;
1759 pfminfo
->os2_supxoff
= s
*pfminfo
->os2_supyoff
;
1760 pfminfo
->os2_subxoff
= -s
*pfminfo
->os2_subyoff
;
1761 pfminfo
->os2_strikeysize
= 102*emsize
/2048;
1762 pfminfo
->os2_strikeypos
= 530*emsize
/2048;
1765 void SFDefaultOS2Info(struct pfminfo
*pfminfo
,SplineFont
*sf
,char *fontname
) {
1767 char *weight
= sf
->cidmaster
==NULL
? sf
->weight
: sf
->cidmaster
->weight
;
1769 if ( sf
->pfminfo
.pfmset
) {
1770 if ( pfminfo
!=&sf
->pfminfo
)
1771 *pfminfo
= sf
->pfminfo
;
1772 if ( !pfminfo
->panose_set
) {
1773 struct pfminfo info
;
1774 memset(&info
,0,sizeof(info
));
1775 sf
->pfminfo
.pfmset
= false;
1776 SFDefaultOS2Info(&info
,sf
,fontname
);
1777 sf
->pfminfo
.pfmset
= true;
1778 memcpy(pfminfo
->panose
,info
.panose
,sizeof(info
.panose
));
1781 struct pfminfo hold
;
1782 if ( pfminfo
->hheadset
|| pfminfo
->vheadset
)
1785 hold
.hheadset
= hold
.vheadset
= false;
1786 memset(pfminfo
,'\0',sizeof(*pfminfo
));
1787 SFDefaultOS2Simple(pfminfo
,sf
);
1788 samewid
= CIDOneWidth(sf
);
1790 pfminfo
->pfmfamily
= 0x10;
1792 pfminfo
->pfmfamily
= 0x30;
1793 /* pfminfo->panose[3] = 9; */ /* This is done later */
1794 } else if ( strstrmatch(fontname
,"sans")!=NULL
)
1795 pfminfo
->pfmfamily
= 0x20;
1796 else if ( strstrmatch(fontname
,"script")!=NULL
) {
1797 pfminfo
->pfmfamily
= 0x40;
1798 pfminfo
->panose
[0] = 3;
1801 pfminfo
->pfmfamily
|= 0x1; /* Else it assumes monospace */
1803 /* urw uses 4 character abreviations */
1805 OS2WeightCheck(pfminfo
,weight
);
1806 OS2WeightCheck(pfminfo
,fontname
);
1808 if ( strstrmatch(fontname
,"ultra")!=NULL
&&
1809 strstrmatch(fontname
,"condensed")!=NULL
) {
1811 pfminfo
->panose
[3] = 8;
1812 } else if ( strstrmatch(fontname
,"extra")!=NULL
&&
1813 strstrmatch(fontname
,"condensed")!=NULL
) {
1815 pfminfo
->panose
[3] = 8;
1816 } else if ( strstrmatch(fontname
,"semi")!=NULL
&&
1817 strstrmatch(fontname
,"condensed")!=NULL
) {
1819 pfminfo
->panose
[3] = 6;
1820 } else if ( strstrmatch(fontname
,"condensed")!=NULL
||
1821 strstrmatch(fontname
,"narrow")!=NULL
) {
1823 pfminfo
->panose
[3] = 6;
1824 } else if ( strstrmatch(fontname
,"ultra")!=NULL
&&
1825 strstrmatch(fontname
,"expanded")!=NULL
) {
1827 pfminfo
->panose
[3] = 7;
1828 } else if ( strstrmatch(fontname
,"extra")!=NULL
&&
1829 strstrmatch(fontname
,"expanded")!=NULL
) {
1831 pfminfo
->panose
[3] = 7;
1832 } else if ( strstrmatch(fontname
,"semi")!=NULL
&&
1833 strstrmatch(fontname
,"expanded")!=NULL
) {
1835 pfminfo
->panose
[3] = 5;
1836 } else if ( strstrmatch(fontname
,"expanded")!=NULL
) {
1838 pfminfo
->panose
[3] = 5;
1841 pfminfo
->panose
[3] = 9;
1842 if ( hold
.hheadset
) {
1843 pfminfo
->hheadset
= true;
1844 pfminfo
->hheadascent_add
= hold
.hheadascent_add
;
1845 pfminfo
->hheaddescent_add
= hold
.hheaddescent_add
;
1846 pfminfo
->hhead_ascent
= hold
.hhead_ascent
;
1847 pfminfo
->hhead_descent
= hold
.hhead_descent
;
1848 pfminfo
->linegap
= hold
.linegap
;
1850 if ( hold
.vheadset
) {
1851 pfminfo
->vheadset
= true;
1852 pfminfo
->vlinegap
= hold
.vlinegap
;
1855 if ( !pfminfo
->subsuper_set
)
1856 SFDefaultOS2SubSuper(pfminfo
,sf
->ascent
+sf
->descent
,sf
->italicangle
);
1859 char *utf8_verify_copy(const char *str
) {
1860 /* When given a postscript string it SHOULD be in ASCII. But it will often*/
1861 /* contain a copyright symbol (sometimes in latin1, sometimes in macroman)*/
1862 /* unfortunately both encodings use 0xa9 for copyright so we can't distinguish */
1863 /* guess that it's latin1 (or that copyright is the only odd char which */
1864 /* means a latin1 conversion will work for macs too). */
1869 if ( utf8_valid(str
))
1870 return( copy(str
)); /* Either in ASCII (good) or appears to be utf8*/
1871 return( latin1_2_utf8_copy(str
));
1874 int SFHasInstructions(SplineFont
*sf
) {
1877 if ( sf
->subfontcnt
!=0 )
1878 return( false ); /* Truetype doesn't support cid keyed fonts */
1880 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
) {
1881 if ( strcmp(sf
->glyphs
[i
]->name
,".notdef")==0 )
1882 continue; /* ff produces fonts with instructions in .notdef & not elsewhere. Ignore these */
1883 if ( sf
->glyphs
[i
]->ttf_instrs
!=NULL
)
1889 static int dumpcff(struct alltabs
*at
,SplineFont
*sf
,enum fontformat format
,
1893 if ( format
==ff_cff
) {
1894 AssignTTFGlyph(&at
->gi
,sf
,at
->map
,true);
1895 ret
= dumptype2glyphs(sf
,at
);
1897 SFDummyUpCIDs(&at
->gi
,sf
); /* life is easier if we ignore the seperate fonts of a cid keyed fonts and treat it as flat */
1898 ret
= dumpcidglyphs(sf
,at
);
1899 free(sf
->glyphs
); sf
->glyphs
= NULL
;
1900 sf
->glyphcnt
= sf
->glyphmax
= sf
->glyphmin
= 0;
1902 free( at
->gi
.bygid
);
1906 else if ( at
->gi
.flags
& ps_flag_nocffsugar
) {
1907 if ( !ttfcopyfile(cff
,at
->cfff
,0,"CFF"))
1912 fprintf(cff
,"%%!PS-Adobe-3.0 Resource-FontSet\n");
1913 fprintf(cff
,"%%%%DocumentNeedResources:ProcSet (FontSetInit)\n");
1914 fprintf(cff
,"%%%%Title: (FontSet/%s)\n", sf
->fontname
);
1915 fprintf(cff
,"%%%%EndComments\n" );
1916 fprintf(cff
,"%%%%IncludeResource: ProcSet(FontSetInit)\n" );
1917 fprintf(cff
,"%%%%BeginResource: FontSet(%s)\n", sf
->fontname
);
1918 fprintf(cff
,"/FontSetInit /ProcSet findresource begin\n" );
1919 fseek(at
->cfff
,0,SEEK_END
);
1920 len
= ftell(at
->cfff
);
1922 sprintf( buffer
, "/%s %ld StartData\n", sf
->fontname
, len
);
1923 fprintf(cff
,"%%%%BeginData: %ld Binary Bytes\n", (long) (len
+strlen(buffer
)) );
1925 if ( !ttfcopyfile(cff
,at
->cfff
,ftell(cff
),"CFF"))
1927 fprintf(cff
,"\n%%%%EndData\n" );
1928 fprintf(cff
,"%%%%EndResource\n" );
1929 fprintf(cff
,"%%%%EOF\n" );
1931 return( !at
->error
);
1934 int _WriteTTFFont(FILE *ttf
,SplineFont
*sf
,enum fontformat format
,
1935 int32
*bsizes
, enum bitmapformat bf
,int flags
,EncMap
*map
, int layer
) {
1940 oldloc
= setlocale(LC_NUMERIC
,"C"); /* TrueType probably doesn't need this, but OpenType does for floats in dictionaries */
1941 if ( format
==ff_otfcid
|| format
== ff_cffcid
) {
1942 if ( sf
->cidmaster
) sf
= sf
->cidmaster
;
1944 if ( sf
->subfontcnt
!=0 ) sf
= sf
->subfonts
[0];
1947 if ( sf
->subfontcnt
==0 ) {
1949 for ( i
=sf
->glyphcnt
-1; i
>0 ; --i
) {
1950 if ( SCWorthOutputting(sf
->glyphs
[i
])) {
1952 if ( sf
->glyphs
[i
]->unicodeenc
!=-1 )
1956 if ( !anyglyphs
&& !sf
->internal_temp
) {
1957 ff_post_error(_("No Encoded Glyphs"),_("Warning: Font contained no glyphs"));
1959 if ( format
!=ff_ttfsym
&& !(flags
&ttf_flag_symbol
) && !sf
->internal_temp
) {
1960 if ( i
==0 && anyglyphs
) {
1961 if ( map
->enccount
<=256 ) {
1963 buts
[0] = _("_Yes"); buts
[1] = _("_No"); buts
[2] = NULL
;
1964 if ( ff_ask(_("No Encoded Glyphs"),(const char **) buts
,0,1,_("This font contains no glyphs with unicode encodings.\nWould you like to use a \"Symbol\" encoding instead of Unicode?"))==0 )
1965 flags
|= ttf_flag_symbol
;
1967 ff_post_error(_("No Encoded Glyphs"),_("This font contains no glyphs with unicode encodings.\nYou will probably not be able to use the output."));
1972 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
)
1973 sf
->glyphs
[i
]->ttf_glyph
= -1;
1975 memset(&at
,'\0',sizeof(struct alltabs
));
1976 at
.gi
.flags
= flags
;
1977 at
.gi
.layer
= layer
;
1978 at
.gi
.is_ttf
= false;
1980 at
.opentypemode
= 0;
1981 at
.msbitmaps
= false;
1982 at
.applebitmaps
= false;
1983 at
.gi
.onlybitmaps
= false;
1984 at
.gi
.bsizes
= bsizes
;
1985 at
.gi
.fixed_width
= CIDOneWidth(sf
);
1988 at
.next_strid
= 256;
1992 if ( format
==ff_cff
|| format
==ff_cffcid
) {
1993 dumpcff(&at
,sf
,format
,ttf
);
1995 /* TODO: remove top function layers here */
1997 setlocale(LC_NUMERIC
,oldloc
);
1998 if ( at
.error
|| ferror(ttf
))
2002 /* Modern versions of windows want the execute bit set on a ttf file */
2003 /* I've no idea what this corresponds to in windows, nor any idea on */
2004 /* how to set it from the windows UI, but this seems to work */
2007 fstat(fileno(ttf
),&buf
);
2008 fchmod(fileno(ttf
),S_IXUSR
| buf
.st_mode
);
2015 int WriteTTFFont(char *fontname
,SplineFont
*sf
,enum fontformat format
,
2016 int32
*bsizes
, enum bitmapformat bf
,int flags
,EncMap
*map
, int layer
) {
2020 if ( strstr(fontname
,"://")!=NULL
) {
2021 if (( ttf
= tmpfile())==NULL
)
2024 if (( ttf
=fopen(fontname
,"wb+"))==NULL
)
2027 ret
= _WriteTTFFont(ttf
,sf
,format
,bsizes
,bf
,flags
,map
,layer
);
2028 if ( fclose(ttf
)==-1 )