|
View:
New views
2 Messages
—
Rating Filter:
Alert me
|
|
|
UFO Anchor pointsDear All,
The enclosed patch seeks to address UFO import and export of Anchor points. RoboFab handles anchors by emitting them as a single point contour (with just a single move type point) giving that point a name. FontForge doesn't really have the concept of an arbitrary anchor point. All anchors must be associated via a AnchorClass to a lookup. While this is great if you are doing all your OT work in fontforge, it is problematic if you are viewing fontforge purely as a design tool which links to external tools, and are viewing anchors merely as something else a designer puts into their design. To get around this philosophical clash, this patch programs the UFO import to read any anchor beginning with _ as a mark type anchor (as is the fontlab convention). All other anchors are considered simply basechar anchors. We then create a hardwired named lookup (_holdAnchors) of type mark2base with a subtable (_someAnchors) and put all the AnchorClasses we need in there. I don't necessarily think this is the best way to address this issue. But it is one way that seems to work. I hope others can come up with a better approach to solving this. The output routine outputs all anchors as single point contours as per RoboFab. There are some spurious changes due to unexpanding the code layout to ensure appropriate tabbing. I don't know how strict the coding culture is on this code. Yours, Martin [fontforge-hg_rev5079.patch] # HG changeset patch # User Martin Hosken <martin_hosken@...> # Date 1254974960 -25200 # Branch mhosken # Node ID 8b00f4e32f2888b3e175ed1ebb7c0d63ce98e750 # Parent 00fa00d5781362cb6fe7d97a7c600f9a85b17259 Add anchor support to UFO diff -r 00fa00d57813 -r 8b00f4e32f28 fontforge/ufo.c --- a/fontforge/ufo.c Thu Oct 08 08:22:55 2009 +0700 +++ b/fontforge/ufo.c Thu Oct 08 11:09:20 2009 +0700 @@ -223,6 +223,7 @@ SplinePoint *sp; RefChar *ref; int err; + AnchorPoint *ap; if ( glif==NULL ) return( false ); @@ -258,6 +259,16 @@ fprintf( glif, " yOffset=\"%g\"", (double) ref->transform[5] ); fprintf( glif, "/>\n" ); } + for ( ap = sc->anchor; ap!=NULL; ap=ap->next ) { + fprintf( glif, " <contour>\n" ); + if ( ap->type==at_mark ) + fprintf( glif, " <point x=\"%g\" y=\"%g\" type\"move\" name=\"_%s\"/>\n", + (double) ap->me.x, (double) ap->me.y, ap->anchor->name ); + else + fprintf( glif, " <point x=\"%g\" y=\"%g\" type\"move\" name=\"%s\"/>\n", + (double) ap->me.x, (double) ap->me.y, ap->anchor->name ); + fprintf( glif, " </contour>\n" ); + } for ( spl=sc->layers[layer].splines; spl!=NULL; spl=spl->next ) { fprintf( glif, " <contour>\n" ); for ( sp=spl->first; sp!=NULL; ) { @@ -1085,15 +1096,15 @@ } if ( pos!=-88888888 && width!=0 ) { h = chunkalloc(sizeof(StemInfo)); - h->start = pos; - h->width = width; - if ( width==-20 || width==-21 ) + h->start = pos; + h->width = width; + if ( width==-20 || width==-21 ) h->ghost = true; if ( head==NULL ) head = last = h; else { last->next = h; - last = h; + last = h; } } } @@ -1105,7 +1116,46 @@ return( head ); } -static SplineChar *_UFOLoadGlyph(xmlDocPtr doc,char *glifname) { +static AnchorClass *UFOGetAnchorClass(char *name,SplineFont *sf) { + struct lookup_subtable *sub; + AnchorClass *ac; + OTLookup *otl; + + if ( sf==NULL ) + return( NULL ); + for ( ac = sf->anchor; ac!=NULL && strcmp(ac->name,name)!=0; ac = ac->next); + if ( ac!=NULL ) + return( ac ); + for ( otl = sf->gpos_lookups; otl!=NULL && strcmp(otl->lookup_name,"_holdAnchors")!=0; otl = otl->next); + if ( otl==NULL ) { + otl = chunkalloc(sizeof(OTLookup)); + otl->lookup_name=galloc(13); + strcpy(otl->lookup_name,"_holdAnchors"); + otl->lookup_type = gpos_mark2base; + otl->next = sf->gpos_lookups; + sf->gpos_lookups = otl; + } + for ( sub = otl->subtables; sub!=NULL && strcmp(sub->subtable_name,"_someAnchors")!=0; sub = sub->next); + if ( sub==NULL ) { + sub = chunkalloc(sizeof(struct lookup_subtable)); + sub->subtable_name=galloc(14); + strcpy(sub->subtable_name,"_someAnchors"); + sub->anchor_classes = true; + sub->lookup = otl; + sub->next = otl->subtables; + otl->subtables = sub; + } + ac = chunkalloc(sizeof(AnchorClass)); + ac->name = galloc(strlen(name)+1); + strcpy(ac->name,name); + ac->subtable = sub; + ac->type = act_mark; + ac->next = sf->anchor; + sf->anchor = ac; + return( ac ); +} + +static SplineChar *_UFOLoadGlyph(xmlDocPtr doc,char *glifname,SplineFont *sf) { xmlNodePtr glyph, kids, contour, points; SplineChar *sc; xmlChar *format, *width, *height, *u; @@ -1201,7 +1251,7 @@ ss = chunkalloc(sizeof(SplineSet)); for ( points = contour->children; points!=NULL; points=points->next ) { - char *xs, *ys, *type; + char *xs, *ys, *type, *name; double x,y; if ( _xmlStrcmp(points->name,(const xmlChar *) "point")!=0 ) continue; @@ -1211,36 +1261,55 @@ if ( xs==NULL || ys == NULL ) continue; x = strtod(xs,NULL); y = strtod(ys,NULL); - if ( type!=NULL && (strcmp(type,"move")==0 || + name = _xmlGetProp(points,(xmlChar *) "name"); + /* test for anchor points */ + if ( name!=NULL && strcmp(type,"move")==0 ) { + AnchorPoint *ap = chunkalloc(sizeof(AnchorPoint)); + if (name[0] == '_') { + ap->type = at_mark; + ap->anchor = UFOGetAnchorClass(name+1,sf); + ap->anchor->has_mark = true; + } else { + ap->type = at_basechar; + ap->anchor = UFOGetAnchorClass(name,sf); + ap->anchor->has_base = true; + } + ap->me.x = x; + ap->me.y = y; + ap->next = sc->anchor; + sc->anchor = ap; + open = true; + continue; + } else if ( type!=NULL && (strcmp(type,"move")==0 || strcmp(type,"line")==0 || strcmp(type,"curve")==0 || strcmp(type,"qcurve")==0 )) { sp = SplinePointCreate(x,y); if ( strcmp(type,"move")==0 ) { open = true; - ss->first = ss->last = sp; + ss->first = ss->last = sp; } else if ( ss->first==NULL ) { ss->first = ss->last = sp; - memcpy(init,pre,sizeof(pre)); - initcnt = precnt; - if ( strcmp(type,"qcurve")==0 ) + memcpy(init,pre,sizeof(pre)); + initcnt = precnt; + if ( strcmp(type,"qcurve")==0 ) wasquad = true; } else if ( strcmp(type,"line")==0 ) { SplineMake(ss->last,sp,false); - ss->last = sp; + ss->last = sp; } else if ( strcmp(type,"curve")==0 ) { wasquad = false; if ( precnt==2 ) { ss->last->nextcp = pre[0]; - ss->last->nonextcp = false; - sp->prevcp = pre[1]; - sp->noprevcp = false; + ss->last->nonextcp = false; + sp->prevcp = pre[1]; + sp->noprevcp = false; } else if ( precnt==1 ) { ss->last->nextcp = sp->prevcp = pre[0]; - ss->last->nonextcp = sp->noprevcp = false; + ss->last->nonextcp = sp->noprevcp = false; } SplineMake(ss->last,sp,false); - ss->last = sp; + ss->last = sp; } else if ( strcmp(type,"qcurve")==0 ) { wasquad = true; if ( precnt==2 ) { @@ -1250,12 +1319,12 @@ SplineMake(ss->last,sp,true); ss->last = sp; } - if ( precnt>=1 ) { + if ( precnt>=1 ) { ss->last->nextcp = sp->prevcp = pre[precnt-1]; - ss->last->nonextcp = sp->noprevcp = false; + ss->last->nonextcp = sp->noprevcp = false; } SplineMake(ss->last,sp,true); - ss->last = sp; + ss->last = sp; } precnt = 0; } else { @@ -1264,44 +1333,44 @@ memcpy(init,pre,sizeof(pre)); initcnt = 1; sp = SplinePointCreate((pre[1].x+pre[0].x)/2,(pre[1].y+pre[0].y)/2); - sp->nextcp = pre[1]; - sp->nonextcp = false; - if ( ss->first==NULL ) + sp->nextcp = pre[1]; + sp->nonextcp = false; + if ( ss->first==NULL ) ss->first = sp; else { ss->last->nextcp = sp->prevcp = pre[0]; - ss->last->nonextcp = sp->noprevcp = false; - initcnt = 0; - SplineMake(ss->last,sp,true); + ss->last->nonextcp = sp->noprevcp = false; + initcnt = 0; + SplineMake(ss->last,sp,true); } - ss->last = sp; + ss->last = sp; sp = SplinePointCreate((x+pre[1].x)/2,(y+pre[1].y)/2); - sp->prevcp = pre[1]; - sp->noprevcp = false; - SplineMake(ss->last,sp,true); - ss->last = sp; - pre[0].x = x; pre[0].y = y; - precnt = 1; + sp->prevcp = pre[1]; + sp->noprevcp = false; + SplineMake(ss->last,sp,true); + ss->last = sp; + pre[0].x = x; pre[0].y = y; + precnt = 1; wasquad = true; } else if ( wasquad==true && precnt==1 ) { sp = SplinePointCreate((x+pre[0].x)/2,(y+pre[0].y)/2); - sp->prevcp = pre[0]; - sp->noprevcp = false; - if ( ss->last==NULL ) { + sp->prevcp = pre[0]; + sp->noprevcp = false; + if ( ss->last==NULL ) { ss->first = sp; - memcpy(init,pre,sizeof(pre)); - initcnt = 1; + memcpy(init,pre,sizeof(pre)); + initcnt = 1; } else { ss->last->nextcp = sp->prevcp; - ss->last->nonextcp = false; + ss->last->nonextcp = false; SplineMake(ss->last,sp,true); } ss->last = sp; - pre[0].x = x; pre[0].y = y; + pre[0].x = x; pre[0].y = y; } else if ( precnt<2 ) { pre[precnt].x = x; - pre[precnt].y = y; - ++precnt; + pre[precnt].y = y; + ++precnt; } } free(xs); free(ys); free(type); @@ -1318,10 +1387,10 @@ int i; for ( i=0; i<initcnt-1; ++i ) { sp = SplinePointCreate((init[i+1].x+init[i].x)/2,(init[i+1].y+init[i].y)/2); - sp->prevcp = ss->last->nextcp = init[i]; - sp->noprevcp = ss->last->nonextcp = false; - SplineMake(ss->last,sp,true); - ss->last = sp; + sp->prevcp = ss->last->nextcp = init[i]; + sp->noprevcp = ss->last->nonextcp = false; + SplineMake(ss->last,sp,true); + ss->last = sp; } ss->last->nextcp = ss->first->prevcp = init[initcnt-1]; ss->last->nonextcp = ss->first->noprevcp = false; @@ -1334,11 +1403,13 @@ SplineMake(ss->last,ss->first,wasquad); ss->last = ss->first; } - if ( last==NULL ) - sc->layers[ly_fore].splines = ss; - else - last->next = ss; - last = ss; + if ( ss->first!=NULL) { + if ( last==NULL ) + sc->layers[ly_fore].splines = ss; + else + last->next = ss; + last = ss; + } } } } else if ( _xmlStrcmp(kids->name,(const xmlChar *) "lib")==0 ) { @@ -1357,8 +1428,8 @@ if ( temp!=NULL ) { sc->hstem = GlifParseHints(doc,temp,"hhints"); sc->vstem = GlifParseHints(doc,temp,"vhints"); - SCGuessHHintInstancesList(sc,ly_fore); - SCGuessVHintInstancesList(sc,ly_fore); + SCGuessHHintInstancesList(sc,ly_fore); + SCGuessVHintInstancesList(sc,ly_fore); } break; } @@ -1375,7 +1446,7 @@ return( sc ); } -static SplineChar *UFOLoadGlyph(char *glifname) { +static SplineChar *UFOLoadGlyph(char *glifname,SplineFont *sf) { xmlDocPtr doc; doc = _xmlParseFile(glifname); @@ -1383,7 +1454,7 @@ LogError( _("Bad glif file %s\n" ), glifname); return( NULL ); } -return( _UFOLoadGlyph(doc,glifname)); +return( _UFOLoadGlyph(doc,glifname,sf)); } @@ -1451,7 +1522,7 @@ valname = (char *) _xmlNodeListGetString(doc,value->children,true); glyphfname = buildname(glyphdir,valname); free(valname); - sc = UFOLoadGlyph(glyphfname); + sc = UFOLoadGlyph(glyphfname,sf); if ( sc!=NULL ) { sc->parent = sf; if ( sf->glyphcnt>=sf->glyphmax ) @@ -1741,10 +1812,10 @@ } else if ( strncmp((char *) keyname, "openTypeHhea",12)==0 ) { if ( _xmlStrcmp(keyname+12,(xmlChar *) "Ascender")==0 ) { sf->pfminfo.hhead_ascent = strtol((char *) valname,&end,10); - sf->pfminfo.hheadascent_add = false; + sf->pfminfo.hheadascent_add = false; } else if ( _xmlStrcmp(keyname+12,(xmlChar *) "Descender")==0 ) { sf->pfminfo.hhead_descent = strtol((char *) valname,&end,10); - sf->pfminfo.hheaddescent_add = false; + sf->pfminfo.hheaddescent_add = false; } else if ( _xmlStrcmp(keyname+12,(xmlChar *) "LineGap")==0 ) sf->pfminfo.linegap = strtol((char *) valname,&end,10); free(valname); @@ -1758,7 +1829,7 @@ sf->pfminfo.pfmset = true; if ( _xmlStrcmp(keyname+11,(xmlChar *) "Panose")==0 ) { UFOGetByteArray(sf->pfminfo.panose,sizeof(sf->pfminfo.panose),doc,value); - sf->pfminfo.panose_set = true; + sf->pfminfo.panose_set = true; } else if ( _xmlStrcmp(keyname+11,(xmlChar *) "Type")==0 ) sf->pfminfo.fstype = UFOGetBits(doc,value); else if ( _xmlStrcmp(keyname+11,(xmlChar *) "FamilyClass")==0 ) { @@ -1772,18 +1843,18 @@ else if ( _xmlStrcmp(keyname+11,(xmlChar *) "VendorID")==0 ) memcpy(sf->pfminfo.os2_vendor,valname,4); else if ( _xmlStrcmp(keyname+11,(xmlChar *) "TypoAscender")==0 ) { - sf->pfminfo.typoascent_add = false; + sf->pfminfo.typoascent_add = false; sf->pfminfo.os2_typoascent = strtol((char *) valname,&end,10); } else if ( _xmlStrcmp(keyname+11,(xmlChar *) "TypoDescender")==0 ) { - sf->pfminfo.typodescent_add = false; + sf->pfminfo.typodescent_add = false; sf->pfminfo.os2_typodescent = strtol((char *) valname,&end,10); } else if ( _xmlStrcmp(keyname+11,(xmlChar *) "TypoLineGap")==0 ) sf->pfminfo.os2_typolinegap = strtol((char *) valname,&end,10); else if ( _xmlStrcmp(keyname+11,(xmlChar *) "WinAscent")==0 ) { - sf->pfminfo.winascent_add = false; + sf->pfminfo.winascent_add = false; sf->pfminfo.os2_winascent = strtol((char *) valname,&end,10); } else if ( _xmlStrcmp(keyname+11,(xmlChar *) "WinDescent")==0 ) { - sf->pfminfo.windescent_add = false; + sf->pfminfo.windescent_add = false; sf->pfminfo.os2_windescent = strtol((char *) valname,&end,10); } else if ( strncmp((char *) keyname+11,"Subscript",9)==0 ) { sf->pfminfo.subsuper_set = true; @@ -1971,7 +2042,7 @@ return( NULL ); oldloc = setlocale(LC_NUMERIC,"C"); - sc = _UFOLoadGlyph(doc,filename); + sc = _UFOLoadGlyph(doc,filename,NULL); setlocale(LC_NUMERIC,oldloc); if ( sc==NULL ) ------------------------------------------------------------------------------ Come build with us! The BlackBerry(R) Developer Conference in SF, CA is the only developer event you need to attend this year. Jumpstart your developing skills, take BlackBerry mobile applications to market and stay ahead of the curve. Join us from November 9 - 12, 2009. Register now! http://p.sf.net/sfu/devconference _______________________________________________ Fontforge-devel mailing list Fontforge-devel@... https://lists.sourceforge.net/lists/listinfo/fontforge-devel |
|
|
Re: UFO Anchor pointsMartin Hosken <martin_hosken@...> writes:
> FontForge doesn't really have the concept of an arbitrary anchor > point. All anchors must be associated via a AnchorClass to a > lookup. While this is great if you are doing all your OT work in > fontforge, it is problematic if you are viewing fontforge purely as > a design tool which links to external tools, and are viewing anchors > merely as something else a designer puts into their design. Because you started me thinking about it -- There is a tiny little bit of a problem with the way fontforge handles anchors, in that if you use them just to place accents and don’t want to output them in the font (which indeed I don't) then you need a script to generate the font (which in fact is what I do). The same problem arises in my "spacing by anchors" scripts, where anchor points are used to mark "generalized sidebearings". These points are of no use in the generated font and so having them in sfnt tables is a nuisance. Admittedly in that case I am making "off-label" use of anchor points, but using them to place accents is a built-in feature of fontforge and yet is not really connected to sfnt tables, conceptually -- removing the anchor points does no harm at all to the accented glyphs. ------------------------------------------------------------------------------ Come build with us! The BlackBerry(R) Developer Conference in SF, CA is the only developer event you need to attend this year. Jumpstart your developing skills, take BlackBerry mobile applications to market and stay ahead of the curve. Join us from November 9 - 12, 2009. Register now! http://p.sf.net/sfu/devconference _______________________________________________ Fontforge-devel mailing list Fontforge-devel@... https://lists.sourceforge.net/lists/listinfo/fontforge-devel |
| Free embeddable forum powered by Nabble | Forum Help |