% dxaccess.mf % % This file is part of dcfonts version 1.3 Patchlevel 3 % % Please read the files 00readme.txt, 00inst.txt, 00error.txt, and % copyrite.txt for further information % % You find some documentation in dcdoc.tex (needs LaTeX2e) % % Accessories and special definitions for polish letters % Adapted to dxbase and dcfont by J\"org Knappen % Copyright (c) 1992 Bogus\l{}aw Jackowski \& Marek Ry\'cko % Copyright (c) 1995, 1996 J\"org Knappen % --------------------------------------------------------------------------- % This was PL_DOD.MF ({\bif{}dodatkowy}, i.e., additional file for the Polish % extension of CM family) in text format. % --------------------------------------------------------------------------- %%{\let\:\sl %\: This file provides accessories for making Polish diacritical characters: %\: acute accent for |"C"|, |"N"|, |"L"|, |"S"|, |"Z"|, dot accent for |"Z"|, %\: cross for |"L"| and ogonek for |"A"| and |"E"|. In order to avoid extra %\: parameters (62 should be enough) the macros do a lot of ``clever'' stuff, %\: trying to figure out needed dimensions. This is not always a trivial %\: task and in some cases such extra parameters may prove to be unavoidable. %\: Several additional parameters may be assigned a value, prior to reading %\: the driver file, in order to override the default behaviour. %\: One of them is %\: --- the factor controlling the slope of accents over majuscules, %\: |cap_flat|; if the default slope is, say, $\beta$, the resulting %\: slope is equal to |(1-cap_flat)*|$\beta$; this parameter is used %\: in the sources of the following fonts: %\ PLCSC10, PLDUNH10, PLTCSC10 %\: Unexpectedly difficult to program turned out to be ogoneks. We decided %\: that the best looking are ogoneks such that a single B\`ezier segment %\: describes each of ogonek's edges. This necessitated introducing many %\: parameters controlling the positions of control points (for more details %\: see comments in the section ``OGONEK ACCESSORIES''). All these %\: (optional) parameters may be splitted into three groups of importance: %\: primary, secondary and tertiary. The primary parameters are intended %\: to be ``normally'' accessible to users, the secondary ones---only in %\: case of emergency, the tertiary ones---rather not at all. %\: The primary parameters are: %\: --- the factor controlling the depth of ogoneks, |depth_corr|; the %\: resulting depth is equal to |depth_corr*desc_depth#| if the value %\: of |depth_corr| is known, |desc_depth#| otherwise %\: --- the factor controlling the leftmost and tip positions %\: of an ogonek, |left_corr|, |tip_xcorr| and |tip_ycorr|; %\: the default distances are scaled using the values of the %\: corresponding parameters %\: --- the scaling factor for the top and tip breadths of an ogonek, %\: |top_breadth_corr|, |tip_breadth_corr| %\: Some of the primary parameters are used in the sources of the following %\: fonts: % PLB10, PLBX5, PLBX6, PLBX7, PLBX8, PLFI10, PLITT10, PLR5, PLR6, PLR7, % PLR8, PLR9, PLR12, PLR17, PLSL8, PLSL9, PLSL12, PLSSQ8, PLSSQI8, PLTI7, % PLTI8, PLTI12, PLVTT10 %\: The following four parameters we regard as of a secondary importance: %\: --- the pen ogoneks are to be filled with, |ogonek_pen#| (this is %\: the only sharp ogonek parameter and is used in the sources of %\: the {\commfont{}PLFF10} and {\commfont{}PLFI10} fonts) %\: --- the darkness of ogoneks may be controlled using two parameters, %\: |0stem#) enddef; vardef is_bold = if serifs: (hair#+.5stem#)>1.5u# else: stem#>2u# fi\\ enddef; vardef is_cap = (((127 < charcode) and (charcode < 158)) or\\ ((191 < charcode) and (charcode < 224))) or\\ (charcode = 168) % true for l with acute enddef; %%% top is_known %%% top fix_virgin vardef is_known z suffix $ = % an auxiliary macro for |fix_virgin z|, used also while constructing ogoneks (known x$) or (known x$l) or (known x$r)\\ or (known y$) or (known y$l) or (known y$r) enddef; vardef fix_virgin z = % find a pair of virgin pairs numeric ii,jj; jj:=1; forever: if is_known z[jj] or is_known z[jj+1]: % unknown gaps may occur jj:=incr jj else: jj=ii fi; exitif known ii; endfor; jj:=ii+1; % now |ii| and |jj| are such that |z[ii]| and |z[jj]| are ``untouched'' enddef; %%% italcorr corrital % correction of italic correction (cf. D. E. Knuth, The \MF{}book, p. 105): vardef corrital z suffix $ = % |z$| is the rightmost position of a pen (in accent path) if known sharp_calc: if not monospace: save charic_; charic_=(rt(x$)-r)/hppp+slant*y$/vppp+.5u#; if charic_>charic: charic:=charic_; fi fi %| else: %| |charic=mono_charic#|, do nothing fi enddef; %%% fine hi higher % |higher| is a counterpart to |lower| (see the file dxcsc.mf), % |hi| facilitates using higher values (which are reference points in % the floating world of CM fonts) def hi = if is_small_cap: higher fi\\ enddef; %%% top prepare_pen def prepare_pen suffix $ = %%% fine $ %%%% temporary MFT convention if $>fudged.hair: $:=fudged.hair; fi $.breadth:=$; pickup if $=0: nullpen else: pencircle scaled $; $:=$-eps fi; $.nib:=savepen; breadth_[$.nib]:=$; forsuffixes $$=lft,rt,top,bot: shiftdef($.$$,$$ 0); endfor %%% qq $ %%%% ordinary MFT convention enddef; % The proportion of |vair/stem| depends drastically on resolution; % e.g., for 300 dpi cmbx10 |vair=1| and |stem=5|, for 746 dpi cmbx10 % (300 dpi, magstep 5) |vair=4| and |stem=12|, while, sharply speaking, % |stem#/vair#=3.15381|; hence a new variable |xvair| has been introduced % to be used in some crucial places instead of |vair|. vardef xvair = stem*vair#/stem# enddef; % --------------------------------------------------------------------------- % ACCENT ACCESSORIES % --------------------------------------------------------------------------- % |the_cap_flat| is a factor controlling the flatness of accents over % majuscules; a default value may be overriden by assigning a value to the % variable |cap_flat| (cf. also |the_|... macros in ogonek accessories). vardef the_cap_flat = if known cap_flat: cap_flat elseif serifs and hefty: 1/5 else: 1/3 fi enddef; % --------------------------------------------------------------------------- % The |hpos_corr| variable is an optional parameter to |put_ogonek|, meant % to be set locally inside |beginchar| ... |endchar|, if a horizontal % correction of the accent position is needed: numeric hpos_corr; % --------------------------------------------------------------------------- %%%% temporary MFT convention: %%% top x_height diam a_wd a_ht i_ht u asc_height cap_A_wd % width of the acute accent: vardef a_wd@# = 9hi.u@# enddef; % height of the acute accent: vardef a_ht@# = min(asc_height@#,2hi.x_height@#,hi.x_height@#+acc_height@#) enddef; % height of the letter `i': vardef i_ht@#(suffix diam) = if is_small_cap: a_ht@# % usually there is no dot over a small cap `i' else: min(asc_height@#, 10/7hi.x_height@#+.5diam@#) fi enddef; % width of the letter `A' (used in |put_ogonek|): vardef cap_A_wd@# = 13u@# enddef; %%%% ordinary MFT convention: %%% qq x_height diam a_wd a_ht i_ht u asc_height cap_A_wd def mark_height(expr sharp_h)= % |sharp_h| is the height of an accented minuscule if known sharp_calc: charht:=if is_cap: h/vppp else: sharp_h fi; if\\ (proofing>0) and is_cap: % BJ likes to have proofs vertically aligned (somehow): proofoffset(0,h-charht*vppp-1mm); fi fi % say earlier, e.g., |is_smoke=1| if you're making `smoked' proofs % and you don't like to have a rule marking the height if unknown is_smoke: if proofing>0: proofrule((l+w/2,charht*hppp)t_,(r+u,charht*hppp)t_); fi if displaying>0: screenrule((l+w/2,charht*hppp)t_,(r+u,charht*hppp)t_); fi fi enddef; def fix_acc_pairs = fix_virgin z; begingroup % excerpt from |beginchar|: save w,h; w=round(a_wd); h=round(a_ht); % excerpt from |mono_adjust|: if monospace: save u_; numeric u_; u_:=hi.u#; save u; u#:=u_; numeric expansion_faktor; mono_charwd#=2 hi.letter_fit#+expansion_faktor*a_wd#; hi.u:=u#*expansion_faktor*hppp; w:=mono_charwd-shrink_fit-2 hi.letter_fit; fi % end of the excerpts numeric accent_gap,mid_stem; mid_stem=2/3[stem,hi.stem]; if serifs: pickup crisp.nib; x[jj]'=hround(w-2hi.u)-.5mid_stem; x[jj]':=x[jj]'-2/3[x[jj]',w-x[jj]']; y[jj]'=h-.5mid_stem+eps-max(2/3[h,hi.x_height],hi.x_height+o+hair); accent_gap=a_ht-(y[jj]'+.5mid_stem)-hi.x_height; bot z[ii]=round(accent_hpos, accent_gap+if is_cap: cap_height else: hi.x_height fi); z[jj]=z[ii]+(z[jj]' if is_cap: rotated (-the_cap_flat*angle(z[jj]')) fi); numeric theta; theta=angle(z[ii]-z[jj])+90; pos[jj](mid_stem,theta); pos[ii](hair,theta); else: pickup fine.nib; rt x[jj]'r=hround(.5w-1.25hi.u); top y[jj]'=h-vround(2/3[h,hi.x_height]); z[ii]'=origin; pos[jj]'(mid_stem,0); pos[ii]'(vair,0); accent_gap=a_ht-y[jj]'-hi.x_height; if is_cap: numeric beta; beta=-the_cap_flat*angle(z[jj]'-z[ii]'); z[ii]=round(accent_hpos,accent_gap+cap_height); z[jj]=z[ii]+(z[jj]' rotated beta); y[jj]r=y[jj]l=y[jj]; y[ii]r=y[ii]l=y[ii]; for xx:=jj,ii: forsuffixes $:=l,r: (z[xx]$-z[ii]) rotated -beta=whatever[z[jj]'$,z[ii]'$]; endfor\\ endfor else: for xx:=jj,ii: forsuffixes $:=r, ,l: z[xx]$=z[xx]'$+round(accent_hpos, accent_gap+if is_small_cap: cap_height else: x_height fi); endfor\\ endfor fi fi endgroup; enddef; def put_accent= numeric accent_hpos; accent_hpos=.5w - if is_cap: .75 else: .5 fi\\ u if known hpos_corr: +hpos_corr fi; fix_acc_pairs; % |fix_acc_pairs| uses private values of |w|, |h| \& |u| numeric hpos_corr; % |hpos_corr| is local: forget its value % draw the diagonal: if serifs: pickup crisp.nib; filldraw circ_stroke (z[jj]e--z[ii]e); z[jj].right=directionpoint up of (z[jj]r{z[jj]r-z[ii]r}..{z[ii]l-z[jj]l}z[jj]l); z[jj].top=directionpoint left of (z[jj]r{z[jj]r-z[ii]r}..{z[ii]l-z[jj]l}z[jj]l); else: pickup fine.nib; filldraw stroke (z[jj]e--z[ii]e); z[jj].right=z[jj].top=z[jj]r; fi corrital z[jj].right; % correct italic correction % adjust and save height (it is used in the program for the dotted `Z'): h:=if is_cap: y[jj].top else: a_ht fi; if known sharp_calc: saved_height:=h; fi mark_height(a_ht#); penlabels([ii],[jj]); enddef; % --------------------------------------------------------------------------- % GRAVE ACCENT ACCESSORIES % --------------------------------------------------------------------------- % This section borrows heavily from the (acute) accent accessories def fix_grav_pairs = fix_virgin z; begingroup % excerpt from |beginchar|: save w,h; w=round(a_wd); h=round(a_ht); % excerpt from |mono_adjust|: if monospace: save u_; numeric u_; u_:=hi.u#; save u; u#:=u_; numeric expansion_faktor; mono_charwd#=2 hi.letter_fit#+expansion_faktor*a_wd#; hi.u:=u#*expansion_faktor*hppp; w:=mono_charwd-shrink_fit-2 hi.letter_fit; fi % end of the excerpts numeric accent_gap,mid_stem; mid_stem=2/3[stem,hi.stem]; if serifs: pickup crisp.nib; x[jj]'=hround(w-2hi.u)-.5mid_stem; x[jj]':= -x[jj]'+ 2/3[x[jj]',w-x[jj]']; y[jj]'=h-.5mid_stem+eps-max(2/3[h,hi.x_height],hi.x_height+o+hair); accent_gap=a_ht-(y[jj]'+.5mid_stem)-hi.x_height; bot z[ii]=round(accent_hpos, accent_gap+if is_cap: cap_height else: hi.x_height fi); z[jj]=z[ii]+(z[jj]' if is_cap: rotated (-the_cap_flat*(angle(z[jj]')-180)) fi); numeric theta; theta=angle(z[ii]-z[jj])+90; pos[jj](mid_stem,theta); pos[ii](hair,theta); else: pickup fine.nib; lft x[jj]'l=-hround(.5w-1.25hi.u); top y[jj]'=h-vround(2/3[h,hi.x_height]); z[ii]'=origin; pos[jj]'(mid_stem,0); pos[ii]'(vair,0); accent_gap=a_ht-y[jj]'-hi.x_height; if is_cap: numeric beta; beta=-the_cap_flat*(angle(z[jj]'-z[ii]')-180); z[ii]=round(accent_hpos,accent_gap+cap_height); z[jj]=z[ii]+(z[jj]' rotated beta); y[jj]r=y[jj]l=y[jj]; y[ii]r=y[ii]l=y[ii]; for xx:=jj,ii: forsuffixes $:=l,r: (z[xx]$-z[ii]) rotated -beta=whatever[z[jj]'$,z[ii]'$]; endfor\\ endfor else: for xx:=jj,ii: forsuffixes $:=r, ,l: z[xx]$=z[xx]'$+round(accent_hpos, accent_gap+if is_small_cap: cap_height else: x_height fi); endfor\\ endfor fi fi endgroup; enddef; def put_gravis= numeric accent_hpos; accent_hpos=.5w + if is_cap: .75 else: .5 fi\\ u if known hpos_corr: +hpos_corr fi; fix_grav_pairs; % |fix_grav_pairs| uses private values of |w|, |h| \& |u| numeric hpos_corr; % |hpos_corr| is local: forget its value % draw the diagonal: if serifs: pickup crisp.nib; filldraw circ_stroke (z[jj]e--z[ii]e); z[jj].right=directionpoint down of (z[jj]r{z[jj]r-z[ii]r}..{z[ii]l-z[jj]l}z[jj]l); z[jj].top=directionpoint left of (z[jj]r{z[jj]r-z[ii]r}..{z[ii]l-z[jj]l}z[jj]l); else: pickup fine.nib; filldraw stroke (z[jj]e--z[ii]e); z[jj].right=z[jj].top=z[jj]r; fi % adjust and save height (tho the height is never needed): h:=if is_cap: y[jj].top else: a_ht fi; if known sharp_calc: saved_height:=h; fi mark_height(a_ht#); penlabels([ii],[jj]); enddef; % --------------------------------------------------------------------------- % DOT ACCENT ACCESSORIES % --------------------------------------------------------------------------- %%% good penkind def put_dot (suffix penkind) (expr dd_) = % dot of the lowercase letter `i' fix_virgin z; numeric dd#; % sharp dot diameter dd#=dd_; define_whole_blacker_pixels(dd); % adjust height temporarily: h:=vround(if is_cap: (cap_height#+1.5u#+dd#) elseif (charcode=oct"273") or (charcode=oct"012"): i_ht#(dd) fi\\ *hppp); pickup penkind.nib; pos[jj](dd,90); pos[ii](dd,0); x[jj]=x[ii]=good.x(.5w+if charcode=oct"233": .5 else: if charcode=oct"235": 0 else: .25 fi\\fi\\ u); top y[jj]r=h+1; y[ii]=.5[y[jj]l,y[jj]r]; % draw the dot: dot([ii],[jj]); % dotted `Z' inherits the recently saved height (if known; usually the height % of the accented `Z') which allows to decrease by one the number of different % heights in a font; dotted `z' has the height of a lowercase `i' (exception: % caps and small caps) if known saved_height: h:=saved_height; fi\\ mark_height(i_ht#(dd)); penlabels([ii],[jj]); enddef; % --------------------------------------------------------------------------- % L's CROSS ACCESSORIES % --------------------------------------------------------------------------- def put_cross(expr l_jut,r_jut) = fix_virgin z; numeric dd; dd=if is_cap: cap_bar else: bar fi; numeric theta; theta=angle(11u#,.3[x_height#,cap_height#]); pickup crisp.nib; pos[ii](dd,theta+90); pos[jj](dd,theta+90); lft x[ii]r = hround(x1-l_jut)-eps; rt x[jj]l = hround(x1+r_jut)+eps; z[ii]-z[jj]=whatever*dir theta; % |.52| is one of CM (Computer Magic) numbers appearing in many CM programs, % among others in the programs for B, F, and H: whatever[z[ii],z[jj]]=if not is_cap and hefty: top fi\\ (x1,if charcode=32: .3[x_height,asc_height-serif_drop] % tc blank sign elseif charcode=147: .3x_height % tc recipe sign else: .52cap_height fi\\); % before drawing the stroke improve discretization: save eps_; eps_:=y[ii]l-good.y(y[ii]l); forsuffixes $:=l, ,r: y[ii]$:=y[ii]$-eps_; endfor eps_:=y[jj]r-good.y(y[jj]r); forsuffixes $:=l, ,r: y[jj]$:=y[jj]$-eps_; endfor filldraw stroke z[ii]e--z[jj]e; % now draw the stroke corrital z[jj]l; % correct italic correction penlabels([ii],[jj]); enddef; % --------------------------------------------------------------------------- % OGONEK ACCESSORIES % --------------------------------------------------------------------------- % This part is admittedly sophisticated, however, a wide spectrum of % different ogonek shapes is in fact to be programmed: one shape is needed % for caps, another for `a' with ogonek, yet another for `e' with ogonek, % as they all have different joins. Moreover, a sansserif ogonek differs % significantly from a serif one, a bold ogonek from a non-bold, an ogonek % for hefty fonts should still be different. And if you take into account % that the basic font unit |u| may change during one session of font % generation (monospace and caps-small-caps) and that a few different % pens may be used to draw a single letter, you'll understand why so many % |if| ... |else:| ... |fi| commands are used in the following code. % % Outer and inner edges of an ogonek (suffixed with |l| and |r|, resp.) % are single B\`ezier segments; the outer one, a path % |p=z_a..controls z_b and z_c ..z_d| % is constructed as follows: given pairs |z_a|, |z_d|, angles |alpha_a|, % |alpha_d| and two numbers |x_down|, |y_right|, find pairs |z_b| and |z_c| % such that the path |p| has the following properties: % (a) |direction p(z_a)=alpha_a| % (b) |direction p(z_d)=alpha_d-180| % (c) |direction p(x_down,some_y)=down| % (d) |direction p(some_x,y_right)=right| % The problem is solved using a ``double'' bisection method, provided % that appropriate limits |z_b'|, |z_b''| and |z_c'|, |z_c''| for |z_b| % and |z_c|, respectively, are given; more precisely, % |z_b=|$\lambda_b$|[z_b',zb'']| and |z_c=|$\lambda_c$|[z_c',zc'']| % is supposed to hold for given |z_b'|, |z_b''|, |z_c'|, |z_c''| and % some $0<\lambda_b,\lambda_c<1$. % % The inner edge is constructed by a careful modification of the outer one. % % If a default behaviour of our program is not satisfying, the user may % assign a value to the following ``emergency'' parameters (provided E knows % what E is doing): % |depth_corr|, |left_corr|, |top_breadth_corr|, |tip_breadth_corr|, % |tip_xcorr|, |tip_ycorr|, |pre_angle|, |post_angle|, % |pre_limit|, |post_limit|, |pre_lightness|, |post_lightness|, % |pre_deflexion|, and |post_deflexion|. % Any of these parameters, if known while generating a font, is used instead % of a default setting. The parameters are accessed only via macros: % |the_ogonek_depth#|, |the_left_pos|, |the_top_breadth_corr|, % |the_tip_breadth_corr|, |the_tip_pos|, % |the_pre_angle|, |the_post_angle|, |the_pre_limit|, |the_post_limit|, % |the_pre_lightness|, |the_post_lightness|, % |the_pre_deflexion|, and |the_post_deflexion|. % There is one sharp ogonek parameter, |ogonek_pen#|; a respective pen is % defined at the end of this file (and once again in POLKAP.MF after % |font_setup|) and used in the files PL_DL.MF, PL_ML.MF, PL_MLK.MF. % Any parameter may have its |lower| variant (see the file POLKAP.MF). % --------------------------------------------------------------------------- % two handy macros: vardef cross_point(expr a,b) (expr c,d) = save z_; pair z_; z_=whatever[a,b]; z_=whatever[c,d]; z_ % the crossing point of lines (not segments) |a--b| and |c--d| is returned enddef; vardef touch_time(expr p,q) = % a variant of |intersectionpoint| save x_,y_; (x_,y_)=p intersectiontimes q; if x_<0: 0 else: y_ fi enddef; % --------------------------------------------------------------------------- % the kernel routine for the ogonek: numeric x_down,x_down',y_right,y_right',alpha_a,alpha_d; pair z_a,z_b,z_b',z_b'',z_c,z_c',z_c'',z_d; pair nz_,pz_; % with plain's |solve| embeded calls are not allowed, hence a bit tricky % variation: %%% known zsolve vardef zsolve@#(suffix z_)= % |@#| is the name of a real monotonic function; it is assumed that % |@#(z_')<=0|, |@#(z_'')>0| holds for given |z_'| and |z_''| save nz_,pz_; pair nz_,pz_; % recursive calls are possible nz_:=z_'; pz_:=z_''; forever: z_:=.5[nz_,pz_]; exitif abs(nz_-pz_)<=tolerance; % by default |tolerance=.1| if @#(z_)<=0: nz_ else: pz_ fi :=z_; endfor % on exit |z_| is (hopefully) near the point where |@#| changes from % negative to positive enddef; vardef down_dir(expr z_b)= zsolve right_dir(z_c); % here |z_c| is computed lft(xpart(directionpoint down of (z_a..controls z_b and z_c..z_d)))-x_down enddef; vardef right_dir(expr z_c)= bot(ypart(directionpoint right of (z_a..controls z_b and z_c..z_d)))-y_right enddef; % --------------------------------------------------------------------------- % ogonek defaults: vardef the_ogonek_depth# = % sharp value if known depth_corr: depth_corr* fi\\ desc_depth# enddef; vardef the_left_pos = if known left_corr: left_corr* fi if monospace: 3.75 elseif serifs: if hefty: 2.3 elseif is_bold: 1.7 else: 1.9 fi else: % sansserif if is_bold: 1.65 else: 1.55 fi\\ fi\\ hi.u enddef; vardef the_tip_pos = (if monospace: 1.9 elseif serifs: if hefty: 1.85 elseif is_bold: 1.75 else: 2 fi\\ else: % sansserif if is_bold: 2.1 else: 1.95 fi\\ fi\\ hi.u, if serifs: if monospace: 1.25 elseif hefty: 1 elseif is_bold: .75 else: 1.45 fi else: % sansserif .45 fi\\ hi.u) if known tip_xcorr: xscaled\\ tip_xcorr fi if known tip_ycorr: yscaled\\ tip_ycorr fi enddef; vardef the_top_breadth_corr = if known top_breadth_corr: top_breadth_corr else: if serifs: 1 elseif is_bold: 1.12 elseif is_cap: 1.06 else: .96 fi\\ fi enddef; vardef the_tip_breadth_corr = if known tip_breadth_corr: tip_breadth_corr else: 1 fi enddef; vardef the_pre_angle = % refers to the outer edge if known pre_angle: pre_angle else: if serifs: if hefty: 208 elseif is_bold: 211 else: 214 fi\\ else: 211 fi fi enddef; vardef the_post_angle = % refers to the outer edge if known post_angle: post_angle else: if serifs: if monospace: 60 elseif hefty: 66 elseif is_bold: 55 else: 74 fi else: 25 fi\\ fi enddef; vardef the_pre_limit = % refers to the outer edge if known pre_limit: pre_limit else: x_down-3.5hi.u fi enddef; vardef the_post_limit = % refers to the outer edge if known post_limit: post_limit else: x_down-2hi.u fi enddef; vardef the_pre_lightness = % refers to the inner edge if known pre_lightness: pre_lightness else: if serifs and hefty: .97 elseif not serifs and is_bold: .6 elseif is_bold: .66 else: .78 fi\\ fi enddef; vardef the_post_lightness = % refers to the inner edge if known post_lightness: post_lightness else: if serifs: if hefty: .95 elseif is_bold: .66 else: .82 fi else: % sansserif .75 fi\\ fi enddef; vardef the_post_deflexion = % refers to the inner edge if known post_deflexion: post_deflexion elseif serifs and hefty: 0 else: -5 fi enddef; vardef the_pre_deflexion = % refers to the inner edge if known pre_deflexion: pre_deflexion elseif known join_angle and not serifs: if is_bold: -4 else: -2 fi\\ elseif not serifs: if is_bold: -8 else: -4 fi\\ else: 0 fi enddef; % --------------------------------------------------------------------------- %%% fine lo vardef lo suffix z = % in a way |lo| is a counterpart to |hi| if is_small_cap: z_a+((z-z_a) scaled sqrt(body_height#/higher.body_height#)) else: z fi enddef; % --------------------------------------------------------------------------- % parameters to |put_ogonek|: numeric join_angle; % starting (inner) ogonek direction, if known numeric ogonek_breadth; % ogonek breadth at the tip % starting (inner for `e' with ogonek, otherwise outer) ogonek position: pair ogonek_pos; % --------------------------------------------------------------------------- def put_ogonek(suffix penkind) = begingroup if monospace: % excerpt from |mono_adjust|: save u_; numeric u_; u_:=hi.u#; save u; u#:=u_; numeric expansion_faktor; mono_charwd#=2hi.letter_fit#+expansion_faktor*cap_A_wd#; % cap_A_wd=13u hi.u:=u#*expansion_faktor*hppp; % now |u| is like in the letter `A' fi fix_virgin z; pickup penkind.nib; % `a' with ogonek attached to the hook deserves a special treatment: if\\ (not is_small_cap) and (charcode=oct"241") and serifs and not is_bold: if ypart(ogonek_pos)>.5penkind: z[ii]~l=ogonek_pos; pos[ii]~(max(the_top_breadth_corr*ogonek_breadth,penkind+epsilon),0); ogonek_pos:=cross_point((0,.5penkind),(1,.5penkind)) (z[ii]~l,z[ii]~l+dir(the_pre_angle)); fi fi % similarly, `e' with ogonek deserves a special treatment: if\\ (not is_small_cap) and (charcode=oct"246"): if ypart(ogonek_pos)>.5penkind: z[ii]~r=ogonek_pos; pos[ii]~(max(the_top_breadth_corr*ogonek_breadth,penkind+epsilon),0); ogonek_pos:=cross_point((0,.5penkind),(1,.5penkind)) (z[ii]~l,z[ii]~l+dir(join_angle)); fi fi % invariant: |ypart(ogonek_pos)|$\le$|.5penkind|; % moreover, for `A' and `E': |ypart(ogonek_pos)=.5penkind| % OUTER EDGE: alpha_a:=the_pre_angle; % starting direction alpha_d:=180+the_post_angle; % ending direction x_down:=if serifs: hround else: ceiling fi (xpart(ogonek_pos)-the_left_pos); % left bound y_right:=-vround(d+hi.o); % bottom bound z_a:=(x_down+the_left_pos,ypart(ogonek_pos)); % starting point z_d:=(xpart(z_a)-.5penkind,y_right+ypart(ogonek_pos))+ the_tip_pos; % ending point % guess the boundaries for control points: z_b':=cross_point (z_a,z_a+dir alpha_a) ((the_pre_limit,0),(the_pre_limit,1)); z_b'':=cross_point (z_b',z_a)\\ ((x_down,0),(x_down,1)); z_c':=cross_point (z_d,z_d+dir alpha_d) ((the_post_limit,0),(the_post_limit,1)); z_c'':=cross_point (z_c',z_d)\\ ((0,y_right),(1,y_right)); % THE PIVOT STEP OF THE OGONEK PROCEDURE, i.e., % determine the control points (|z_b| and |z_c|) of the outer path: zsolve down_dir(z_b); % |down_dir| calls `|zsolve right_dir(z_c)|' x_down':=xpart(lft(directionpoint down of (z_a..controls z_b and z_c..z_d))); y_right':=ypart(bot(directionpoint right of (z_a..controls z_b and z_c..z_d))); if abs(x_down'-x_down,y_right'-y_right)>sqrt2: message "ERROR: `ogonek' iteration hasn't converged! Final values:"; message "x_down="&decimal x_down'&" (should be "&decimal x_down&")"; message "y_right="&decimal y_right'&" (should be "&decimal y_right&")"; errhelp "Maybe Jackowski knows how to change them..."; errmessage "Probably, you have to change somehow the boundary values"; fi % small caps have ogoneks a bit smaller: z[ii]l=z_a; z[ii]'l=lo.z_b; z[jj]'l=lo.z_c; z[jj]l=lo.z_d; % INNER EDGE: pos[ii](max(the_top_breadth_corr*ogonek_breadth,penkind+epsilon),0); pos[jj](max(the_tip_breadth_corr*ogonek_breadth,penkind+epsilon), angle(direction 1 of (z_a..controls z_b and z_c..z_d))+ if serifs: 90 else: 80 fi); z[ii]'r=z[ii]r+((z[ii]'l-z[ii]l) scaled the_pre_lightness rotated the_pre_deflexion); z[jj]'r=z[jj]r+((z[jj]'l-z[jj]l) scaled the_post_lightness rotated the_post_deflexion); % trim the top of the ogonek, if necessary: path ogonek.l, ogonek.r; numeric tt.r, tt.l; ogonek.l=if is_known z[ii]~: % minuscule with ogonek z[ii]~l{dir if charcode=oct"241": the_pre_angle else: join_angle fi}..fi z[ii]l..controls z[ii]'l and z[jj]'l..z[jj]l; ogonek.r=if is_known z[ii]~: % ditto z[ii]~r{dir if charcode=oct"241": the_pre_angle else: join_angle fi}..fi z[ii]r..controls z[ii]'r and z[jj]'r..z[jj]r; tt.r=if serifs and (not is_small_cap) and (charcode=oct"241"): touch_time(p.l,ogonek.r) else: 0 fi; tt.l=if\\ (not is_small_cap) and (charcode=oct"246"): touch_time(p.r,ogonek.l) else: 0 fi; % at last, draw the ogonek: if ogonek_breadth>.5: interim turningcheck:=0; filldraw if\\ (not is_small_cap) and (charcode=oct"246"): (point tt.r of ogonek.r){direction tt.r of ogonek.r}..{curl 1} fi subpath (tt.l,length ogonek.l) of ogonek.l-- reverse(subpath (tt.r,length ogonek.r) of ogonek.r) if is_small_cap or (charcode<>oct"246"): -- else: & fi\\ cycle; % the |draw| command covers with ink unwanted breaks: pickup pensquare scaled (.5*sqrt2) rotated 45; draw .5[z[ii]l,z[ii]r]..controls .5[z[ii]'l,z[ii]'r] and .5[z[jj]'l,z[jj]'r].. .5[z[jj]l,z[jj]r]; else: % poor resolution: pickup pensquare scaled (.5*sqrt2) rotated 45; draw z[ii]l..controls z[ii]'l and z[jj]'l..z[jj]l; fi numeric join_angle, ogonek_breadth; pair ogonek_pos; % all they are local penlabels([ii],[jj]); endgroup enddef; %******************************************************************************* % % This was csaccent.mf in text format, as of 89/05/08 % written by P. Novak, Prague % Czech and Slovak letters with accents % Changed paths for acute and hachek accent added 26/04/92, 11/08/92 % Accent definitions |lc_circle_accent| modified % |uc_Circle_accent| added for Duerer font % % 7 May 1995 did whole sale surgery to this part. Moved parameters to % dxpseudo.mf to be able to manipulate them from there. The Acute % accent is done the polish way, therefore removed all acute related % macros. Pseudoparametrised all kinds of |dot_diam|. % 17 Jun 1995 adjusted hachek height parameters to blend better with acute % parameters. Removed lots of stuff not used by the dc and tc fonts. % 17 Jul 1995 corrected uppercase hachek height for sans serif case % Removed many macros, which aren't used anymore % 23 Aug 1996 Adjusted |lc_hachek_accent| for dcsx font def lc_hachek_accent(expr ref) = if serifs: pickup crisp.nib; pos52'(0.75[vair,curve],90); pos52(0.75[vair,curve],90); x52=good.x ref; x52-x51=x53-x52=good.x if hach_sharp:2.5 else:3 fi accent_u-accent_thin; top y52' = top y51 = top y53 = lc_hachek_height; if hach_sharp: y52=max(2/3[h,hi.x_height],hi.x_height+o+hair); % lower point pos51(1.5stem,0); pos53(accent_thin,180); else: 0.5[y52,y52r] = 0.5[x_height,y52']; pos51(accent_thin,angle(z52-z51)+90); pos53(accent_thin,angle(z53-z52)+90); fi filldraw stroke z51e -- z52e -- z53e; else: pickup fine.nib; pos51(vair,0); pos53(vair,0); x52=good.x ref; x52-lft x51=rt x53-x52= hround(1.25accent_u + vair); pos52(stem,0); % bot y52=vround(0.3[x_height,lc_hachek_height]); bot y52=vround(max(2/3[h,hi.x_height],hi.x_height+o+hair)); top y51 = top y53 = lc_hachek_height; z50 = whatever[z51r,z52r] = whatever[z52l,z53l]; y54l=y54r=y52; x54l=good.x .2[x52l,x52]; x54r-x52 = x52-x54l; filldraw z54l -- z51l-- z51r -- z50 -- z53l -- z53r -- z54r -- cycle; fi penlabels(50,51,52,52',53,54); enddef; def dtl_hachek(text x_ref,y_ref) = pickup fine.nib; pickup fine.nib; x51=hround(x_ref); y51=vround(y_ref); comma(51,q,pdot_diam,.25accent_u,2/3comma_depth); penlabels(51); enddef; def uc_hachek_accent(expr ref) = if serifs: pickup crisp.nib; pos52'(0.75[vair,curve],90); pos52(0.75[vair,curve],90); x52=good.x ref; x52-x51=x53-x52=good.x 3accent_u-accent_thin; top y52' = top y51 = top y53 = % upper points % 0.55[x_height,lc_hachek_height]+uc_acc_shift; h-.75[vair,curve]+eps-max(2/3[h,hi.x_height],hi.x_height+o+hair) +cap_height; if hach_sharp: % y52=.1[x_height,y52']+uc_acc_shift; % lower point y52=max(2/3[h,hi.x_height],hi.x_height+o+hair)-hi.x_height+cap_height; pos51(1.5stem,0); pos53(2accent_thin,180); else: % 0.5[y52,y52r] = 0.5[x_height,y52'-uc_acc_shift]+uc_acc_shift; 0.5[y52,y52r] = if not hefty: max(2/3[h,hi.x_height],hi.x_height+o+hair)-hi.x_height+cap_height; else: max(2/3[h,hi.x_height],hi.x_height+o)-hi.x_height+cap_height-hair; fi pos51(accent_thin,angle(z52-z51)+90); pos53(accent_thin,angle(z53-z52)+90); fi filldraw stroke z51e -- z52e -- z53e; else: pickup fine.nib; pos51(vair,0); pos53(vair,0); x52=good.x ref; x52-x51=x53-x52= 1.75accent_u + .5vair; pos52(stem,0); bot y52= cap_height + .5 accent_gap; top y51 = top y53 = cap_height + acc_height; z50 = whatever[z51r,z52r] = whatever[z52l,z53l]; y54l=y54r=y52; x54l=good.x .2[x52l,x52]; x54r-x52 = x52-x54l; filldraw z54l -- z51l-- z51r -- z50 -- z53l -- z53r -- z54r -- cycle; fi penlabels(50,51,52,52',53,54); enddef; endinput; %%