static void MVInline(MetricsView *mv, real width, real inset) { StrokeInfo si; SplineSet *temp, *spl, *temp2; int i, changed; memset(&si,0,sizeof(si)); si.removeexternal = true; /* si.removeoverlapifneeded = true;*/ for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) { SplineChar *sc = mv->glyphs[i].sc; SCPreserveLayer(sc,mv->layer,false); si.radius = width; temp = SplineSetStroke(sc->layers[mv->layer].splines,&si,sc->layers[mv->layer].order2); si.radius = width+inset; temp2 = SplineSetStroke(sc->layers[mv->layer].splines,&si,sc->layers[mv->layer].order2); for ( spl=sc->layers[mv->layer].splines; spl->next!=NULL; spl=spl->next ); spl->next = temp; for ( ; spl->next!=NULL; spl=spl->next ); spl->next = temp2; SplineSetsCorrect(sc->layers[mv->layer].splines,&changed); SCCharChangedUpdate(sc,mv->layer); } }
void FVOutline(FontViewBase * fv, real width) { StrokeInfo si; SplineSet *temp, *spl; int i, cnt=0, changed, gid; SplineChar *sc; int layer=fv->active_layer; for (i=0; i < fv->map->enccount; ++i) if ((gid=fv->map->map[i]) != -1 && (sc=fv->sf->glyphs[gid]) != NULL && fv->selected[i] && sc->layers[layer].splines) ++cnt; memset(&si, 0, sizeof(si)); si.removeexternal=true; si.radius=width; /*si.removeoverlapifneeded=true; */ SFUntickAll(fv->sf); for (i=0; i < fv->map->enccount; ++i) if ((gid=fv->map->map[i]) != -1 && (sc=fv->sf->glyphs[gid]) != NULL && fv->selected[i] && sc->layers[layer].splines && !sc->ticked) { sc->ticked=true; SCPreserveLayer(sc, layer, false); temp = SplineSetStroke(sc->layers[layer].splines, &si, sc->layers[layer].order2); for (spl=sc->layers[layer].splines; spl->next != NULL; spl=spl->next); spl->next=temp; SplineSetsCorrect(sc->layers[layer].splines, &changed); SCCharChangedUpdate(sc, layer, true); } }
static SplineChar *_SFMakeChar(SplineFont *sf,EncMap *map,int enc) { SplineChar dummy, *sc; SplineFont *ssf; int j, real_uni, gid; extern const int cns14pua[], amspua[]; if ( enc>=map->enccount ) gid = -1; else gid = map->map[enc]; if ( sf->subfontcnt!=0 && gid!=-1 ) { ssf = NULL; for ( j=0; j<sf->subfontcnt; ++j ) if ( gid<sf->subfonts[j]->glyphcnt ) { ssf = sf->subfonts[j]; if ( ssf->glyphs[gid]!=NULL ) { return( ssf->glyphs[gid] ); } } sf = ssf; } if ( gid==-1 || (sc = sf->glyphs[gid])==NULL ) { if (( map->enc->is_unicodebmp || map->enc->is_unicodefull ) && ( enc>=0xe000 && enc<=0xf8ff ) && ( sf->uni_interp==ui_ams || sf->uni_interp==ui_trad_chinese ) && ( real_uni = (sf->uni_interp==ui_ams ? amspua : cns14pua)[enc-0xe000])!=0 ) { if ( real_uni<map->enccount ) { SplineChar *sc; /* if necessary, create the real unicode code point */ /* and then make us be a duplicate of it */ sc = _SFMakeChar(sf,map,real_uni); map->map[enc] = gid = sc->orig_pos; SCCharChangedUpdate(sc,ly_all); return( sc ); } } SCBuildDummy(&dummy,sf,map,enc); /* Let's say a user has a postscript encoding where the glyph ".notdef" */ /* is assigned to many slots. Once the user creates a .notdef glyph */ /* all those slots should fill in. If they don't they damn well better*/ /* when the user clicks on one to edit it */ /* Used to do that with all encodings. It just confused people */ if ( map->enc->psnames!=NULL && (sc = SFGetChar(sf,dummy.unicodeenc,dummy.name))!=NULL ) { map->map[enc] = sc->orig_pos; return( sc ); } sc = SFSplineCharCreate(sf); sc->unicodeenc = dummy.unicodeenc; sc->name = copy(dummy.name); sc->width = dummy.width; sc->orig_pos = 0xffff; /*SCLigDefault(sc);*/ SFAddGlyphAndEncode(sf,sc,map,enc); } return( sc ); }
static void MVShadow(MetricsView *mv,real angle, real outline_width, real shadow_length,int wireframe) { int i; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) { SplineChar *sc = mv->glyphs[i].sc; SCPreserveLayer(sc,mv->layer,false); sc->layers[mv->layer].splines = SSShadow(sc->layers[mv->layer].splines,angle,outline_width,shadow_length,sc,wireframe); SCCharChangedUpdate(sc,mv->layer); } }
static void ApplyChanges(WidthInfo *wi) { EncMap *map = wi->fv->map; uint8 *rsel = calloc(map->enccount,sizeof(char)); int i, width; real transform[6]; struct charone *ch; DBounds bb; for ( i=0; i<wi->real_rcnt; ++i ) { int gid = map->map[wi->right[i]->sc->orig_pos]; if ( gid!=-1 ) rsel[gid] = true; } transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[5] = 0; for ( i=0; i<wi->real_rcnt; ++i ) { ch = wi->right[i]; transform[4] = ch->newl-ch->lbearing; if ( transform[4]!=0 ) { FVTrans(wi->fv,ch->sc,transform,rsel,false); SCCharChangedUpdate(ch->sc,ly_none); } } free(rsel); for ( i=0; i<wi->real_lcnt; ++i ) { ch = wi->left[i]; SplineCharLayerFindBounds(ch->sc,wi->layer,&bb); width = rint(bb.maxx + ch->newr); if ( width!=ch->sc->width ) { SCPreserveWidth(ch->sc); SCSynchronizeWidth(ch->sc,width,ch->sc->width,wi->fv); SCCharChangedUpdate(ch->sc,ly_none); } } }
static void SetAnchor(SplineChar *sc,int layer, AnchorPoint *ap,DeviceTable *xadjust, DeviceTable *yadjust, BasePoint *pos) { int ly; free(ap->xadjust.corrections); if ( xadjust->corrections==NULL ) { memset(&ap->xadjust,0,sizeof(DeviceTable)); } else { ap->xadjust = *xadjust; xadjust->corrections = NULL; } free(ap->yadjust.corrections); if ( yadjust->corrections==NULL ) { memset(&ap->yadjust,0,sizeof(DeviceTable)); } else { ap->yadjust = *yadjust; yadjust->corrections = NULL; } ap->me = *pos; /* If the anchor is bound to a truetype point we must move the point too */ /* or the anchor will just snap back to the point */ ly = ly_none; if ( ap->has_ttf_pt && ap->ttf_pt_index!=0xffff ) { int any = false; for ( ly=ly_fore; ly<sc->layer_cnt; ++ly ) if ( sc->layers[ly].order2 ) { SplinePoint *sp = SCFindPoint(sc,layer,ap->ttf_pt_index); if ( sp!=NULL ) { sp->nextcp.x += pos->x - sp->me.x; sp->prevcp.x += pos->x - sp->me.x; sp->nextcp.y += pos->y - sp->me.y; sp->prevcp.y += pos->y - sp->me.y; sp->me = *pos; any = true; } } if ( !any ) { ff_post_notice(_("Detaching Anchor Point"),_("This anchor was attached to point %d, but that's not a point I can move. I'm detaching the anchor from the point.") ); ap->has_ttf_pt = false; ly = ly_none; } } SCCharChangedUpdate(sc,ly); }
void FVInline(FontViewBase *fv, real width, real inset) { StrokeInfo si; SplineSet *temp, *spl, *temp2; int i, cnt=0, changed, gid; SplineChar *sc; int layer = fv->active_layer; for ( i=0; i<fv->map->enccount; ++i ) if ( (gid=fv->map->map[i])!=-1 && (sc=fv->sf->glyphs[gid])!=NULL && fv->selected[i] && sc->layers[layer].splines ) ++cnt; ff_progress_start_indicator(10,_("Inlining glyphs"),_("Inlining glyphs"),0,cnt,1); memset(&si,0,sizeof(si)); si.removeexternal = true; /*si.removeoverlapifneeded = true;*/ SFUntickAll(fv->sf); for ( i=0; i<fv->map->enccount; ++i ) if ( (gid=fv->map->map[i])!=-1 && (sc=fv->sf->glyphs[gid])!=NULL && fv->selected[i] && sc->layers[layer].splines && !sc->ticked ) { sc->ticked = true; SCPreserveLayer(sc,layer,false); si.radius = width; temp = SplineSetStroke(sc->layers[layer].splines,&si,sc->layers[layer].order2); si.radius = width+inset; temp2 = SplineSetStroke(sc->layers[layer].splines,&si,sc->layers[layer].order2); for ( spl=sc->layers[layer].splines; spl->next!=NULL; spl=spl->next ); spl->next = temp; for ( ; spl->next!=NULL; spl=spl->next ); spl->next = temp2; SplineSetsCorrect(sc->layers[layer].splines,&changed); SCCharChangedUpdate(sc,layer); if ( !ff_progress_next()) break; } ff_progress_end_indicator(); }
static void DoChar(SplineChar *sc,CreateWidthData *wd, FontViewBase *fv, BDFChar *bc) { real transform[6]; DBounds bb; IBounds ib; int width=0; BVTFunc bvts[2]; BDFFont *bdf; RefChar *r = HasUseMyMetrics(sc,fv->active_layer); /* Can't change the horizontal or vertical advance if there's a "use my metrics" bit set */ if ( r!=NULL && wd->wtype != wt_lbearing ) return; if ( wd->wtype == wt_width ) { if ( wd->type==st_set ) width = wd->setto; else if ( wd->type == st_incr ) width = sc->width + wd->increment; else width = sc->width * wd->scale/100; sc->widthset = true; if ( width!=sc->width ) { SCPreserveWidth(sc); SCSynchronizeWidth(sc,width,sc->width,fv); } } else if ( wd->wtype == wt_lbearing ) { transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[5] = 0; bvts[1].func = bvt_none; bvts[0].func = bvt_transmove; bvts[0].y = 0; if ( bc==NULL ) { SplineCharFindBounds(sc,&bb); if ( wd->type==st_set ) transform[4] = wd->setto-bb.minx; else if ( wd->type == st_incr ) transform[4] = wd->increment; else transform[4] = bb.minx*wd->scale/100 - bb.minx; } else { double scale = (fv->sf->ascent+fv->sf->descent)/(double) (fv->active_bitmap->pixelsize); BDFCharFindBounds(bc,&ib); if ( wd->type==st_set ) transform[4] = wd->setto-ib.minx*scale; else if ( wd->type == st_incr ) transform[4] = wd->increment; else transform[4] = scale*ib.minx*wd->scale/100 - ib.minx; } if ( transform[4]!=0 ) { FVTrans(fv,sc,transform,NULL,fvt_dontmovewidth); bvts[0].x = transform[4]; for ( bdf = fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next ) if ( bdf->glyphs[sc->orig_pos]!=NULL ) BCTrans(bdf,bdf->glyphs[sc->orig_pos],bvts,fv); } return; } else if ( wd->wtype == wt_rbearing ) { if ( bc==NULL ) { SplineCharFindBounds(sc,&bb); if ( wd->type==st_set ) width = bb.maxx + wd->setto; else if ( wd->type == st_incr ) width = sc->width+wd->increment; else width = (sc->width-bb.maxx) * wd->scale/100 + bb.maxx; } else { double scale = (fv->sf->ascent+fv->sf->descent)/(double) (fv->active_bitmap->pixelsize); BDFCharFindBounds(bc,&ib); ++ib.maxx; if ( wd->type==st_set ) width = rint(ib.maxx*scale + wd->setto); else if ( wd->type == st_incr ) width = rint(sc->width+wd->increment); else width = rint(scale * (bc->width-ib.maxx) * wd->scale/100 + ib.maxx*scale); } if ( width!=sc->width ) { SCPreserveWidth(sc); SCSynchronizeWidth(sc,width,sc->width,fv); } } else if ( wd->wtype == wt_bearings ) { transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[5] = 0; bvts[1].func = bvt_none; bvts[0].func = bvt_transmove; bvts[0].y = 0; if ( bc==NULL ) { SplineCharFindBounds(sc,&bb); if ( wd->type==st_set ) { transform[4] = wd->setto-bb.minx; width = bb.maxx-bb.minx + 2*wd->setto; } else if ( wd->type == st_incr ) { transform[4] = wd->increment; width += 2*wd->increment; } else { transform[4] = bb.minx*wd->scale/100 - bb.minx; width = bb.maxx-bb.minx + (bb.minx + (sc->width-bb.maxx))*wd->scale/100; } } else { double scale = (fv->sf->ascent+fv->sf->descent)/(double) (fv->active_bitmap->pixelsize); BDFCharFindBounds(bc,&ib); ++ib.maxx; if ( wd->type==st_set ) { transform[4] = wd->setto-ib.minx; width = (ib.maxx-ib.minx + 2*wd->setto); } else if ( wd->type == st_incr ) { transform[4] = wd->increment; width += 2*wd->increment; } else { transform[4] = ib.minx*wd->scale/100 - ib.minx; width = ib.maxx-ib.minx + (ib.minx + (bc->width-ib.maxx))*wd->scale/100; } transform[4] *= scale; width = rint(width*scale); } if ( width!=sc->width ) { SCPreserveWidth(sc); SCSynchronizeWidth(sc,width,sc->width,fv); } if ( transform[4]!=0 ) { FVTrans(fv,sc,transform,NULL,fvt_dontmovewidth); bvts[0].x = transform[4]; for ( bdf = fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next ) if ( bdf->glyphs[sc->orig_pos]!=NULL ) BCTrans(bdf,bdf->glyphs[sc->orig_pos],bvts,fv); } return; } else { if ( wd->type==st_set ) width = wd->setto; else if ( wd->type == st_incr ) width = sc->vwidth + wd->increment; else width = sc->vwidth * wd->scale/100; if ( width!=sc->vwidth ) { SCPreserveVWidth(sc); sc->vwidth = width; } } SCCharChangedUpdate(sc,fv->active_layer); }
static void aw2_figure_all_sidebearing(AW_Data *all) { int i,j; AW_Glyph *me, *other; real transform[6], half; int width, changed; uint8 *rsel = calloc(all->fv->map->enccount,sizeof(char)); real denom = (all->sf->ascent + all->sf->descent)/DENOM_FACTOR_OF_EMSIZE; int ldiff, rdiff; all->denom = denom; all->visual_separation = malloc(all->gcnt*all->gcnt*sizeof(int)); for ( i=0; i<all->gcnt; ++i ) { int *vpt = all->visual_separation + i*all->gcnt; me = &all->glyphs[i]; for ( j=0; j<all->gcnt; ++j ) { other = &all->glyphs[j]; vpt[j] = aw2_bbox_separation(me,other,all); } } half = all->desired_separation/2; for ( i=0; i<all->gcnt; ++i ) { me = &all->glyphs[i]; me->lsb = me->rsb = half; } for ( j=0; j<all->loop_cnt; ++j ) { for ( i=0; i<all->gcnt; ++i ) aw2_figure_lsb(i,all); for ( i=0; i<all->gcnt; ++i ) aw2_figure_rsb(i,all); for ( i=0; i<all->gcnt; ++i ) { AW_Glyph *me = &all->glyphs[i]; me->rsb = me->nrsb; me->lsb = me->nlsb; } } free(all->visual_separation); all->visual_separation = NULL; if ( all->normalize ) { /* This is the dummy flat edge we added. We want the separation between */ /* two adjacent flat edges to be desired_separation */ me = &all->glyphs[all->gcnt-1]; if ( me->lsb+me->rsb != all->desired_separation && me->sc==NULL ) { if ( me->lsb+me->rsb!=0 ) { ldiff = (all->desired_separation-(me->lsb+me->rsb)) * me->lsb/(me->lsb+me->rsb); } else { ldiff = all->desired_separation/2; } rdiff = (all->desired_separation-(me->lsb+me->rsb)) - ldiff; for ( i=0; (me = &all->glyphs[i])->sc!=NULL; ++i ) { me->lsb += ldiff; me->rsb += rdiff; } } } transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[5] = 0; for ( i=0; (me = &all->glyphs[i])->sc!=NULL; ++i ) { changed = 0; if ( me->lsb != me->bb.minx ) { transform[4] = me->lsb-me->bb.minx; FVTrans(all->fv,me->sc,transform,rsel,false); changed = true; } width = me->lsb + me->rsb + rint(me->bb.maxx - me->bb.minx); if ( me->sc->width != width ) { SCPreserveWidth(me->sc); SCSynchronizeWidth(me->sc,width,me->sc->width,all->fv); changed = true; } if ( changed ) SCCharChangedUpdate(me->sc,ly_none); } free(rsel); }
static SplineChar *AddAnchor(AnchorDlg *a, SplineFont *sf, AnchorClass *ac, int ismarklike) { char *ret, *def; SplineChar *sc; int isliga = false, ismrk=false, maxlig=-1; AnchorPoint *ap; PST *pst; int i; def = copy(".notdef"); for (;;) { ret = gwwv_ask_string(_("Provide a glyph name"),def,_("Please identify a glyph by name, and FontForge will add an anchor to that glyph.")); free(def); if ( ret==NULL ) return( NULL ); sc = SFGetChar(sf,-1,ret); def = ret; if ( sc==NULL ) ff_post_error(_("Non-existant glyph"), _("The glyph, %.80s, is not in the font"), ret ); else { isliga = ismrk = false; for ( ap=sc->anchor ; ap!=NULL; ap=ap->next ) { if ( ap->type == at_baselig ) isliga = true; else if ( ap->type == at_basemark || ap->type == at_mark ) ismrk = true; if ( ap->anchor == ac ) { if ( (ap->type == at_centry || (ap->type == at_mark && ac->type==act_mkmk) || ap->type == at_baselig ) && ismarklike==-1 ) ismarklike = false; else if ( (ap->type == at_cexit || (ap->type == at_basemark && ac->type==act_mkmk)) && ismarklike==-1 ) ismarklike = true; else if ( ap->type != at_baselig || ( ap->type == at_baselig && ismarklike>0 )) ff_post_error(_("Duplicate Anchor Class"), _("The glyph, %.80s, already contains an anchor in this class, %.80s."), ret, ac->name ); else if ( maxlig<ap->lig_index ) maxlig = ap->lig_index; break; } } if ( ap==NULL ) break; } } ap = chunkalloc(sizeof(AnchorPoint)); ap->anchor = ac; ap->me.x = ap->me.y = 0; ap->next = sc->anchor; sc->anchor = ap; SCCharChangedUpdate(sc,ly_none); if ( sc->width==0 ) ismrk = true; for ( pst=sc->possub; pst!=NULL; pst=pst->next ) { if ( pst->type == pst_ligature || pst->type == pst_lcaret ) { isliga = true; break; } } if ( isliga || (ac->type==act_mklg && ismarklike==0 ) ) { ap->type = at_baselig; ap->lig_index = maxlig+1; } else if ( ismrk && ismarklike!=0 ) ap->type = at_mark; else if ( ismarklike==0 && (ismrk || ac->type==act_mkmk) ) ap->type = at_basemark; else if ( ac->type == act_curs ) { if ( ismarklike==true ) ap->type = at_centry; else ap->type = at_cexit; } else if ( ismarklike==true ) ap->type = at_mark; else ap->type = at_basechar; if ( a!=NULL ) { GTextInfo **ti = AnchorD_GlyphsInClass(a); GGadgetSetList(GWidgetGetControl(a->gw,CID_Glyph),ti,false); for ( i=0; ti[i]->text!=NULL || ti[i]->line; ++i ) { if ( ti[i]->userdata == ap ) { GGadgetSelectOneListItem(GWidgetGetControl(a->gw,CID_Glyph),i); break; } } AnchorD_ChangeGlyph(a,sc,ap); } return( sc ); }