summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/autohint.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/autohint.c')
-rw-r--r--Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/autohint.c2708
1 files changed, 0 insertions, 2708 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/autohint.c b/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/autohint.c
deleted file mode 100644
index 034978b9193..00000000000
--- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/autohint.c
+++ /dev/null
@@ -1,2708 +0,0 @@
-/* Copyright (C) 2000-2012 by George Williams */
-/*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
-
- * The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
-
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "fontforge.h"
-#include <math.h>
-#include "stemdb.h"
-#include <utype.h>
-#include <chardata.h>
-#include "edgelist.h"
-
-float OpenTypeLoadHintEqualityTolerance = 0.0;
-
-/* to create a type 1 font we must come up with the following entries for the
- private dictionary:
- BlueValues -- an array of 2n entries where Blue[2i]<Blue[2i+1] max n=7, Blue[i]>0
- OtherBlues -- (optional) OtherBlue[i]<0
- (blue zones should be at least 3 units appart)
- StdHW -- (o) array with one entry, standard hstem height
- StdVW -- (o) ditto vstem width
- StemSnapH -- (o) up to 12 numbers containing various hstem heights (includes StdHW), small widths first
- StemSnapV -- (o) ditto, vstem
-This file has routines to figure out at least some of these
-
-Also other routines to guess at good per-character hints
-*/
-
-static void AddBlue(real val, real array[5], int force) {
- val = rint(val);
- if ( !force && (val<array[0]-array[1] || val >array[0]+array[1] ))
-return; /* Outside of one sd */
- if ( array[3]==0 && array[4]==0 )
- array[3] = array[4] = val;
- else if ( val>array[4] )
- array[4] = val;
- else if ( val<array[3] )
- array[3] = val;
-}
-
-static void MergeZones(real zone1[5], real zone2[5]) {
- if ( zone1[2]!=0 && zone2[2]!=0 &&
- ((zone1[4]+3>zone2[3] && zone1[3]<=zone2[3]) ||
- (zone2[4]+3>zone1[3] && zone2[3]<=zone1[3]) )) {
- if (( zone2[0]<zone1[0]-zone1[1] || zone2[0] >zone1[0]+zone1[1] ) &&
- ( zone1[0]<zone2[0]-zone2[1] || zone1[0] >zone2[0]+zone2[1] ))
- /* the means of the zones are too far appart, don't merge em */;
- else {
- if ( zone1[0]<zone2[0] ) zone2[0] = zone1[0];
- if ( zone1[1]>zone2[1] ) zone2[1] = zone1[1];
- }
- zone1[2] = 0;
- }
-}
-
-/* I can deal with latin, greek and cyrillic because the they all come from */
-/* the same set of letter shapes and have all evolved together and have */
-/* various common features (ascenders, descenders, lower case, etc.). Other */
-/* scripts don't fit */
-void FindBlues( SplineFont *sf, int layer, real blues[14], real otherblues[10]) {
- real caph[5], xh[5], ascenth[5], digith[5], descenth[5], base[5];
- real otherdigits[5];
- int i, j, k;
- DBounds b;
-
- /* Go through once to get some idea of the average value so we can weed */
- /* out undesirables */
- caph[0] = caph[1] = caph[2] = xh[0] = xh[1] = xh[2] = 0;
- ascenth[0] = ascenth[1] = ascenth[2] = digith[0] = digith[1] = digith[2] = 0;
- descenth[0] = descenth[1] = descenth[2] = base[0] = base[1] = base[2] = 0;
- otherdigits[0] = otherdigits[1] = otherdigits[2] = 0;
- for ( i=0; i<sf->glyphcnt; ++i ) {
- if ( sf->glyphs[i]!=NULL && sf->glyphs[i]->layers[layer].splines!=NULL ) {
- int enc = sf->glyphs[i]->unicodeenc;
- const unichar_t *upt;
- if ( enc<0x10000 && isalnum(enc) &&
- ((enc>=32 && enc<128 ) || enc == 0xfe || enc==0xf0 || enc==0xdf ||
- enc==0x131 ||
- (enc>=0x391 && enc<=0x3f3 ) ||
- (enc>=0x400 && enc<=0x4e9 ) )) {
- /* no accented characters (or ligatures) */
- if ( unicode_alternates[enc>>8]!=NULL &&
- (upt =unicode_alternates[enc>>8][enc&0xff])!=NULL &&
- upt[1]!='\0' )
- continue;
- SplineCharFindBounds(sf->glyphs[i],&b);
- if ( b.miny==0 && b.maxy==0 )
- continue;
- if ( enc=='g' || enc=='j' || enc=='p' || enc=='q' || enc=='y' ||
- enc==0xfe ||
- enc==0x3c1 /* rho */ ||
- enc==0x3c6 /* phi */ ||
- enc==0x3c7 /* chi */ ||
- enc==0x3c8 /* psi */ ||
- enc==0x440 /* cyr er */ ||
- enc==0x443 /* cyr u */ ||
- enc==0x444 /* cyr ef */) {
- descenth[0] += b.miny;
- descenth[1] += b.miny*b.miny;
- ++descenth[2];
- } else if ( enc=='x' || enc=='r' || enc=='o' || enc=='e' ||
- enc=='s' || enc=='c' || enc=='h' || enc=='k' ||
- enc=='l' || enc=='m' || enc=='n' ||
- enc==0x3b5 /* epsilon */ ||
- enc==0x3b9 /* iota */ ||
- enc==0x3ba /* kappa */ ||
- enc==0x3bf /* omicron */ ||
- enc==0x3c3 /* sigma */ ||
- enc==0x3c5 /* upsilon */ ||
- enc==0x430 /* cyr a */ ||
- enc==0x432 /* cyr ve */ ||
- enc==0x433 /* cyr ge */ ||
- enc==0x435 /* cyr e */ ||
- enc==0x436 /* cyr zhe */ ||
- enc==0x438 /* cyr i */ ||
- enc==0x43a /* cyr ka */ ||
- enc==0x43d /* cyr en */ ||
- enc==0x43e /* cyr o */ ||
- enc==0x441 /* cyr es */ ||
- enc==0x445 /* cyr ha */ ||
- enc==0x447 /* cyr che */ ||
- enc==0x448 /* cyr sha */ ||
- enc==0x44f /* cyr ya */ ){
- base[0] += b.miny;
- base[1] += b.miny*b.miny;
- ++base[2];
- }
- /* careful of lowercase digits, 6 and 8 should be ascenders */
- if ( enc=='6' || enc=='8' ) {
- digith[0] += b.maxy;
- digith[1] += b.maxy*b.maxy;
- ++digith[2];
- } else if ( enc<0x10000 && isdigit(enc) ) {
- otherdigits[0] += b.maxy;
- otherdigits[1] += b.maxy*b.maxy;
- ++otherdigits[2];
- } else if ( enc<0x10000 && isupper(enc) && enc!=0x462 && enc!=0x490 ) {
- caph[0] += b.maxy;
- caph[1] += b.maxy*b.maxy;
- ++caph[2];
- } else if ( enc=='b' || enc=='d' || enc=='f' || enc=='h' || enc=='k' ||
- enc == 'l' || enc==0xf0 || enc==0xfe || enc == 0xdf ||
- enc == 0x3b2 || enc==0x3b6 || enc==0x3b8 || enc==0x3bb ||
- enc == 0x3be ||
- enc == 0x431 /* cyr be */ /* || enc == 0x444 - ef may have varible height */) {
- ascenth[0] += b.maxy;
- ascenth[1] += b.maxy*b.maxy;
- ++ascenth[2];
- } else if ( enc=='c' || enc=='e' || enc=='o' || enc=='s' || enc=='u' ||
- enc=='v' || enc=='w' || enc=='x' || enc=='y' || enc=='z' ||
- enc==0x3b5 /* epsilon */ ||
- enc==0x3b9 /* iota */ ||
- enc==0x3ba /* kappa */ ||
- enc==0x3bc /* mu */ ||
- enc==0x3bd /* nu */ ||
- enc==0x3bf /* omicron */ ||
- enc==0x3c0 /* pi */ ||
- enc==0x3c1 /* rho */ ||
- enc==0x3c5 /* upsilon */ ||
- enc==0x433 /* cyr ge */ ||
- enc==0x435 /* cyr e */ ||
- enc==0x436 /* cyr zhe */ ||
- enc==0x438 /* cyr i */ ||
- enc==0x43b /* cyr el */ ||
- enc==0x43d /* cyr en */ ||
- enc==0x43e /* cyr o */ ||
- enc==0x43f /* cyr pe */ ||
- enc==0x440 /* cyr er */ ||
- enc==0x441 /* cyr es */ ||
- enc==0x442 /* cyr te */ ||
- enc==0x443 /* cyr u */ ||
- enc==0x445 /* cyr ha */ ||
- enc==0x446 /* cyr tse */ ||
- enc==0x447 /* cyr che */ ||
- enc==0x448 /* cyr sha */ ||
- enc==0x449 /* cyr shcha */ ||
- enc==0x44a /* cyr hard sign */ ||
- enc==0x44b /* cyr yery */ ||
- enc==0x44c /* cyr soft sign */ ||
- enc==0x44d /* cyr reversed e */ ||
- enc==0x44f /* cyr ya */ ) {
- xh[0] += b.maxy;
- xh[1] += b.maxy*b.maxy;
- ++xh[2];
- }
- }
- }
- if ( !ff_progress_next())
- break;
- }
- if ( otherdigits[2]>0 && digith[2]>0 ) {
- if ( otherdigits[0]/otherdigits[2] >= .95*digith[0]/digith[2] ) {
- /* all digits are about the same height, not lowercase */
- digith[0] += otherdigits[0];
- digith[1] += otherdigits[1];
- digith[2] += otherdigits[2];
- }
- }
-
- if ( xh[2]>1 ) {
- xh[1] = sqrt((xh[1]-xh[0]*xh[0]/xh[2])/(xh[2]-1));
- xh[0] /= xh[2];
- }
- if ( ascenth[2]>1 ) {
- ascenth[1] = sqrt((ascenth[1]-ascenth[0]*ascenth[0]/ascenth[2])/(ascenth[2]-1));
- ascenth[0] /= ascenth[2];
- }
- if ( caph[2]>1 ) {
- caph[1] = sqrt((caph[1]-caph[0]*caph[0]/caph[2])/(caph[2]-1));
- caph[0] /= caph[2];
- }
- if ( digith[2]>1 ) {
- digith[1] = sqrt((digith[1]-digith[0]*digith[0]/digith[2])/(digith[2]-1));
- digith[0] /= digith[2];
- }
- if ( base[2]>1 ) {
- base[1] = sqrt((base[1]-base[0]*base[0]/base[2])/(base[2]-1));
- base[0] /= base[2];
- }
- if ( descenth[2]>1 ) {
- descenth[1] = sqrt((descenth[1]-descenth[0]*descenth[0]/descenth[2])/(descenth[2]-1));
- descenth[0] /= descenth[2];
- }
-
- /* we'll accept values between +/- 1sd of the mean */
- /* array[0] == mean, array[1] == sd, array[2] == cnt, array[3]=min, array[4]==max */
- if ( base[0]+base[1]<0 ) base[1] = -base[0]; /* Make sure 0 is within the base bluezone */
- caph[3] = caph[4] = 0;
- xh[3] = xh[4] = 0;
- ascenth[3] = ascenth[4] = 0;
- digith[3] = digith[4] = 0;
- descenth[3] = descenth[4] = 0;
- base[3] = base[4] = 0;
- for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
- int enc = sf->glyphs[i]->unicodeenc;
- const unichar_t *upt;
- if ( enc<0x10000 && isalnum(enc) &&
- ((enc>=32 && enc<128 ) || enc == 0xfe || enc==0xf0 || enc==0xdf ||
- (enc>=0x391 && enc<=0x3f3 ) ||
- (enc>=0x400 && enc<=0x4e9 ) )) {
- /* no accented characters (or ligatures) */
- if ( unicode_alternates[enc>>8]!=NULL &&
- (upt =unicode_alternates[enc>>8][enc&0xff])!=NULL &&
- upt[1]!='\0' )
- continue;
- SplineCharFindBounds(sf->glyphs[i],&b);
- if ( b.miny==0 && b.maxy==0 )
- continue;
- if ( enc=='g' || enc=='j' || enc=='p' || enc=='q' || enc=='y' ||
- enc==0xfe || enc == 0x3c6 || enc==0x3c8 ||
- enc==0x440 || enc==0x443 || enc==0x444) {
- AddBlue(b.miny,descenth,false);
- } else {
- /* O and o get forced into the baseline blue value even if they*/
- /* are beyond 1 sd */
- AddBlue(b.miny,base,enc=='O' || enc=='o');
- }
- if ( enc<0x10000 && isdigit(enc)) {
- AddBlue(b.maxy,digith,false);
- } else if ( enc<0x10000 && isupper(enc)) {
- AddBlue(b.maxy,caph,enc=='O');
- } else if ( enc=='b' || enc=='d' || enc=='f' || enc=='h' || enc=='k' ||
- enc == 'l' || enc=='t' || enc==0xf0 || enc==0xfe || enc == 0xdf ||
- enc == 0x3b2 || enc==0x3b6 || enc==0x3b8 || enc==0x3bb ||
- enc == 0x3be ||
- enc == 0x431 ) {
- AddBlue(b.maxy,ascenth,false);
- } else if ( enc=='c' || enc=='e' || enc=='o' || enc=='s' || enc=='u' ||
- enc=='v' || enc=='w' || enc=='x' || enc=='y' || enc=='z' ||
- enc==0x3b5 /* epsilon */ ||
- enc==0x3b9 /* iota */ ||
- enc==0x3ba /* kappa */ ||
- enc==0x3bc /* mu */ ||
- enc==0x3bd /* nu */ ||
- enc==0x3bf /* omicron */ ||
- enc==0x3c0 /* pi */ ||
- enc==0x3c1 /* rho */ ||
- enc==0x3c5 /* upsilon */ ||
- enc==0x433 /* cyr ge */ ||
- enc==0x435 /* cyr e */ ||
- enc==0x436 /* cyr zhe */ ||
- enc==0x438 /* cyr i */ ||
- enc==0x43b /* cyr el */ ||
- enc==0x43d /* cyr en */ ||
- enc==0x43e /* cyr o */ ||
- enc==0x43f /* cyr pe */ ||
- enc==0x440 /* cyr er */ ||
- enc==0x441 /* cyr es */ ||
- enc==0x442 /* cyr te */ ||
- enc==0x443 /* cyr u */ ||
- enc==0x445 /* cyr ha */ ||
- enc==0x446 /* cyr tse */ ||
- enc==0x447 /* cyr che */ ||
- enc==0x448 /* cyr sha */ ||
- enc==0x449 /* cyr shcha */ ||
- enc==0x44a /* cyr hard sign */ ||
- enc==0x44b /* cyr yery */ ||
- enc==0x44c /* cyr soft sign */ ||
- enc==0x44d /* cyr reversed e */ ||
- enc==0x44f /* cyr ya */ ) {
- AddBlue(b.maxy,xh,enc=='o' || enc=='x');
- }
- }
- }
-
- /* the descent blue zone merges into the base zone */
- MergeZones(descenth,base);
- MergeZones(xh,base);
- MergeZones(ascenth,caph);
- MergeZones(digith,caph);
- MergeZones(xh,caph);
- MergeZones(ascenth,digith);
- MergeZones(xh,digith);
-
- if ( otherblues!=NULL )
- for ( i=0; i<10; ++i )
- otherblues[i] = 0;
- for ( i=0; i<14; ++i )
- blues[i] = 0;
-
- if ( otherblues!=NULL && descenth[2]!=0 ) {
- otherblues[0] = descenth[3];
- otherblues[1] = descenth[4];
- }
- i = 0;
- if ( base[2]==0 && (xh[2]!=0 || ascenth[2]!=0 || caph[2]!=0 || digith[2]!=0 )) {
- /* base line blue value must be present if any other value is */
- /* make one up if we don't have one */
- blues[0] = -20;
- blues[1] = 0;
- i = 2;
- } else if ( base[2]!=0 ) {
- blues[0] = base[3];
- blues[1] = base[4];
- i = 2;
- }
- if ( xh[2]!=0 ) {
- blues[i++] = xh[3];
- blues[i++] = xh[4];
- }
- if ( caph[2]!=0 ) {
- blues[i++] = caph[3];
- blues[i++] = caph[4];
- }
- if ( digith[2]!=0 ) {
- blues[i++] = digith[3];
- blues[i++] = digith[4];
- }
- if ( ascenth[2]!=0 ) {
- blues[i++] = ascenth[3];
- blues[i++] = ascenth[4];
- }
-
- for ( j=0; j<i; j+=2 ) for ( k=j+2; k<i; k+=2 ) {
- if ( blues[j]>blues[k] ) {
- real temp = blues[j];
- blues[j]=blues[k];
- blues[k] = temp;
- temp = blues[j+1];
- blues[j+1] = blues[k+1];
- blues[k+1] = temp;
- }
- }
-}
-
-static int PVAddBlues(BlueData *bd,unsigned bcnt,char *pt) {
- char *end;
- real val1, val2;
- unsigned i,j;
-
- if ( pt==NULL )
-return( bcnt );
-
- while ( isspace(*pt) || *pt=='[' ) ++pt;
- while ( *pt!=']' && *pt!='\0' ) {
- val1 = strtod(pt,&end);
- if ( *end=='\0' || end==pt )
- break;
- for ( pt=end; isspace(*pt) ; ++pt );
- val2 = strtod(pt,&end);
- if ( end==pt )
- break;
- if ( bcnt==0 || val1>bd->blues[bcnt-1][0] )
- i = bcnt;
- else {
- for ( i=0; i<bcnt && val1>bd->blues[i][0]; ++i );
- for ( j=bcnt; j>i; --j ) {
- bd->blues[j][0] = bd->blues[j-1][0];
- bd->blues[j][1] = bd->blues[j-1][1];
- }
- }
- bd->blues[i][0] = val1;
- bd->blues[i][1] = val2;
- ++bcnt;
- if ( bcnt>=sizeof(bd->blues)/sizeof(bd->blues[0]))
- break;
- for ( pt=end; isspace(*pt) ; ++pt );
- }
-return( bcnt );
-}
-
-/* Quick and dirty (and sometimes wrong) approach to figure out the common */
-/* alignment zones in latin (greek, cyrillic) alphabets */
-void QuickBlues(SplineFont *_sf, int layer, BlueData *bd) {
- real xheight = -1e10, caph = -1e10, ascent = -1e10, descent = 1e10, max, min;
- real xheighttop = -1e10, caphtop = -1e10;
- real numh = -1e10, numhtop = -1e10;
- real base = -1e10, basebelow = 1e10;
- SplineFont *sf;
- SplinePoint *sp;
- SplineSet *spl;
- int i,j, bcnt;
- SplineChar *t;
- char *pt;
-
- /* Get the alignment zones we care most about */
-
- /* be careful of cid fonts */
- if ( _sf->cidmaster!=NULL )
- _sf = _sf->cidmaster;
-
- j=0;
- do {
- sf = ( _sf->subfontcnt==0 )? _sf : _sf->subfonts[j];
- for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
- int enc = sf->glyphs[i]->unicodeenc;
- if ( enc=='I' || enc=='O' || enc=='x' || enc=='o' || enc=='p' || enc=='l' ||
-/* Jean-Christophe Dubacq points out that x-height should be calculated from */
-/* various characters and not just x and o. Italic "x"s often have strange */
-/* shapes */
- enc=='A' || enc==0x391 || enc==0x410 ||
- enc=='V' ||
- enc=='u' || enc=='v' || enc=='w' || enc=='y' || enc=='z' ||
- enc=='7' || enc=='8' || /* numbers with ascenders */
- enc==0x399 || enc==0x39f || enc==0x3ba || enc==0x3bf || enc==0x3c1 || enc==0x3be || enc==0x3c7 ||
- enc==0x41f || enc==0x41e || enc==0x43e || enc==0x43f || enc==0x440 || enc==0x452 || enc==0x445 ) {
- t = sf->glyphs[i];
- while ( t->layers[layer].splines==NULL && t->layers[layer].refs!=NULL )
- t = t->layers[layer].refs->sc;
- max = -1e10; min = 1e10;
- if ( t->layers[layer].splines!=NULL ) {
- for ( spl=t->layers[layer].splines; spl!=NULL; spl=spl->next ) {
- for ( sp=spl->first; ; ) {
- if ( sp->me.y > max ) max = sp->me.y;
- if ( sp->me.y < min ) min = sp->me.y;
- if ( sp->next==NULL )
- break;
- sp = sp->next->to;
- if ( sp==spl->first )
- break;
- }
- }
- if ( enc>0x400 ) {
- /* Only use ascent and descent here if we don't have anything better */
- if ( enc==0x41f ) { caph = max; base = min; }
- else if ( enc==0x41e ) { if ( max>caphtop ) caphtop = max; basebelow = min; }
- else if ( enc==0x410 ) { if ( max>caphtop ) caphtop = max; }
- else if ( enc==0x43f && xheight<0 ) xheight = max;
- else if ( enc==0x445 && xheight<0 ) xheight = max;
- else if ( enc==0x43e ) xheighttop = max;
- else if ( enc==0x452 && ascent<0 ) ascent = max;
- else if ( enc==0x440 && descent>0 ) descent = min;
- } else if ( enc>0x300 ) {
- if ( enc==0x399 ) { caph = max; base = min; }
- else if ( enc==0x391 ) { if ( max>caphtop ) caphtop = max; }
- else if ( enc==0x39f ) { if ( max>caphtop ) caphtop = max; basebelow = min; }
- else if ( enc==0x3ba && xheight<0 ) xheight = max;
- else if ( enc==0x3c7 && xheight<0 ) xheight = max;
- else if ( enc==0x3bf ) xheighttop = max;
- else if ( enc==0x3be && ascent<0 ) ascent = max;
- else if ( enc==0x3c1 && descent>0 ) descent = min;
- } else {
- if ( enc=='I' ) { caph = max; base = min; }
- else if ( enc=='O' ) { if ( max>caphtop ) caphtop = max; if ( basebelow<min ) basebelow = min; }
- else if ( enc=='V' ) { if ( basebelow<min ) basebelow = min; }
- else if ( enc=='A' ) { if ( max>caphtop ) caphtop = max; }
- else if ( enc=='7' ) numh = max;
- else if ( enc=='0' ) numhtop = max;
- else if ( enc=='x' || enc=='o' || enc=='u' || enc=='v' ||
- enc =='w' || enc=='y' || enc=='z' ) {
- if ( xheighttop==-1e10 ) xheighttop = max;
- if ( xheight==-1e10 ) xheight = max;
- if ( max > xheighttop ) xheighttop = max;
- else if ( max<xheight && max>20 ) xheight = max;
- if ( enc=='y' && descent==1e10 ) descent = min;
- } else if ( enc=='l' ) ascent = max;
- else descent = min;
- }
- }
- }
- }
- ++j;
- } while ( j<_sf->subfontcnt );
-
- if ( basebelow==1e10 ) basebelow=-1e10;
-
- if ( caphtop<caph ) caphtop = caph; else if ( caph==-1e10 ) caph=caphtop;
- if ( basebelow>base ) basebelow = base; else if ( base==-1e10 ) base=basebelow;
- if ( base==-1e10 ) { base=basebelow = 0; }
- if ( xheighttop<xheight ) xheighttop = xheight; else if ( xheight==-1e10 ) xheight=xheighttop;
- bd->xheight = xheight; bd->xheighttop = xheighttop;
- bd->caph = caph; bd->caphtop = caphtop;
- bd->numh = numh; bd->numhtop = numhtop;
- bd->ascent = ascent; bd->descent = descent;
- bd->base = base; bd->basebelow = basebelow;
-
- bcnt = 0;
- if ( (pt=PSDictHasEntry(sf->private,"BlueValues"))!=NULL )
- bcnt = PVAddBlues(bd,bcnt,pt);
- if ( (pt=PSDictHasEntry(sf->private,"OtherBlues"))!=NULL )
- bcnt = PVAddBlues(bd,bcnt,pt);
- if ( bcnt==0 ) {
- if ( basebelow==-1e10 ) basebelow = base;
- if ( base==-1e10 ) base = basebelow;
- if ( xheight==-1e10 ) xheight = xheighttop;
- if ( xheighttop==-1e10 ) xheighttop = xheight;
- if ( caph==-1e10 ) caph = caphtop;
- if ( caphtop==-1e10 ) caphtop = caph;
- if ( numh==-1e10 ) numh = numhtop;
- if ( numhtop==-1e10 ) numhtop = numh;
- if ( numh!=-1e10 && (numhtop>caph-2 && numh<caphtop+2)) {
- if ( numh<caph ) caph=numh;
- if ( numhtop>caphtop ) caphtop = numhtop;
- numh = numhtop = -1e10;
- }
- if ( ascent!=-1e10 && (ascent>caph-2 && ascent<caphtop+2)) {
- if ( ascent<caph ) caph=ascent;
- if ( ascent>caphtop ) caphtop = ascent;
- ascent = -1e10;
- }
- if ( ascent!=-1e10 && (ascent>numh-2 && ascent<numhtop+2)) {
- if ( ascent<numh ) numh=ascent;
- if ( ascent>numhtop ) numhtop = ascent;
- ascent = -1e10;
- if ( numhtop>caph-2 && numh<caphtop+2 ) {
- if ( numh<caph ) caph=numh;
- if ( numhtop>caphtop ) caphtop = numhtop;
- numh = numhtop = -1e10;
- }
- }
-
- if ( descent!=1e10 ) {
- bd->blues[0][0] = bd->blues[0][1] = descent;
- ++bcnt;
- }
- if ( basebelow!=-1e10 ) {
- bd->blues[bcnt][0] = basebelow;
- bd->blues[bcnt][1] = base;
- ++bcnt;
- }
- if ( xheight!=-1e10 ) {
- bd->blues[bcnt][0] = xheight;
- bd->blues[bcnt][1] = xheighttop;
- ++bcnt;
- }
- if ( numh!=-1e10 ) {
- bd->blues[bcnt][0] = numh;
- bd->blues[bcnt][1] = numhtop;
- ++bcnt;
- }
- if ( caph!=-1e10 ) {
- bd->blues[bcnt][0] = caph;
- bd->blues[bcnt][1] = caphtop;
- ++bcnt;
- }
- if ( ascent!=-1e10 ) {
- bd->blues[bcnt][0] = bd->blues[bcnt][1] = ascent;
- ++bcnt;
- }
- }
- bd->bluecnt = bcnt;
-}
-
-void ElFreeEI(EIList *el) {
- EI *e, *next;
-
- for ( e = el->edges; e!=NULL; e = next ) {
- next = e->next;
- free(e);
- }
-}
-
-static int EIAddEdge(Spline *spline, real tmin, real tmax, EIList *el) {
- EI *new = calloc(1,sizeof(EI));
- real min, max, temp;
- Spline1D *s;
- real dxdtmin, dxdtmax, dydtmin, dydtmax;
-
- new->spline = spline;
- new->tmin = tmin;
- new->tmax = tmax;
-
- s = &spline->splines[1];
- if (( dydtmin = (3*s->a*tmin + 2*s->b)*tmin + s->c )<0 ) dydtmin = -dydtmin;
- if (( dydtmax = (3*s->a*tmax + 2*s->b)*tmax + s->c )<0 ) dydtmax = -dydtmax;
- s = &spline->splines[0];
- if (( dxdtmin = (3*s->a*tmin + 2*s->b)*tmin + s->c )<0 ) dxdtmin = -dxdtmin;
- if (( dxdtmax = (3*s->a*tmax + 2*s->b)*tmax + s->c )<0 ) dxdtmax = -dxdtmax;
-
- /*s = &spline->splines[0];*/
- min = ((s->a * tmin + s->b)* tmin + s->c)* tmin + s->d;
- max = ((s->a * tmax + s->b)* tmax + s->c)* tmax + s->d;
- if ( tmax==1 ) max = spline->to->me.x; /* beware rounding errors */
- if ( !el->leavetiny && floor(min)==floor(max) ) { /* If it doesn't cross a pixel boundary then it might as well be vertical */
- if ( tmin==0 ) max = min;
- else if ( tmax==1 ) min = max;
- else max = min;
- }
- if ( min==max )
- new->vert = true;
- else if ( min<max )
- new->hup = true;
- else {
- temp = min; min = max; max=temp;
- }
- if ( !el->leavetiny && min+1>max ) new->almostvert = true;
- if ( 40*dxdtmin<dydtmin ) new->vertattmin = true;
- if ( 40*dxdtmax<dydtmax ) new->vertattmax = true;
- /*if ( new->vertattmin && new->vertattmax && s->a==0 && s->b==0 ) new->almostvert = true;*/
- new->coordmin[0] = min; new->coordmax[0] = max;
- if ( el->coordmin[0]>min )
- el->coordmin[0] = min;
- if ( el->coordmax[0]<max )
- el->coordmax[0] = max;
-
- s = &spline->splines[1];
- min = ((s->a * tmin + s->b)* tmin + s->c)* tmin + s->d;
- max = ((s->a * tmax + s->b)* tmax + s->c)* tmax + s->d;
- if ( tmax==1 ) max = spline->to->me.y;
- if ( !el->leavetiny && floor(min)==floor(max) ) { /* If it doesn't cross a pixel boundary then it might as well be horizontal */
- if ( tmin==0 ) max = min;
- else if ( tmax==1 ) min = max;
- else max = min;
- }
- if ( min==max )
- new->hor = true;
- else if ( min<max )
- new->vup = true;
- else {
- temp = min; min = max; max=temp;
- }
- if ( !el->leavetiny && min+1>max ) new->almosthor = true;
- if ( 40*dydtmin<dxdtmin ) new->horattmin = true;
- if ( 40*dydtmax<dxdtmax ) new->horattmax = true;
- /*if ( new->horattmin && new->horattmax && s->a==0 && s->b==0 ) new->almosthor = true;*/
- new->coordmin[1] = min; new->coordmax[1] = max;
- if ( el->coordmin[1]>min )
- el->coordmin[1] = min;
- if ( el->coordmax[1]<max )
- el->coordmax[1] = max;
-
- if ( new->hor && new->vert ) {
- /* This spline is too small for us to notice */
- free(new);
-return( false );
- } else {
- new->next = el->edges;
- el->edges = new;
-
- if ( el->splinelast!=NULL )
- el->splinelast->splinenext = new;
- el->splinelast = new;
- if ( el->splinefirst==NULL )
- el->splinefirst = new;
-
-return( true );
- }
-}
-
-static void EIAddSpline(Spline *spline, EIList *el) {
- extended ts[6], temp;
- int i, j, base, last;
-
- ts[0] = 0; ts[5] = 1.0;
- SplineFindExtrema(&spline->splines[0],&ts[1],&ts[2]);
- SplineFindExtrema(&spline->splines[1],&ts[3],&ts[4]);
- /* avoid teeny tiny segments, they just confuse us */
- SplineRemoveExtremaTooClose(&spline->splines[0],&ts[1],&ts[2]);
- SplineRemoveExtremaTooClose(&spline->splines[1],&ts[3],&ts[4]);
- for ( i=0; i<4; ++i ) for ( j=i+1; j<5; ++j ) {
- if ( ts[i]>ts[j] ) {
- temp = ts[i];
- ts[i] = ts[j];
- ts[j] = temp;
- }
- }
- for ( base=0; ts[base]==-1; ++base);
- for ( i=5; i>base ; --i ) {
- if ( ts[i]==ts[i-1] ) {
- for ( j=i-1; j>base; --j )
- ts[j] = ts[j-1];
- ts[j] = -1;
- ++base;
- }
- }
- last = base;
- for ( i=base; i<5 ; ++i )
- if ( EIAddEdge(spline,ts[last],ts[i+1],el) )
- last = i+1;
-}
-
-void ELFindEdges(SplineChar *sc, EIList *el) {
- Spline *spline, *first;
- SplineSet *spl;
-
- el->sc = sc;
- if ( sc->layers[el->layer].splines==NULL )
-return;
-
- el->coordmin[0] = el->coordmax[0] = sc->layers[el->layer].splines->first->me.x;
- el->coordmin[1] = el->coordmax[1] = sc->layers[el->layer].splines->first->me.y;
-
- for ( spl = sc->layers[el->layer].splines; spl!=NULL; spl = spl->next ) if ( spl->first->prev!=NULL && spl->first->prev->from!=spl->first ) {
- first = NULL;
- for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
- EIAddSpline(spline,el);
- if ( first==NULL ) first = spline;
- }
- if ( el->splinefirst!=NULL && spl->first->prev!=NULL )
- el->splinelast->splinenext = el->splinefirst;
- el->splinelast = NULL; el->splinefirst = NULL;
- }
-}
-
-static int IsBiggerSlope(EI *test, EI *base, int major) {
- int other = !major;
- real tdo, tdm, bdo, bdm, t;
-
- if (( major && test->vup ) || (!major && test->hup))
- t = test->tmin;
- else
- t = test->tmax;
- tdm = (3*test->spline->splines[major].a*t + 2*test->spline->splines[major].b)*t + test->spline->splines[major].c;
- tdo = (3*test->spline->splines[other].a*t + 2*test->spline->splines[other].b)*t + test->spline->splines[other].c;
-
- if (( major && base->vup ) || (!major && base->hup))
- t = base->tmin;
- else
- t = base->tmax;
- bdm = (3*base->spline->splines[major].a*t + 2*base->spline->splines[major].b)*t + base->spline->splines[major].c;
- bdo = (3*base->spline->splines[other].a*t + 2*base->spline->splines[other].b)*t + base->spline->splines[other].c;
-
- if ( tdm==0 && bdm==0 )
-return( tdo > bdo );
- if ( tdo==0 )
-return( tdo>0 );
- else if ( bdo==0 )
-return( bdo>0 );
-
-return( tdo/tdm > bdo/bdm );
-}
-
-void ELOrder(EIList *el, int major ) {
- int other = !major;
- int pos;
- EI *ei, *prev, *test;
-
- el->low = floor(el->coordmin[major]); el->high = ceil(el->coordmax[major]);
- el->cnt = el->high-el->low+1;
- el->ordered = calloc(el->cnt,sizeof(EI *));
- el->ends = calloc(el->cnt,1);
-
- for ( ei = el->edges; ei!=NULL ; ei=ei->next ) {
- pos = ceil(ei->coordmax[major])-el->low;
- el->ends[pos] = true;
- pos = floor(ei->coordmin[major])-el->low;
- ei->ocur = (ei->hup == ei->vup)?ei->coordmin[other]:ei->coordmax[other];
- ei->tcur = ((major && ei->vup) || (!major && ei->hup)) ?
- ei->tmin: ei->tmax;
- if ( major ) {
- ei->up = ei->vup;
- ei->hv = (ei->vert || ei->almostvert);
- ei->hvbottom = ei->vup ? ei->vertattmin : ei->vertattmax;
- ei->hvtop =!ei->vup ? ei->vertattmin : ei->vertattmax;
- if ( ei->hor || ei->almosthor)
- continue;
- } else {
- ei->up = ei->hup;
- ei->hv = (ei->hor || ei->almosthor);
- ei->hvbottom = ei->hup ? ei->horattmin : ei->horattmax;
- ei->hvtop =!ei->hup ? ei->horattmin : ei->horattmax;
- if ( ei->vert || ei->almostvert)
- continue;
- }
- if ( el->ordered[pos]==NULL || ei->ocur<el->ordered[pos]->ocur ) {
- ei->ordered = el->ordered[pos];
- el->ordered[pos] = ei;
- } else {
- for ( prev=el->ordered[pos], test = prev->ordered; test!=NULL;
- prev = test, test = test->ordered ) {
- if ( test->ocur>ei->ocur ||
- (test->ocur==ei->ocur && IsBiggerSlope(test,ei,major)))
- break;
- }
- ei->ordered = test;
- prev->ordered = ei;
- }
- }
-}
-
-static HintInstance *HIMerge(HintInstance *into, HintInstance *hi) {
- HintInstance *n, *first = NULL, *last = NULL;
-
- while ( into!=NULL && hi!=NULL ) {
- if ( into->begin<hi->begin ) {
- n = into;
- into = into->next;
- } else {
- n = hi;
- hi = hi->next;
- }
- if ( first==NULL )
- first = n;
- else
- last->next = n;
- last = n;
- }
- if ( into!=NULL ) {
- if ( first==NULL )
- first = into;
- else
- last->next = into;
- } else if ( hi!=NULL ) {
- if ( first==NULL )
- first = hi;
- else
- last->next = hi;
- }
-return( first );
-}
-
-real EITOfNextMajor(EI *e, EIList *el, real sought_m ) {
- /* We want to find t so that Mspline(t) = sought_m */
- /* the curve is monotonic */
- Spline1D *msp = &e->spline->splines[el->major];
- real new_t;
- real found_m;
- real t_mmax, t_mmin;
-
- if ( msp->a==0 && msp->b==0 ) {
- if ( msp->c == 0 ) {
- IError("Hor/Vert line when not expected");
-return( 0 );
- }
- new_t = (sought_m-msp->d)/(msp->c);
-return( new_t );
- }
-
- t_mmax = e->up?e->tmax:e->tmin;
- t_mmin = e->up?e->tmin:e->tmax;
- /* sought_m += el->low; */
-
- while ( 1 ) {
- new_t = (t_mmin+t_mmax)/2;
- found_m = ( ((msp->a*new_t+msp->b)*new_t+msp->c)*new_t + msp->d );
- if ( found_m>sought_m-.001 && found_m<sought_m+.001 )
-return( new_t );
- if ( found_m > sought_m ) {
- t_mmax = new_t;
- } else {
- t_mmin = new_t;
- }
- if ( t_mmax==t_mmin ) {
- IError("EITOfNextMajor failed! on %s", el->sc!=NULL?el->sc->name:"Unknown" );
-return( new_t );
- }
- }
-}
-
-EI *EIActiveListReorder(EI *active,int *change) {
- int any;
- EI *pr, *apt;
-
- *change = false;
- if ( active!=NULL ) {
- any = true;
- while ( any ) {
- any = false;
- for ( pr=NULL, apt=active; apt->aenext!=NULL; ) {
- if ( apt->ocur <= apt->aenext->ocur ) {
- /* still ordered */;
- pr = apt;
- apt = apt->aenext;
- } else if ( pr==NULL ) {
- active = apt->aenext;
- apt->aenext = apt->aenext->aenext;
- active->aenext = apt;
- *change = true;
- /* don't need to set any, since this reorder can't disorder the list */
- pr = active;
- } else {
- pr->aenext = apt->aenext;
- apt->aenext = apt->aenext->aenext;
- pr->aenext->aenext = apt;
- any = *change = true;
- pr = pr->aenext;
- }
- }
- }
- }
-return( active );
-}
-
-EI *EIActiveEdgesRefigure(EIList *el, EI *active,real i,int major, int *_change) {
- EI *apt, *pr, *npt;
- int change = false, subchange;
- int other = !major;
-
- /* first remove any entry which doesn't intersect the new scan line */
- /* (ie. stopped on last line) */
- for ( pr=NULL, apt=active; apt!=NULL; apt = apt->aenext ) {
- if ( apt->coordmax[major]<i+el->low ) {
- if ( pr==NULL )
- active = apt->aenext;
- else
- pr->aenext = apt->aenext;
- change = true;
- } else
- pr = apt;
- }
- /* then move the active list to the next line */
- for ( apt=active; apt!=NULL; apt = apt->aenext ) {
- Spline1D *osp = &apt->spline->splines[other];
- apt->tcur = EITOfNextMajor(apt,el,i+el->low);
- apt->ocur = ( ((osp->a*apt->tcur+osp->b)*apt->tcur+osp->c)*apt->tcur + osp->d );
- }
- /* reorder list */
- active = EIActiveListReorder(active,&subchange);
- if ( subchange ) change = true;
-
- /* Insert new nodes */
- if ( el->ordered[(int) i]!=NULL ) change = true;
- for ( pr=NULL, apt=active, npt=el->ordered[(int) i]; apt!=NULL && npt!=NULL; ) {
- if ( npt->ocur<apt->ocur ) {
- npt->aenext = apt;
- if ( pr==NULL )
- active = npt;
- else
- pr->aenext = npt;
- pr = npt;
- npt = npt->ordered;
- } else {
- pr = apt;
- apt = apt->aenext;
- }
- }
- while ( npt!=NULL ) {
- npt->aenext = NULL;
- if ( pr==NULL )
- active = npt;
- else
- pr->aenext = npt;
- pr = npt;
- npt = npt->ordered;
- }
- *_change = change;
-return( active );
-}
-
-/* Should I consider e and n to be a continuation of the same spline? */
-/* If we are at an intersection (and it's the same intersection on both) */
-/* and they go in vaguely the same direction then we should */
-/* Ah, but also if they are at different intersections and are connected */
-/* by a series of horizontal/vertical lines (whichever are invisible to major)*/
-/* then we still should. */
-int EISameLine(EI *e, EI *n, real i, int major) {
- EI *t;
-
- if ( n!=NULL && /*n->up==e->up &&*/
- (ceil(e->coordmin[major])==i || floor(e->coordmin[major])==i || floor(e->coordmax[major])==i || ceil(e->coordmax[major])==i) &&
- (ceil(n->coordmin[major])==i || floor(n->coordmin[major])==i || floor(n->coordmax[major])==i || ceil(n->coordmax[major])==i) ) {
- if (
- (n==e->splinenext && n->tmin==e->tmax &&
- n->tcur<n->tmin+.2 && e->tcur>e->tmax-.2 ) ||
- (n->splinenext==e && n->tmax==e->tmin &&
- n->tcur>n->tmax-.2 && e->tcur<e->tmin+.2 ) )
-return( true );
- /* can be separated by a horizontal/vertical line in the other direction */
- if ( n->tmax==1 && e->tmin==0 && n->tcur>.8 && e->tcur<.2) {
- t = n;
- while ( (t = t->splinenext)!=e ) {
- if ( t==NULL || t==n ||
- (major && !t->hor) || ( !major && !t->vert ))
-return( false );
- }
-return( n->up==e->up );
- } else if ( n->tmin==0 && e->tmax==1 && n->tcur<.2 && e->tcur>.8) {
- t = e;
- while ( (t = t->splinenext)!=n ) {
- if ( t==NULL || t==e ||
- (major && !t->hor) || ( !major && !t->vert ))
-return( false );
- }
-return( n->up==e->up );
- }
- }
-return( false );
-}
-
-int EISkipExtremum(EI *e, real i, int major) {
- EI *n = e->aenext, *t;
-
- if ( n==NULL )
-return( false );
- if (
- (ceil(e->coordmin[major])==i || floor(e->coordmin[major])==i || floor(e->coordmax[major])==i || ceil(e->coordmax[major])==i) &&
- (ceil(n->coordmin[major])==i || floor(n->coordmin[major])==i || floor(n->coordmax[major])==i || ceil(n->coordmax[major])==i) ) {
- if (
- (n==e->splinenext && n->tmin==e->tmax &&
- n->tcur<n->tmin+.2 && e->tcur>e->tmax-.2 ) ||
- (n->splinenext==e && n->tmax==e->tmin &&
- n->tcur>n->tmax-.2 && e->tcur<e->tmin+.2 ) )
-return( n->up!=e->up );
- /* can be separated by a horizontal/vertical line in the other direction */
- if ( n->tmax==1 && e->tmin==0 && n->tcur>.8 && e->tcur<.2) {
- t = n;
- while ( (t = t->splinenext)!=e ) {
- if ( t==NULL || t==n ||
- (major && !t->hor) || ( !major && !t->vert ))
-return( false );
- }
-return( n->up!=e->up );
- } else if ( n->tmin==0 && e->tmax==1 && n->tcur<.2 && e->tcur>.8) {
- t = e;
- while ( (t = t->splinenext)!=n ) {
- if ( t==NULL || t==e ||
- (major && !t->hor) || ( !major && !t->vert ))
-return( false );
- }
-return( n->up!=e->up );
- }
- }
-return( false );
-}
-
-static StemInfo *StemRemoveFlexCandidates(StemInfo *stems) {
- StemInfo *s, *t, *sn;
- const real BlueShift = 7;
- /* Suppose we have something that is a flex candidate */
- /* We might get two hints from it... one from the two end points */
- /* and one from the internal point */
-
- if ( stems==NULL )
-return( NULL );
-
- for ( s=stems; (sn = s->next)!=NULL; s = sn ) {
- if ( s->start+BlueShift > sn->start && s->width>0 && sn->width>0 &&
- s->start+s->width-BlueShift < sn->start+sn->width &&
- s->start+s->width+BlueShift > sn->start+sn->width &&
- s->where != NULL && sn->where != NULL &&
- s->where->next!=NULL && sn->where->next==NULL ) {
- t = sn->next;
- sn->next = NULL;
- StemInfoFree(sn);
- s->next = t;
- sn = t;
- if ( t==NULL )
- break;
- }
- }
-return( stems );
-}
-
-real HIlen( StemInfo *stems) {
- HintInstance *hi;
- real len = 0;
-
- for ( hi=stems->where; hi!=NULL; hi = hi->next )
- len += hi->end-hi->begin;
-return( len );
-}
-
-real HIoverlap( HintInstance *mhi, HintInstance *thi) {
- HintInstance *hi;
- real len = 0;
- real s, e;
-
- for ( ; mhi!=NULL; mhi = mhi->next ) {
- for ( hi = thi; hi!=NULL && hi->begin<=mhi->end; hi = hi->next ) {
- if ( hi->end<mhi->begin ) {
- thi = hi;
- continue;
- }
- s = hi->begin<mhi->begin?mhi->begin:hi->begin;
- e = hi->end>mhi->end?mhi->end:hi->end;
- if ( e<s )
- continue; /* Shouldn't happen */
- len += e-s;
- }
- }
-return( len );
-}
-
-int StemListAnyConflicts(StemInfo *stems) {
- StemInfo *s;
- int any= false;
- double end;
-
- for ( s=stems; s!=NULL ; s=s->next )
- s->hasconflicts = false;
- while ( stems!=NULL ) {
- end = stems->width<0 ? stems->start : stems->start+stems->width;
- for ( s=stems->next; s!=NULL && (s->width>0 ? s->start : s->start+s->width)<=end; s=s->next ) {
- stems->hasconflicts = true;
- s->hasconflicts = true;
- any = true;
- }
- stems = stems->next;
- }
-return( any );
-}
-
-HintInstance *HICopyTrans(HintInstance *hi, real mul, real offset) {
- HintInstance *first=NULL, *last, *cur, *p;
-
- while ( hi!=NULL ) {
- cur = chunkalloc(sizeof(HintInstance));
- if ( mul>0 ) {
- cur->begin = hi->begin*mul+offset;
- cur->end = hi->end*mul+offset;
- if ( first==NULL )
- first = cur;
- else
- last->next = cur;
- last = cur;
- } else {
- cur->begin = hi->end*mul+offset;
- cur->end = hi->begin*mul+offset;
- if ( first==NULL || cur->begin<first->begin ) {
- cur->next = first;
- first = cur;
- } else {
- for ( p=first, last=p->next; last!=NULL && cur->begin>last->begin; last=last->next );
- p->next = cur;
- cur->next = last;
- }
- }
- hi = hi->next;
- }
-return( first );
-}
-
-static HintInstance *StemAddHIFromActive(struct stemdata *stem,int major) {
- int i;
- HintInstance *head = NULL, *cur, *t;
- double mino, maxo;
- double dir = ((real *) &stem->unit.x)[major]<0 ? -1 : 1;
-
- for ( i=0; i<stem->activecnt; ++i ) {
- mino = dir*stem->active[i].start + ((real *) &stem->left.x)[major];
- maxo = dir*stem->active[i].end + ((real *) &stem->left.x)[major];
- cur = chunkalloc(sizeof(HintInstance));
- if ( dir>0 ) {
- cur->begin = mino;
- cur->end = maxo;
- if ( head==NULL )
- head = cur;
- else
- t->next = cur;
- t = cur;
- } else {
- cur->begin = maxo;
- cur->end = mino;
- cur->next = head;
- head = cur;
- }
- }
-return( head );
-}
-
-static HintInstance *DStemAddHIFromActive( struct stemdata *stem ) {
- int i;
- HintInstance *head = NULL, *cur, *t;
-
- for ( i=0; i<stem->activecnt; ++i ) {
- cur = chunkalloc( sizeof( HintInstance ));
- cur->begin = stem->active[i].start;
- cur->end = stem->active[i].end;
- if ( head == NULL )
- head = cur;
- else
- t->next = cur;
- t = cur;
- }
-return( head );
-}
-
-void SCGuessHintInstancesList( SplineChar *sc,int layer,StemInfo *hstem,StemInfo *vstem,DStemInfo *dstem,
- int hvforce,int dforce ) {
-
- struct glyphdata *gd;
- struct stemdata *sd;
- int i, cnt=0, hneeds_gd=false, vneeds_gd=false, dneeds_gd=false;
- StemInfo *test;
- DStemInfo *dtest;
- double em_size = ( sc->parent != NULL ) ?
- sc->parent->ascent + sc->parent->descent : 1000;
-
- if ( hstem == NULL && vstem == NULL && dstem == NULL )
-return;
- /* If all stems already have active zones assigned (actual for .sfd */
- /* files), then there is no need to wast time generating glyph data for */
- /* this glyph */
- test = hstem;
- while ( !hneeds_gd && test != NULL ) {
- if ( test->where == NULL || hvforce ) hneeds_gd = true;
- test = test->next;
- }
- test = vstem;
- while ( !vneeds_gd && test != NULL ) {
- if ( test->where == NULL || hvforce ) vneeds_gd = true;
- test = test->next;
- }
- dtest = dstem;
- while ( !dneeds_gd && dtest != NULL ) {
- if ( dtest->where == NULL || dforce ) dneeds_gd = true;
- dtest = dtest->next;
- }
- if ( !hneeds_gd && !vneeds_gd && !dneeds_gd )
-return;
-
- gd = GlyphDataInit( sc,layer,em_size,!dneeds_gd );
- if ( gd == NULL )
-return;
-
- cnt = 0;
- if ( hstem != NULL && hneeds_gd ) {
- gd = StemInfoToStemData( gd,hstem,false );
- for ( i=cnt; i<gd->stemcnt; i++ ) {
- sd = &gd->stems[i];
- if ( hstem == NULL )
- break;
- if ( hstem->where == NULL || hvforce )
- hstem->where = StemAddHIFromActive( sd,false );
- hstem = hstem->next;
- }
- }
- cnt = gd->stemcnt;
- if ( vstem != NULL && vneeds_gd ) {
- gd = StemInfoToStemData( gd,vstem,true );
- for ( i=cnt; i<gd->stemcnt; i++ ) {
- sd = &gd->stems[i];
- if ( vstem == NULL )
- break;
- if ( vstem->where == NULL || hvforce )
- vstem->where = StemAddHIFromActive( sd,true );
- vstem = vstem->next;
- }
- }
- cnt = gd->stemcnt;
- if ( dstem != NULL && dneeds_gd ) {
- gd = DStemInfoToStemData( gd,dstem );
- for ( i=cnt; i<gd->stemcnt; i++ ) {
- sd = &gd->stems[i];
- if ( dstem == NULL )
- break;
- dstem->left = sd->left; dstem->right = sd->right;
- if ( dstem->where == NULL || dforce )
- dstem->where = DStemAddHIFromActive( sd );
- dstem = dstem->next;
- }
- }
- GlyphDataFree( gd );
-return;
-}
-
-/* We have got (either from a file or user specified) a diagonal stem,
- described by 4 base points (pairs of x and y coordinates). Some additional
- tests are required before we can add this stem to the given glyph. */
-int MergeDStemInfo( SplineFont *sf,DStemInfo **ds,DStemInfo *test ) {
- DStemInfo *dn, *cur, *prev, *next, *temp;
- double dot, loff, roff, soff, dist_error_diag ;
- double ibegin, iend;
- int overlap;
- BasePoint *base, *nbase, *pbase;
- HintInstance *hi;
-
- if ( *ds == NULL ) {
- *ds = test;
-return( true );
- }
- dist_error_diag = ( sf->ascent + sf->descent ) * 0.0065;
-
- cur = prev = NULL;
- for ( dn=*ds ; dn!=NULL ; dn=dn->next ) {
- prev = cur; cur = dn;
-
- /* Compare the given stem with each of the existing diagonal stem
- * hints. First ensure that it is not an exact duplicate of an already
- * added stem. Then test if unit vectors are parallel and edges colinear.
- * In this case we should either preserve the existing stem or replace
- * it with the new one, but not keep them both */
- if (test->unit.x == dn->unit.x && test->unit.y == dn->unit.y &&
- test->left.x == dn->left.x && test->left.y == dn->left.y &&
- test->right.x == dn->right.x && test->right.y == dn->right.y ) {
- DStemInfoFree( test );
-return( false );
- }
- dot = ( test->unit.x * dn->unit.y ) -
- ( test->unit.y * dn->unit.x );
- if ( dot <= -0.5 || dot >= 0.5 )
- continue;
-
- loff = ( test->left.x - dn->left.x ) * dn->unit.y -
- ( test->left.y - dn->left.y ) * dn->unit.x;
- roff = ( test->right.x - dn->right.x ) * dn->unit.y -
- ( test->right.y - dn->right.y ) * dn->unit.x;
- if (loff <= -dist_error_diag || loff >= dist_error_diag ||
- roff <= -dist_error_diag || roff >= dist_error_diag )
- continue;
- soff = ( test->left.x - dn->left.x ) * dn->unit.x +
- ( test->left.y - dn->left.y ) * dn->unit.y;
- overlap = false;
- if ( dn->where != NULL && test->where != NULL && test->where->next == NULL ) {
- ibegin = test->where->begin + soff;
- iend = test->where->end + soff;
- for ( hi = dn->where; hi != NULL; hi = hi->next ) {
- if (( hi->begin <= ibegin && ibegin <= hi->end ) ||
- ( hi->begin <= iend && iend <= hi->end ) ||
- ( ibegin <= hi->begin && hi->end <= iend )) {
- overlap = true;
- break;
- }
- }
- } else
- overlap = true;
- /* It's probably a colinear dstem, as in older SFD files. Treat */
- /* it as one more instance for the already added stem */
- if ( !overlap ) {
- for ( hi=dn->where; hi->next != NULL; hi = hi->next ) ;
- hi->next = chunkalloc( sizeof( HintInstance ));
- hi->next->begin = ibegin; hi->next->end = iend;
- DStemInfoFree( test );
-return( false );
- /* The found stem is close but not identical to the stem we */
- /* are going to add. So just replace the older stem with the */
- /* new one */
- } else {
- test->next = dn->next;
- if ( prev == NULL )
- *ds = test;
- else
- prev->next = test;
- DStemInfoFree( dn );
-return( true );
- }
- }
-
- /* Insert the given stem to the list by such a way that diagonal
- * stems are ordered by the X coordinate of the left edge key point, and
- * by Y if X is the same. The order is arbitrary, but may be essential for
- * things like "W". So we should be sure that the autoinstructor will
- * process diagonals from left to right. */
- base = ( test->unit.y < 0 ) ? &test->right : &test->left;
- nbase = ( (*ds)->unit.y < 0 ) ? &(*ds)->right : &(*ds)->left;
-
- if ( base->x < nbase->x || ( base->x == nbase->x && base->y >= nbase->y )) {
- temp = *ds; *ds = test;
- (*ds)->next = temp;
- } else {
- for ( dn=*ds ; dn!=NULL && dn!=test ; dn=dn->next ) {
- next = dn->next;
- pbase = ( dn->unit.y < 0 ) ? &dn->right : &dn->left;
- if ( next != NULL )
- nbase = ( next->unit.y < 0 ) ? &next->right : &next->left;
-
- if (( pbase->x < base->x ||
- ( pbase->x == base->x && pbase->y >= base->y )) &&
- ( next == NULL || base->x < nbase->x ||
- ( base->x == nbase->x && base->y >= nbase->y ))) {
-
- test->next = next; dn->next = test;
- break;
- }
-
- }
- }
-return( true );
-}
-
-static StemInfo *RefHintsMerge(StemInfo *into, StemInfo *rh, real mul, real offset,
- real omul, real oofset) {
- StemInfo *prev, *h, *n;
- real start, width;
-
- for ( ; rh!=NULL; rh=rh->next ) {
- start = rh->start*mul + offset;
- width = rh->width *mul;
- if ( width<0 ) {
- start += width; width = -width;
- }
- for ( h=into, prev=NULL; h!=NULL && (start>h->start || (start==h->start && width>h->width)); prev=h, h=h->next );
- if ( h==NULL || start!=h->start || width!=h->width ) {
- n = chunkalloc(sizeof(StemInfo));
- n->start = start; n->width = width;
- n->ghost = rh->ghost;
- n->next = h;
- if ( prev==NULL )
- into = n;
- else
- prev->next = n;
- n->where = HICopyTrans(rh->where,omul,oofset);
- } else
- h->where = HIMerge(h->where,HICopyTrans(rh->where,omul,oofset));
- }
-return( into );
-}
-
-static DStemInfo *RefDHintsMerge( SplineFont *sf,DStemInfo *into,DStemInfo *rh,
- real xmul,real xoffset,real ymul,real yoffset ) {
- DStemInfo *new;
- double dmul;
-
- for ( ; rh!=NULL; rh=rh->next ) {
- new = chunkalloc( sizeof( DStemInfo ));
- *new = *rh;
- new->left.x = xmul*new->left.x + xoffset;
- new->right.x = xmul*new->right.x + xoffset;
- new->left.y = ymul*new->left.y + yoffset;
- new->right.y = ymul*new->right.y + yoffset;
- new->next = NULL;
- if (( xmul < 0 && ymul > 0 ) || ( xmul > 0 && ymul < 0 ))
- new->unit.y = -new->unit.y;
- new->unit.x *= fabs( xmul ); new->unit.y *= fabs( ymul );
- dmul = sqrt( pow( new->unit.x,2 ) + pow( new->unit.y,2 ));
- new->unit.x /= dmul; new->unit.y /= dmul;
- if ( xmul < 0 ) dmul = -dmul;
- new->where = HICopyTrans( rh->where,dmul,0 );
-
- MergeDStemInfo( sf,&into,new );
- }
-return( into );
-}
-
-static void __SplineCharAutoHint( SplineChar *sc, int layer, BlueData *bd, int gen_undoes );
-
-static void AutoHintRefs(SplineChar *sc,int layer, BlueData *bd, int picky, int gen_undoes) {
- RefChar *ref;
-
- /* Add hints for base characters before accent hints => if there are any */
- /* conflicts, the base characters win */
- for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next ) {
- if ( ref->transform[1]==0 && ref->transform[2]==0 ) {
- if ( picky ) {
- if ( !ref->sc->manualhints && ref->sc->changedsincelasthinted &&
- (ref->sc->layers[layer].refs!=NULL &&
- ref->sc->layers[layer].splines==NULL))
- AutoHintRefs(ref->sc,layer,bd,true,gen_undoes);
- } else if ( !ref->sc->manualhints && ref->sc->changedsincelasthinted )
- __SplineCharAutoHint(ref->sc,layer,bd,gen_undoes);
- if ( ref->sc->unicodeenc!=-1 && ref->sc->unicodeenc<0x10000 &&
- isalnum(ref->sc->unicodeenc) ) {
- sc->hstem = RefHintsMerge(sc->hstem,ref->sc->hstem,ref->transform[3], ref->transform[5], ref->transform[0], ref->transform[4]);
- sc->vstem = RefHintsMerge(sc->vstem,ref->sc->vstem,ref->transform[0], ref->transform[4], ref->transform[3], ref->transform[5]);
- sc->dstem = RefDHintsMerge(sc->parent,sc->dstem,ref->sc->dstem,ref->transform[0], ref->transform[4], ref->transform[3], ref->transform[5]);
- }
- }
- }
-
- for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next ) {
- if ( ref->transform[1]==0 && ref->transform[2]==0 &&
- (ref->sc->unicodeenc==-1 || ref->sc->unicodeenc>=0x10000 ||
- !isalnum(ref->sc->unicodeenc)) ) {
- sc->hstem = RefHintsMerge(sc->hstem,ref->sc->hstem,ref->transform[3], ref->transform[5], ref->transform[0], ref->transform[4]);
- sc->vstem = RefHintsMerge(sc->vstem,ref->sc->vstem,ref->transform[0], ref->transform[4], ref->transform[3], ref->transform[5]);
- sc->dstem = RefDHintsMerge(sc->parent,sc->dstem,ref->sc->dstem,ref->transform[0], ref->transform[4], ref->transform[3], ref->transform[5]);
- }
- }
-
- sc->vconflicts = StemListAnyConflicts(sc->vstem);
- sc->hconflicts = StemListAnyConflicts(sc->hstem);
-}
-
-static void _SCClearHintMasks(SplineChar *sc,int layer, int counterstoo) {
- SplineSet *spl;
- SplinePoint *sp;
- RefChar *ref;
-
- if ( layer<0 || layer>=sc->layer_cnt )
- return;
-
- if ( counterstoo ) {
- free(sc->countermasks);
- sc->countermasks = NULL; sc->countermask_cnt = 0;
- }
-
- for ( spl = sc->layers[layer].splines; spl!=NULL; spl=spl->next ) {
- for ( sp = spl->first ; ; ) {
- chunkfree(sp->hintmask,sizeof(HintMask));
- sp->hintmask = NULL;
- if ( sp->next==NULL )
- break;
- sp = sp->next->to;
- if ( sp==spl->first )
- break;
- }
- }
-
- for ( ref = sc->layers[layer].refs; ref!=NULL; ref=ref->next ) {
- for ( spl = ref->layers[0].splines; spl!=NULL; spl=spl->next ) {
- for ( sp = spl->first ; ; ) {
- chunkfree(sp->hintmask,sizeof(HintMask));
- sp->hintmask = NULL;
- if ( sp->next==NULL )
- break;
- sp = sp->next->to;
- if ( sp==spl->first )
- break;
- }
- }
- }
-}
-
-static void SCFigureSimpleCounterMasks(SplineChar *sc) {
- SplineChar *scs[MmMax];
- int hadh3, hadv3, i, vbase;
- HintMask mask;
- StemInfo *h;
-
- if ( sc->countermask_cnt!=0 )
-return;
-
- scs[0] = sc;
- hadh3 = CvtPsStem3(NULL,scs,1,true,false);
- hadv3 = CvtPsStem3(NULL,scs,1,false,false);
- if ( hadh3 || hadv3 ) {
- memset(mask,0,sizeof(mask));
- if ( hadh3 ) mask[0] = 0x80|0x40|0x20;
- if ( hadv3 ) {
- for ( h=sc->hstem, vbase=0; h!=NULL; h=h->next, ++vbase );
- for ( i=0; i<3 ; ++i ) {
- int j = i+vbase;
- mask[j>>3] |= (0x80>>(j&7));
- }
- }
- sc->countermask_cnt = 1;
- sc->countermasks = malloc(sizeof(HintMask));
- memcpy(sc->countermasks[0],mask,sizeof(HintMask));
-return;
- }
-}
-
-void SCClearHintMasks(SplineChar *sc,int layer,int counterstoo) {
- MMSet *mm = sc->parent->mm;
- int i;
-
- if ( mm==NULL )
- _SCClearHintMasks(sc,layer,counterstoo);
- else {
- for ( i=0; i<mm->instance_count; ++i ) {
- if ( sc->orig_pos<mm->instances[i]->glyphcnt )
- _SCClearHintMasks(mm->instances[i]->glyphs[sc->orig_pos],layer,counterstoo);
- }
- if ( sc->orig_pos<mm->normal->glyphcnt )
- _SCClearHintMasks(mm->normal->glyphs[sc->orig_pos],layer,counterstoo);
- }
-}
-
-static StemInfo *OnHHint(SplinePoint *sp, StemInfo *s) {
- StemInfo *possible=NULL;
- HintInstance *hi;
-
- if ( sp==NULL )
-return( NULL );
-
- for ( ; s!=NULL; s=s->next ) {
- if ( sp->me.y<s->start )
-return( possible );
- if ( s->start==sp->me.y || s->start+s->width==sp->me.y ) {
- if ( !s->hasconflicts )
-return( s );
- for ( hi=s->where; hi!=NULL; hi=hi->next ) {
- if ( hi->begin<=sp->me.x && hi->end>=sp->me.x )
-return( s );
- }
- if ( !s->used )
- possible = s;
- }
- }
-return( possible );
-}
-
-static StemInfo *OnVHint(SplinePoint *sp, StemInfo *s) {
- StemInfo *possible=NULL;
- HintInstance *hi;
-
- if ( sp==NULL )
-return( NULL );
-
- for ( ; s!=NULL; s=s->next ) {
- if ( sp->me.x<s->start )
-return( possible );
- if ( s->start==sp->me.x || s->start+s->width==sp->me.x ) {
- if ( !s->hasconflicts )
-return( s );
- for ( hi=s->where; hi!=NULL; hi=hi->next ) {
- if ( hi->begin<=sp->me.y && hi->end>=sp->me.y )
-return( s );
- }
- if ( !s->used )
- possible = s;
- }
- }
-return( possible );
-}
-
-/* Does h have a conflict with any of the stems in the list which have bits */
-/* set in the mask */
-static int ConflictsWithMask(StemInfo *stems, HintMask mask,StemInfo *h) {
- while ( stems!=NULL && stems->start<=h->start+h->width ) {
- if ( stems->start+stems->width>=h->start && stems!=h ) {
- if ( stems->hintnumber!=-1 &&
- (mask[stems->hintnumber>>3]&(0x80>>(stems->hintnumber&7))) )
-return( true );
- }
- stems = stems->next;
- }
-return( false );
-}
-
-/* All instances of a MM set must have the same hint mask at all points */
-static void FigureHintMask(SplineChar *scs[MmMax], SplinePoint *to[MmMax], int instance_count,
- HintMask mask) {
- StemInfo *s;
- int i;
- SplinePoint *sp;
-
- memset(mask,'\0',sizeof(HintMask));
-
- /* Install all hints that are always active */
- i=0; {
- SplineChar *sc = scs[i];
-
- if ( sc==NULL )
-return;
-
- for ( s=sc->hstem; s!=NULL; s=s->next )
- if ( s->hintnumber!=-1 && !s->hasconflicts )
- mask[s->hintnumber>>3] |= (0x80>>(s->hintnumber&7));
- for ( s=sc->vstem; s!=NULL; s=s->next )
- if ( s->hintnumber!=-1 && !s->hasconflicts )
- mask[s->hintnumber>>3] |= (0x80>>(s->hintnumber&7));
-
- if ( sc->hconflicts ) {
- for ( sp=to[i]; sp!=NULL; ) {
- s = OnHHint(sp,sc->hstem);
- if ( s!=NULL && s->hintnumber!=-1 ) {
- if ( ConflictsWithMask(scs[i]->hstem,mask,s))
- break;
- mask[s->hintnumber>>3] |= (0x80>>(s->hintnumber&7));
- }
- if ( sp->next==NULL )
- break;
- sp = sp->next->to;
- if ( to[i]==sp )
- break;
- }
- }
- if ( sc->vconflicts ) {
- for ( sp=to[i]; sp!=NULL; ) {
- s = OnVHint(sp,sc->vstem);
- if ( s!=NULL && s->hintnumber!=-1 ) {
- if ( ConflictsWithMask(scs[i]->vstem,mask,s))
- break;
- mask[s->hintnumber>>3] |= (0x80>>(s->hintnumber&7));
- }
- if ( sp->next==NULL )
- break;
- sp = sp->next->to;
- if ( to[i]==sp )
- break;
- }
- }
- }
- for ( i=0; i<instance_count; ++i ) if ( to[i]!=NULL ) {
- chunkfree(to[i]->hintmask,sizeof(HintMask));
- to[i]->hintmask = chunkalloc(sizeof(HintMask));
- memcpy(to[i]->hintmask,mask,sizeof(HintMask));
- }
-}
-
-static int TestHintMask(SplineChar *scs[MmMax], SplinePoint *to[MmMax], int instance_count,
- HintMask mask) {
- StemInfo *h=NULL, *v=NULL;
- int i;
-
- for ( i=0; i<instance_count; ++i ) {
- SplineChar *sc = scs[i];
-
- if ( sc==NULL || (!sc->hconflicts && !sc->vconflicts ))
- continue;
-
- /* Does this point lie on any hints? */
- if ( scs[i]->hconflicts )
- h = OnHHint(to[i],sc->hstem);
- if ( scs[i]->vconflicts )
- v = OnVHint(to[i],sc->vstem);
-
- /* Need to set this hint */
- if ( (h!=NULL && h->hintnumber!=-1 && (mask[h->hintnumber>>3]&(0x80>>(h->hintnumber&7)))==0 ) ||
- (v!=NULL && v->hintnumber!=-1 && (mask[v->hintnumber>>3]&(0x80>>(v->hintnumber&7)))==0 ))
- break;
- }
- if ( i==instance_count ) /* All hint masks were ok */
-return( false );
-
- FigureHintMask(scs,to,instance_count,mask);
-return( true );
-}
-
-static void UnnumberHints(SplineChar *sc) {
- StemInfo *h;
-
- for ( h=sc->hstem; h!=NULL; h=h->next )
- h->hintnumber = -1;
- for ( h=sc->vstem; h!=NULL; h=h->next )
- h->hintnumber = -1;
-}
-
-static int NumberHints(SplineChar *sc) {
- StemInfo *h;
- int hcnt=0;
-
- for ( h=sc->hstem; h!=NULL; h=h->next )
- h->hintnumber = hcnt>=HntMax ? -1 : hcnt++;
- for ( h=sc->vstem; h!=NULL; h=h->next )
- h->hintnumber = hcnt>=HntMax ? -1 : hcnt++;
-return( hcnt );
-}
-
-static void UntickHints(SplineChar *sc) {
- StemInfo *h;
-
- for ( h=sc->hstem; h!=NULL; h=h->next )
- h->used = false;
- for ( h=sc->vstem; h!=NULL; h=h->next )
- h->used = false;
-}
-
-struct coords {
- real coords[MmMax];
- struct coords *next;
-};
-
-typedef struct mmh {
- StemInfo *hints[MmMax], *map[MmMax];
- struct coords *where;
- struct mmh *next;
-} MMH;
-
-static void AddCoord(MMH *mmh,SplinePoint *sps[MmMax],int instance_count, int ish) {
- struct coords *coords;
- int i;
-
- coords = chunkalloc(sizeof(struct coords));
- coords->next = mmh->where;
- mmh->where = coords;
- if ( ish )
- for ( i=0; i<instance_count; ++i )
- coords->coords[i] = sps[i]->me.x;
- else
- for ( i=0; i<instance_count; ++i )
- coords->coords[i] = sps[i]->me.y;
-}
-
-static MMH *AddHintSet(MMH *hints,StemInfo *h[MmMax], int instance_count,
- SplinePoint *sps[MmMax], int ish) {
- int i, cnt, bestc;
- MMH *test, *best;
-
- for ( i=0; i<instance_count; ++i )
- if ( h[i]==NULL )
-return( hints );
-
- best = NULL; bestc = 0;
- for ( test=hints; test!=NULL; test=test->next ) {
- cnt = 0;
- for ( i=0; i<instance_count; ++i )
- if ( test->hints[i]==h[i] )
- ++cnt;
- if ( cnt==instance_count ) {
- AddCoord(test,sps,instance_count,ish);
-return( hints );
- }
- if ( cnt>bestc ) {
- bestc = cnt;
- best = test;
- }
- }
- test = chunkalloc(sizeof(MMH));
- test->next = hints;
- AddCoord(test,sps,instance_count,ish);
- for ( i=0; i<instance_count; ++i )
- test->hints[i]=h[i];
- if ( bestc!=0 ) {
- for ( i=0; i<instance_count; ++i ) {
- if ( best->hints[i]==h[i] ) {
- h[i]->hasconflicts = true;
- test->map[i] = chunkalloc(sizeof(StemInfo));
- *test->map[i] = *h[i];
- test->map[i]->where = NULL;
- test->map[i]->used = true;
- h[i]->next = test->map[i];
- } else
- test->map[i] = h[i];
- }
- } else {
- for ( i=0; i<instance_count; ++i )
- test->map[i]=h[i];
- }
-return( test );
-}
-
-static int CompareMMH(MMH *mmh1,MMH *mmh2, int instance_count) {
- int i;
-
- if ( mmh1->map[0]==NULL )
-return( 1 );
- if ( mmh2->map[0]==NULL )
-return( -1 );
-
- for ( i=0; i<instance_count; ++i ) {
- if ( mmh1->map[i]->start!=mmh2->map[i]->start ) {
- if ( mmh1->map[i]->start > mmh2->map[i]->start )
-return( 1 );
- else
-return( -1 );
- }
- }
- for ( i=0; i<instance_count; ++i ) {
- if ( mmh1->map[i]->width!=mmh2->map[i]->width ) {
- if ( mmh1->map[i]->width > mmh2->map[i]->width )
-return( 1 );
- else
-return( -1 );
- }
- }
-return( 0 );
-}
-
-static MMH *SortMMH(MMH *head,int instance_count) {
- MMH *mmh, *p, *smallest, *psmallest, *test, *ptest;
-
- for ( mmh = head, p=NULL; mmh!=NULL ; ) {
- smallest = mmh; psmallest = p;
- ptest = mmh; test = mmh->next;
- while ( test!=NULL ) {
- if ( CompareMMH(test,smallest,instance_count)<0 ) {
- smallest = test;
- psmallest = ptest;
- }
- ptest = test;
- test = test->next;
- }
- if ( smallest!=mmh ) {
- if ( p==NULL )
- head = smallest;
- else
- p->next = smallest;
- if ( mmh->next==smallest ) {
- mmh->next = smallest->next;
- smallest->next = mmh;
- } else {
- test = mmh->next;
- mmh->next = smallest->next;
- smallest->next = test;
- psmallest->next = mmh;
- }
- }
- p = smallest;
- mmh = smallest->next;
- }
-return( head );
-}
-
-static int NumberMMH(MMH *mmh,int hstart,int instance_count) {
- int i;
- HintInstance *hi, *n;
- struct coords *coords;
-
- while ( mmh!=NULL ) {
- for ( i=0; i<instance_count; ++i ) {
- StemInfo *h = mmh->map[i];
- if ( h==NULL )
- continue;
-
- h->hintnumber = hstart;
-
- for ( hi=h->where; hi!=NULL; hi=n ) {
- n = hi->next;
- chunkfree(hi,sizeof(HintInstance));
- }
- h->where = NULL;
- for ( coords=mmh->where; coords!=NULL; coords = coords->next ) {
- hi = chunkalloc(sizeof(HintInstance));
- hi->next = h->where;
- h->where = hi;
- hi->begin = coords->coords[i]-1;
- hi->end = coords->coords[i]+1;
- }
- }
- if ( mmh->map[0]!=NULL ) ++hstart;
- mmh = mmh->next;
- }
-return( hstart );
-}
-
-static void SortMMH2(SplineChar *scs[MmMax],MMH *mmh,int instance_count,int ish) {
- int i;
- StemInfo *h, *n;
- MMH *m;
-
- for ( i=0; i<instance_count; ++i ) {
- for ( h= ish ? scs[i]->hstem : scs[i]->vstem; h!=NULL; h=n ) {
- n = h->next;
- if ( h->hintnumber==-1 )
- StemInfoFree(h);
- }
- n = NULL;
- for ( m = mmh ; m!=NULL; m=m->next ) {
- h = m->map[i];
- if ( n!=NULL )
- n->next = h;
- else if ( ish )
- scs[i]->hstem = h;
- else
- scs[i]->vstem = h;
- n = h;
- }
- if ( n!=NULL )
- n->next = NULL;
- else if ( ish )
- scs[i]->hstem = NULL;
- else
- scs[i]->vstem = NULL;
- }
-}
-
-static void MMHFreeList(MMH *mmh) {
- MMH *mn;
- struct coords *c, *n;
-
- for ( ; mmh!=NULL; mmh = mn ) {
- mn = mmh->next;
- for ( c=mmh->where; c!=NULL; c=n ) {
- n = c->next;
- chunkfree(c,sizeof(struct coords));
- }
- chunkfree(mmh,sizeof(struct coords));
- }
-}
-
-static void SplResolveSplitHints(SplineChar *scs[MmMax], SplineSet *spl[MmMax],
- int instance_count, MMH **hs, MMH **vs) {
- SplinePoint *to[MmMax];
- StemInfo *h[MmMax], *v[MmMax];
- int i, anymore;
-
- for (;;) {
- for ( i=0; i<instance_count; ++i ) {
- if ( spl[i]!=NULL )
- to[i] = spl[i]->first;
- else
- to[i] = NULL;
- }
- for (;;) {
- for ( i=0; i<instance_count; ++i ) {
- h[i] = OnHHint(to[i],scs[i]->hstem);
- v[i] = OnVHint(to[i],scs[i]->vstem);
- }
- *hs = AddHintSet(*hs,h,instance_count,to,true);
- *vs = AddHintSet(*vs,v,instance_count,to,false);
- anymore = false;
- for ( i=0; i<instance_count; ++i ) if ( to[i]!=NULL ) {
- if ( to[i]->next==NULL ) to[i] = NULL;
- else {
- to[i] = to[i]->next->to;
- if ( to[i]==spl[i]->first ) to[i] = NULL;
- }
- if ( to[i]!=NULL ) anymore = true;
- }
- if ( !anymore )
- break;
- }
- anymore = false;
- for ( i=0; i<instance_count; ++i ) {
- if ( spl[i]!=NULL )
- spl[i] = spl[i]->next;
- if ( spl[i]!=NULL ) anymore = true;
- }
- if ( !anymore )
- break;
- }
-}
-
-static void ResolveSplitHints(SplineChar *scs[16],int layer,int instance_count) {
- /* It is possible for a single hint in one mm instance to split into two */
- /* in a different MM set. For example, we have two stems which happen */
- /* to line up in one instance but which do not in another instance. */
- /* It is even possible that there could be no instance with any conflicts */
- /* but some of the intermediate forms might conflict. */
- /* We can't deal (nor can postscript) with the case where hints change order*/
- SplinePointList *spl[MmMax];
- RefChar *ref[MmMax];
- int i, hcnt, hmax=0, anymore;
- MMH *hs=NULL, *vs=NULL;
-
- for ( i=0; i<instance_count; ++i ) {
- hcnt = NumberHints(scs[i]);
- UntickHints(scs[i]);
- if ( hcnt>hmax ) hmax = hcnt;
- spl[i] = scs[i]->layers[layer].splines;
- }
- if ( hmax==0 )
-return;
-
- SplResolveSplitHints(scs,spl,instance_count,&hs,&vs);
- anymore = false;
- for ( i=0; i<instance_count; ++i ) {
- ref[i] = scs[i]->layers[layer].refs;
- if ( ref[i]!=NULL ) anymore = true;
- }
- while ( anymore ) {
- for ( i=0; i<instance_count; ++i )
- spl[i] = ( ref[i]!=NULL ) ? ref[i]->layers[0].splines : NULL;
- SplResolveSplitHints(scs,spl,instance_count,&hs,&vs);
- anymore = false;
- for ( i=0; i<instance_count; ++i ) {
- if ( ref[i]!=NULL ) {
- ref[i] = ref[i]->next;
- if ( ref[i]!=NULL ) anymore = true;
- }
- }
- }
-
- for ( i=0; i<instance_count; ++i )
- UnnumberHints(scs[i]);
- hs = SortMMH(hs,instance_count);
- vs = SortMMH(vs,instance_count);
- hcnt = NumberMMH(hs,0,instance_count);
- hcnt = NumberMMH(vs,hcnt,instance_count);
- SortMMH2(scs,hs,instance_count,true);
- SortMMH2(scs,vs,instance_count,false);
- MMHFreeList(hs);
- MMHFreeList(vs);
-}
-
-static int SplFigureHintMasks(SplineChar *scs[MmMax], SplineSet *spl[MmMax],
- int instance_count, HintMask mask, int inited) {
- SplinePoint *to[MmMax];
- int i, anymore;
-
- anymore = false;
- for ( i=0; i<instance_count; ++i ) {
- if ( spl[i]!=NULL ) {
- SplineSetReverse(spl[i]);
- to[i] = spl[i]->first;
- anymore = true;
- } else
- to[i] = NULL;
- }
-
- /* Assign the initial hint mask */
- if ( anymore && !inited ) {
- FigureHintMask(scs,to,instance_count,mask);
- inited = true;
- }
-
- for (;;) {
- for ( i=0; i<instance_count; ++i ) {
- if ( spl[i]!=NULL )
- to[i] = spl[i]->first;
- else
- to[i] = NULL;
- }
- for (;;) {
- TestHintMask(scs,to,instance_count,mask);
- anymore = false;
- for ( i=0; i<instance_count; ++i ) if ( to[i]!=NULL ) {
- if ( to[i]->next==NULL ) to[i] = NULL;
- else {
- to[i] = to[i]->next->to;
- if ( to[i]==spl[i]->first ) to[i] = NULL;
- }
- if ( to[i]!=NULL ) anymore = true;
- }
- if ( !anymore )
- break;
- }
- anymore = false;
- for ( i=0; i<instance_count; ++i ) {
- if ( spl[i]!=NULL ) {
- SplineSetReverse(spl[i]);
- spl[i] = spl[i]->next;
- }
- if ( spl[i]!=NULL ) {
- anymore = true;
- SplineSetReverse(spl[i]);
- }
- }
- if ( !anymore )
- break;
- }
-return( inited );
-}
-
-void SCFigureHintMasks(SplineChar *sc,int layer) {
- SplineChar *scs[MmMax];
- SplinePointList *spl[MmMax];
- RefChar *ref[MmMax];
- MMSet *mm = sc->parent->mm;
- int i, instance_count, conflicts, anymore, inited;
- HintMask mask;
-
- if ( mm==NULL ) {
- scs[0] = sc;
- instance_count = 1;
- SCClearHintMasks(sc,layer,false);
- } else {
- if ( mm->apple )
-return;
- instance_count = mm->instance_count;
- for ( i=0; i<instance_count; ++i )
- if ( sc->orig_pos < mm->instances[i]->glyphcnt ) {
- scs[i] = mm->instances[i]->glyphs[sc->orig_pos];
- SCClearHintMasks(scs[i],layer,false);
- }
- ResolveSplitHints(scs,layer,instance_count);
- }
- conflicts = false;
- for ( i=0; i<instance_count; ++i ) {
- NumberHints(scs[i]);
- if ( scs[i]->hconflicts || scs[i]->vconflicts )
- conflicts = true;
- }
- if ( !conflicts && instance_count==1 ) { /* All hints always active */
- SCFigureSimpleCounterMasks(sc);
-return; /* In an MM font we may still need to resolve things like different numbers of hints */
- }
-
- for ( i=0; i<instance_count; ++i ) {
- spl[i] = scs[i]->layers[layer].splines;
- ref[i] = scs[i]->layers[layer].refs;
- }
- inited = SplFigureHintMasks(scs,spl,instance_count,mask,false);
- for (;;) {
- for ( i=0; i<instance_count; ++i ) {
- if ( ref[i]!=NULL )
- spl[i] = ref[i]->layers[0].splines;
- }
- inited = SplFigureHintMasks(scs,spl,instance_count,mask,inited);
- anymore = false;
- for ( i=0; i<instance_count; ++i ) {
- if ( ref[i]!=NULL ) {
- ref[i] = ref[i]->next;
- if ( ref[i]!=NULL ) anymore = true;
- }
- }
- if ( !anymore )
- break;
- }
- if ( instance_count==1 )
- SCFigureSimpleCounterMasks(sc);
-}
-
-static StemInfo *GDFindStems(struct glyphdata *gd, int major) {
- int i;
- StemInfo *head = NULL, *cur, *p, *t;
- StemBundle *bundle = major ? gd->vbundle : gd->hbundle;
- StemData *stem;
- int other = !major;
- double l, r;
-
- for ( i=0; i<bundle->cnt; ++i ) {
- stem = bundle->stemlist[i];
- l = (&stem->left.x)[other];
- r = (&stem->right.x)[other];
- cur = chunkalloc( sizeof( StemInfo ));
- if ( l<r ) {
- cur->start = l;
- cur->width = r - l;
- cur->haspointleft = stem->lpcnt > 0;
- cur->haspointright = stem->rpcnt > 0;
- } else {
- cur->start = r;
- cur->width = l - r;
- cur->haspointleft = stem->rpcnt > 0;
- cur->haspointright = stem->lpcnt > 0;
- }
- cur->ghost = stem->ghost;
- for ( p=NULL, t=head; t!=NULL ; p=t, t=t->next ) {
- if ( cur->start<=t->start )
- break;
- }
- cur->next = t;
- if ( p==NULL )
- head = cur;
- else
- p->next = cur;
- cur->where = StemAddHIFromActive(stem,major);
- }
- head = StemRemoveFlexCandidates(head);
-return( head );
-}
-
-static DStemInfo *GDFindDStems(struct glyphdata *gd) {
- int i;
- DStemInfo *head = NULL, *cur ;
- struct stemdata *stem;
-
- for ( i=0; i<gd->stemcnt; ++i ) {
- stem = &gd->stems[i];
- /* A real diagonal stem should consist of one or more continuous
- * ranges. Thus the number of active zones should be less then the
- * number of stem chunks (i. e. pairs of the opposite points). If
- * each chunk has its own active zone, then we probably have got
- * not a real stem, but rather two (or more) separate point pairs,
- * which occasionally happened to have nearly the same vectors and
- * to be positioned on the same lines */
- if ( stem->toobig )
- continue;
-
- if (( stem->unit.y > -.05 && stem->unit.y < .05 ) ||
- ( stem->unit.x > -.05 && stem->unit.x < .05 ))
- continue;
-
- if ( stem->lpcnt < 2 || stem->rpcnt < 2 )
- continue;
- cur = chunkalloc( sizeof(DStemInfo) );
- cur->left = stem->left;
- cur->right = stem->right;
- cur->unit = stem->unit;
- cur->where = DStemAddHIFromActive( stem );
- MergeDStemInfo(gd->sf, &head, cur);
- }
-return( head );
-}
-
-
-static bool inorder( real a, real b, real c )
-{
- return a < b && b < c;
-}
-
-/**
- * If fluffy is near enough to exact then clamp to exact.
- * If fluffy is more than Tolerance away from exact then
- * just return fluffy (no change).
- */
-static real clampToIfNear( real exact, real fluffy, real Tolerance )
-{
- if( inorder( exact - Tolerance, fluffy, exact + Tolerance ))
- return exact;
-
- return fluffy;
-}
-
-
-void _SplineCharAutoHint( SplineChar *sc, int layer, BlueData *bd, struct glyphdata *gd2,
- int gen_undoes ) {
- struct glyphdata *gd;
-
- StemInfosFree(sc->vstem); sc->vstem=NULL;
- StemInfosFree(sc->hstem); sc->hstem=NULL;
- DStemInfosFree(sc->dstem); sc->dstem=NULL;
- MinimumDistancesFree(sc->md); sc->md=NULL;
-
- free(sc->countermasks);
- sc->countermasks = NULL; sc->countermask_cnt = 0;
- /* We'll free the hintmasks when we call SCFigureHintMasks */
-
- sc->changedsincelasthinted = false;
- sc->manualhints = false;
-
- if ( (gd=gd2)==NULL )
- gd = GlyphDataBuild( sc,layer,bd,false );
- if ( gd!=NULL ) {
-
- sc->vstem = GDFindStems(gd,1);
- sc->hstem = GDFindStems(gd,0);
-
- if ( !gd->only_hv )
- sc->dstem = GDFindDStems(gd);
- if ( gd2==NULL ) GlyphDataFree(gd);
- }
-
- real AutohintRoundingTolerance = 0.005;
- StemInfo* s = sc->hstem;
- for( ; s; s = s->next )
- {
- s->width = clampToIfNear( 20.0, s->width, AutohintRoundingTolerance );
- s->width = clampToIfNear( 21.0, s->width, AutohintRoundingTolerance );
- }
-
- AutoHintRefs(sc,layer,bd,false,gen_undoes);
-}
-
-static void __SplineCharAutoHint( SplineChar *sc, int layer, BlueData *bd, int gen_undoes ) {
- MMSet *mm = sc->parent->mm;
- int i;
-
- if ( mm==NULL )
- _SplineCharAutoHint(sc,layer,bd,NULL,gen_undoes);
- else {
- for ( i=0; i<mm->instance_count; ++i )
- if ( sc->orig_pos < mm->instances[i]->glyphcnt )
- _SplineCharAutoHint(mm->instances[i]->glyphs[sc->orig_pos],layer,NULL,NULL,gen_undoes);
- if ( sc->orig_pos < mm->normal->glyphcnt )
- _SplineCharAutoHint(mm->normal->glyphs[sc->orig_pos],layer,NULL,NULL,gen_undoes);
- }
- SCFigureHintMasks(sc,layer);
-}
-
-void SplineCharAutoHint( SplineChar *sc, int layer, BlueData *bd ) {
- __SplineCharAutoHint(sc,layer,bd,true);
-}
-
-void SFSCAutoHint( SplineChar *sc, int layer, BlueData *bd ) {
- RefChar *ref;
-
- if ( sc->ticked )
-return;
- for ( ref=sc->layers[ly_fore].refs; ref!=NULL; ref=ref->next ) {
- if ( !ref->sc->ticked )
- SFSCAutoHint(ref->sc,layer,bd);
- }
- sc->ticked = true;
- SplineCharAutoHint(sc,layer,bd);
-}
-
-void SplineFontAutoHint( SplineFont *_sf,int layer) {
- int i,k;
- SplineFont *sf;
- BlueData *bd = NULL, _bd;
- SplineChar *sc;
-
- if ( _sf->mm==NULL ) {
- QuickBlues(_sf,layer,&_bd);
- bd = &_bd;
- }
-
- /* Tick the ones we don't want to AH, untick the ones that need AH */
- k=0;
- do {
- sf = _sf->subfontcnt==0 ? _sf : _sf->subfonts[k];
- for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL )
- sc->ticked = ( !sc->changedsincelasthinted || sc->manualhints );
- ++k;
- } while ( k<_sf->subfontcnt );
-
- k=0;
- do {
- sf = _sf->subfontcnt==0 ? _sf : _sf->subfonts[k];
- for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
- if ( sf->glyphs[i]->changedsincelasthinted &&
- !sf->glyphs[i]->manualhints )
- SFSCAutoHint(sf->glyphs[i],layer,bd);
- if ( !ff_progress_next()) {
- k = _sf->subfontcnt+1;
- break;
- }
- }
- ++k;
- } while ( k<_sf->subfontcnt );
-}
-
-void SplineFontAutoHintRefs( SplineFont *_sf,int layer) {
- int i,k;
- SplineFont *sf;
- BlueData *bd = NULL, _bd;
- SplineChar *sc;
-
- if ( _sf->mm==NULL ) {
- QuickBlues(_sf,layer,&_bd);
- bd = &_bd;
- }
-
- k=0;
- do {
- sf = _sf->subfontcnt==0 ? _sf : _sf->subfonts[k];
- for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
- if ( sc->changedsincelasthinted &&
- !sc->manualhints &&
- (sc->layers[layer].refs!=NULL && sc->layers[layer].splines==NULL)) {
- StemInfosFree(sc->vstem); sc->vstem=NULL;
- StemInfosFree(sc->hstem); sc->hstem=NULL;
- AutoHintRefs(sc,layer,bd,true,true);
- }
- }
- ++k;
- } while ( k<_sf->subfontcnt );
-}
-
-static void FigureStems( SplineFont *sf, real snaps[12], real cnts[12],
- int which ) {
- int i, j, k, cnt, smax=0, smin=2000;
- real stemwidths[2000];
- StemInfo *stems, *test;
- int len;
- HintInstance *hi;
-
- memset(stemwidths,'\0',sizeof(stemwidths));
-
- for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
- stems = which?sf->glyphs[i]->hstem:sf->glyphs[i]->vstem;
- for ( test=stems; test!=NULL; test = test->next ) if ( !test->ghost ) {
- if ( (j=test->width)<0 ) j= -j;
- if ( j<2000 ) {
- len = 0;
- for ( hi=test->where; hi!=NULL; hi=hi->next )
- len += hi->end-hi->begin;
- if ( len==0 ) len = 100;
- stemwidths[j] += len;
- if ( smax<j ) smax=j;
- if ( smin>j ) smin=j;
- }
- }
- }
-
- for ( i=smin, cnt=0; i<=smax; ++i ) {
- if ( stemwidths[i]!=0 )
- ++cnt;
- }
-
- if ( cnt>12 ) {
- /* Merge width windows */
- int windsize=3, j;
- for ( i=smin; i<=smax; ++i ) if ( stemwidths[i]!=0 ) {
- if ( (j = i-windsize)<0 ) j=0;
- for ( ; j<smax && j<=i+windsize; ++j )
- if ( stemwidths[i]<stemwidths[j] )
- break;
- if ( j==smax || j>i+windsize ) {
- if ( (j = i-windsize)<0 ) j=0;
- for ( ; j<smax && j<=i+windsize; ++j ) if ( j!=i ) {
- stemwidths[i] += stemwidths[j];
- stemwidths[j] = 0;
- }
- }
- }
- /* Merge adjacent widths */
- for ( i=smin; i<=smax; ++i ) {
- if ( i<=smax-1 && stemwidths[i]!=0 && stemwidths[i+1]!=0 ) {
- if ( stemwidths[i]>stemwidths[i+1] ) {
- stemwidths[i] += stemwidths[i+1];
- stemwidths[i+1] = 0;
- } else {
- if ( i<=smax-2 && stemwidths[i+2] && stemwidths[i+2]<stemwidths[i+1] ) {
- stemwidths[i+1] += stemwidths[i+2];
- stemwidths[i+2] = 0;
- }
- stemwidths[i+1] += stemwidths[i];
- stemwidths[i] = 0;
- ++i;
- }
- }
- }
- for ( i=smin, cnt=0; i<=smax; ++i ) {
- if ( stemwidths[i]!=0 )
- ++cnt;
- }
- }
- if ( cnt<=12 ) {
- for ( i=smin, cnt=0; i<=smax; ++i ) {
- if ( stemwidths[i]!=0 ) {
- snaps[cnt] = i;
- cnts[cnt++] = stemwidths[i];
- }
- }
- } else { real firstbiggest=0;
- for ( cnt = 0; cnt<12; ++cnt ) {
- int biggesti=0;
- real biggest=0;
- for ( i=smin; i<=smax; ++i ) {
- if ( stemwidths[i]>biggest ) { biggest = stemwidths[i]; biggesti=i; }
- }
- /* array must be sorted */
- if ( biggest<firstbiggest/6 )
- break;
- for ( j=0; j<cnt; ++j )
- if ( snaps[j]>biggesti )
- break;
- for ( k=cnt-1; k>=j; --k ) {
- snaps[k+1] = snaps[k];
- cnts[k+1]=cnts[k];
- }
- snaps[j] = biggesti;
- cnts[j] = biggest;
- stemwidths[biggesti] = 0;
- if ( firstbiggest==0 ) firstbiggest = biggest;
- }
- }
- for ( ; cnt<12; ++cnt ) {
- snaps[cnt] = 0;
- cnts[cnt] = 0;
- }
-}
-
-void FindHStems( SplineFont *sf, real snaps[12], real cnt[12]) {
- FigureStems(sf,snaps,cnt,1);
-}
-
-void FindVStems( SplineFont *sf, real snaps[12], real cnt[12]) {
- FigureStems(sf,snaps,cnt,0);
-}
-
-static int IsFlexSmooth(SplinePoint *sp) {
- BasePoint nvec, pvec;
- double proj_same, proj_normal;
-
- if ( sp->nonextcp || sp->noprevcp )
-return( false ); /* No continuity of slopes */
-
- nvec.x = sp->nextcp.x - sp->me.x; nvec.y = sp->nextcp.y - sp->me.y;
- pvec.x = sp->me.x - sp->prevcp.x; pvec.y = sp->me.y - sp->prevcp.y;
-
- /* Avoid cases where the slopes are 180 out of phase */
- if ( (proj_same = nvec.x*pvec.x + nvec.y*pvec.y)<=0 )
-return( false );
- if ( (proj_normal = nvec.x*pvec.y - nvec.y*pvec.x)<0 )
- proj_normal = -proj_normal;
-
- /* Something is smooth if the normal projection is 0. Let's allow for */
- /* some rounding errors */
- if ( proj_same >= 16*proj_normal )
-return( true );
-
-return( false );
-}
-
-static int _SplineCharIsFlexible(SplineChar *sc, int layer, int blueshift) {
- /* Need two splines
- outer endpoints have same x (or y) values
- inner point must be less than 20 horizontal (v) units from the outer points
- inner point must also be less than BlueShift units (defaults to 7=>6)
- (can increase BlueShift up to 21)
- the inner point must be a local extremum
- the inner point's cps must be at the x (or y) value as the extremum
- (I think)
- */
- /* We want long, nearly straight stems. If the end-points should not have
- continuous slopes, or if they do, they must be horizontal/vertical.
- This is an heuristic requirement, not part of Adobe's spec.
- */
- SplineSet *spl;
- SplinePoint *sp, *np, *pp;
- int max=0, val;
- RefChar *r;
-
- if ( sc==NULL )
-return(false);
-
- for ( spl = sc->layers[layer].splines; spl!=NULL; spl=spl->next ) {
- if ( spl->first->prev==NULL ) {
- /* Mark everything on the open path as inflexible */
- sp=spl->first;
- while ( 1 ) {
- sp->flexx = sp->flexy = false;
- if ( sp->next==NULL )
- break;
- sp = sp->next->to;
- }
- continue; /* Ignore open paths */
- }
- sp=spl->first;
- do {
- if ( sp->next==NULL || sp->prev==NULL )
- break;
- np = sp->next->to;
- pp = sp->prev->from;
- if ( !pp->flexx && !pp->flexy ) {
- sp->flexy = sp->flexx = 0;
- val = 0;
- if ( RealNear(sp->nextcp.x,sp->me.x) &&
- RealNear(sp->prevcp.x,sp->me.x) &&
- RealNear(np->me.x,pp->me.x) &&
- !RealNear(np->me.x,sp->me.x) &&
- (!IsFlexSmooth(pp) || RealNear(pp->nextcp.x,pp->me.x)) &&
- (!IsFlexSmooth(np) || RealNear(np->prevcp.x,np->me.x)) &&
- np->me.x-sp->me.x < blueshift &&
- np->me.x-sp->me.x > -blueshift ) {
- if ( (np->me.x>sp->me.x &&
- np->prevcp.x<=np->me.x && np->prevcp.x>=sp->me.x &&
- pp->nextcp.x<=pp->me.x && pp->prevcp.x>=sp->me.x ) ||
- (np->me.x<sp->me.x &&
- np->prevcp.x>=np->me.x && np->prevcp.x<=sp->me.x &&
- pp->nextcp.x>=pp->me.x && pp->prevcp.x<=sp->me.x )) {
- sp->flexx = true;
- val = np->me.x-sp->me.x;
- }
- }
- if ( RealNear(sp->nextcp.y,sp->me.y) &&
- RealNear(sp->prevcp.y,sp->me.y) &&
- RealNear(np->me.y,pp->me.y) &&
- !RealNear(np->me.y,sp->me.y) &&
- (!IsFlexSmooth(pp) || RealNear(pp->nextcp.y,pp->me.y)) &&
- (!IsFlexSmooth(np) || RealNear(np->prevcp.y,np->me.y)) &&
- np->me.y-sp->me.y < blueshift &&
- np->me.y-sp->me.y > -blueshift ) {
- if ( (np->me.y>sp->me.y &&
- np->prevcp.y<=np->me.y && np->prevcp.y>=sp->me.y &&
- pp->nextcp.y<=pp->me.y && pp->nextcp.y>=sp->me.y ) ||
- (np->me.y<sp->me.y &&
- np->prevcp.y>=np->me.y && np->prevcp.y<=sp->me.y &&
- pp->nextcp.y>=pp->me.y && pp->nextcp.y<=sp->me.y )) {
- sp->flexy = true;
- val = np->me.y-sp->me.y;
- }
- }
- if ( val<0 ) val = -val;
- if ( val>max ) max = val;
- }
- sp = np;
- } while ( sp!=spl->first );
- }
- sc->layers[layer].anyflexes = max>0;
- if ( max==0 )
- for ( r = sc->layers[layer].refs; r!=NULL ; r=r->next )
- if ( r->sc->layers[layer].anyflexes ) {
- sc->layers[layer].anyflexes = true;
- break;
- }
-return( max );
-}
-
-static void SCUnflex(SplineChar *sc, int layer) {
- SplineSet *spl;
- SplinePoint *sp;
-
- for ( spl = sc->layers[layer].splines; spl!=NULL; spl=spl->next ) {
- /* Mark everything on the path as inflexible */
- sp=spl->first;
- while ( 1 ) {
- sp->flexx = sp->flexy = false;
- if ( sp->next==NULL )
- break;
- sp = sp->next->to;
- if ( sp==spl->first )
- break;
- }
- }
- sc->layers[layer].anyflexes = false;
-}
-
-static void FlexDependents(SplineChar *sc,int layer) {
- struct splinecharlist *scl;
-
- sc->layers[layer].anyflexes = true;
- for ( scl = sc->dependents; scl!=NULL; scl=scl->next )
- FlexDependents(scl->sc,layer);
-}
-
-int SplineFontIsFlexible(SplineFont *sf,int layer, int flags) {
- int i;
- int max=0, val;
- char *pt;
- int blueshift;
- /* if the return value is bigger than 6 and we don't have a BlueShift */
- /* then we must set BlueShift to ret+1 before saving private dictionary */
- /* If the first point in a spline set is flexible, then we must rotate */
- /* the splineset */
-
- if ( flags&(ps_flag_nohints|ps_flag_noflex)) {
- for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
- SCUnflex(sf->glyphs[i],layer);
-return( 0 );
- }
-
- pt = PSDictHasEntry(sf->private,"BlueShift");
- blueshift = 21; /* maximum posible flex, not default */
- if ( pt!=NULL ) {
- blueshift = strtol(pt,NULL,10);
- if ( blueshift>21 ) blueshift = 21;
- } else if ( PSDictHasEntry(sf->private,"BlueValues")!=NULL )
- blueshift = 7; /* The BlueValues array may depend on BlueShift having its default value */
-
- for ( i=0; i<sf->glyphcnt; ++i )
- if ( sf->glyphs[i]!=NULL ) if ( sf->glyphs[i]!=NULL ) {
- val = _SplineCharIsFlexible(sf->glyphs[i],layer,blueshift);
- if ( val>max ) max = val;
- if ( sf->glyphs[i]->layers[layer].anyflexes )
- FlexDependents(sf->glyphs[i],layer);
- }
-return( max );
-}
-
-