From b4fb48bdb6cbefb8895c9dda9624f4dc4e2afb5a Mon Sep 17 00:00:00 2001 From: be5invis Date: Tue, 4 Aug 2015 22:23:15 +0800 Subject: [PATCH] Added features, ccmp and mark. --- buildglyphs.patel | 21 +++---- features/common.fea | 58 +++++++++++++++++++ final.pe | 2 +- generate.js | 19 ++++++- glyphs/autobuilds.patel | 95 +++++++++++++++++++++++++------- glyphs/cyrillic-extended.patel | 3 +- glyphs/latin-basic-capital.patel | 28 +++++----- glyphs/overmarks.patel | 17 +++++- makefile | 2 +- parameters.patel | 2 +- support/glyph.patel | 28 +++++++--- 11 files changed, 212 insertions(+), 63 deletions(-) diff --git a/buildglyphs.patel b/buildglyphs.patel index 7cf05dcbb..171b83bb0 100644 --- a/buildglyphs.patel +++ b/buildglyphs.patel @@ -143,11 +143,11 @@ define [buildFont para recursive] : begin { define markLFZero (.anchors (.lf [tm (.x MIDDLE .y 0 .type BASE)])) - define capitalMarks (.anchors (.above markAboveCap.anchors.above .below markBelowZero.anchors.below .trailing markTrailingZero.anchors.trailing .lf markLFZero.anchors.lf)) - define bMarks (.anchors (.above markAboveCap.anchors.above .below markBelowZero.anchors.below .trailing markTrailingZero.anchors.trailing .lf markLFZero.anchors.lf)) - define eMarks (.anchors (.above markAboveLower.anchors.above .below markBelowZero.anchors.below .trailing markTrailingZero.anchors.trailing .lf markLFZero.anchors.lf)) - define pMarks (.anchors (.above markAboveLower.anchors.above .below markBelowLower.anchors.below .trailing markTrailingLower.anchors.trailing .lf markLFLower.anchors.lf)) - define ifMarks (.anchors (.above markAboveCap.anchors.above .below markBelowLower.anchors.below .trailing markTrailingLower.anchors.trailing .lf markLFLower.anchors.lf)) + define capitalMarks (.anchors (.above markAboveCap.anchors.above .below markBelowZero.anchors.below)) + define bMarks (.anchors (.above markAboveCap.anchors.above .below markBelowZero.anchors.below)) + define eMarks (.anchors (.above markAboveLower.anchors.above .below markBelowZero.anchors.below)) + define pMarks (.anchors (.above markAboveLower.anchors.above .below markBelowLower.anchors.below)) + define ifMarks (.anchors (.above markAboveCap.anchors.above .below markBelowLower.anchors.below)) Stroke.bindParameters para @@ -220,7 +220,6 @@ define [buildFont para recursive] : begin { local [dont-export] : set currentGlyph.dontExport true this.gizmo = globalTransform - this.set-width WIDTH begin @::[steps.map formOf] return nothing }]] env) @@ -264,14 +263,12 @@ define [buildFont para recursive] : begin { if [pickHash && [not pickHash.(name)]] : return nothing local variant : variantSelector`name || default local chosenGlyph glyphs`[name + '.' + variant] - set glyphs`name chosenGlyph + create-glyph name : glyph-construction { + include chosenGlyph AS_BASE + if unicode : assign-unicode unicode + } local allAliases : Object.keys glyphs :.filter [[k] -> [glyphs`k === glyphs.(chosenGlyph.name)]] set dependencyProfile`name : allAliases.concat dependencyProfile.(chosenGlyph.name) - if unicode : begin { - chosenGlyph.assign-unicode unicode - set chosenGlyph.dontExport false - set unicodeGlyphs.(chosenGlyph.unicode`[chosenGlyph.unicode.length - 1]) chosenGlyph - } } define [italic-variant name unicode] : create-glyph name : glyph-construction { if [para.italicangle > 0] { diff --git a/features/common.fea b/features/common.fea index e69de29bb..d1b151ffe 100644 --- a/features/common.fea +++ b/features/common.fea @@ -0,0 +1,58 @@ +lookup ccmpManual { + sub [i j]' @MG_above by [dotlessi dotlessj]; + + sub eta iotaBelow' by iotaLF; + sub eta @MG_above iotaBelow' by iotaLF; + sub eta @MG_above @MG_above iotaBelow' by iotaLF; + sub eta @MG_above @MG_above @MG_above iotaBelow' by iotaLF; + + sub [a A u cyra cyrA] ogonekBelow' by ogonekTR; + sub [a A u cyra cyrA] @MG_above ogonekBelow' by ogonekTR; + sub [a A u cyra cyrA] @MG_above @MG_above ogonekBelow' by ogonekTR; + sub [a A u cyra cyrA] @MG_above @MG_above @MG_above ogonekBelow' by ogonekTR; +} ccmpManual; + +feature ccmp { + script latn; + language dflt; + lookup ccmpManual; + script grek; + language dflt; + lookup ccmpManual; + script cyrl; + language dflt; + lookup ccmpManual; + script dflt; + language dflt; + lookup ccmpManual; +} ccmp; + +feature mark { + script latn; + language dflt; + lookup markAuto; + script grek; + language dflt; + lookup markAuto; + script cyrl; + language dflt; + lookup markAuto; + script dflt; + language dflt; + lookup markAuto; +} mark; + +feature mkmk { + script latn; + language dflt; + lookup mkmkAuto; + script grek; + language dflt; + lookup mkmkAuto; + script cyrl; + language dflt; + lookup mkmkAuto; + script dflt; + language dflt; + lookup mkmkAuto; +} mkmk; \ No newline at end of file diff --git a/final.pe b/final.pe index 6c6bd0d52..81c1463eb 100644 --- a/final.pe +++ b/final.pe @@ -18,7 +18,7 @@ RemoveOverlap(); ReplaceWithReference(4, 1); Print("Simplifying"); AddExtrema(); -Simplify(0, 2); +Simplify(0, 3); Print("Finalizing"); CorrectDirection(); CanonicalContours(); diff --git a/generate.js b/generate.js index c2cb68f35..aa324dd2c 100644 --- a/generate.js +++ b/generate.js @@ -46,7 +46,20 @@ if(argv.dumpmap) { if(argv.dumpfeature) { var featurefile = '\n\n'; // ccmp - var ccmp = ttfFont.features.ccmp; - featurefile += 'feature ccmp {' + ccmp.join(';\n') + ';} ccmp;' - fs.writeFileSync(argv.dumpfeature, featurefile, 'utf8') + // var ccmp = ttfFont.features.ccmp; + // featurefile += 'lookup ccmpAuto {' + ccmp.join(';\n') + ';} ccmpAuto;'; + + // markGlyphs + for(var key in ttfFont.features.markGlyphs){ + featurefile += '@MG_' + key + '= [' + ttfFont.features.markGlyphs[key].join(' ') + '];\n' + } + // mark + var mark = ttfFont.features.mark; + featurefile += 'lookup markAuto {' + mark.marks.join(';\n') + ';\n' + mark.bases.join(';\n') + ';} markAuto;' + + // mkmk + var mkmk = ttfFont.features.mkmk; + featurefile += 'lookup mkmkAuto {' + mkmk.marks.join(';\n') + ';\n' + mkmk.bases.join(';\n') + ';} mkmkAuto;' + + fs.writeFileSync(argv.dumpfeature, featurefile, 'utf8'); }; \ No newline at end of file diff --git a/glyphs/autobuilds.patel b/glyphs/autobuilds.patel index 148852116..4ce2c56fc 100644 --- a/glyphs/autobuilds.patel +++ b/glyphs/autobuilds.patel @@ -320,45 +320,100 @@ define customDecompositions ( ."\u0384" " \u0301" ."\u0385" " \u0308\u0301" ) -define [decompositionModify s] : s.replace [regex '\u0313\u0300'] "\u1FCD" - :.replace [regex '\u0313\u0301'] "\u1FCE" - :.replace [regex '\u0313\u0342'] "\u1FCF" - :.replace [regex '\u0314\u0300'] "\u1FDD" - :.replace [regex '\u0314\u0301'] "\u1FDE" - :.replace [regex '\u0314\u0342'] "\u1FDF" + +define [subParts parts] : begin { + local hasMarkAbove false + foreach p [items-of parts] : if [isAboveMark p] : set hasMarkAbove true + + # replace dotted-i and dotted-j with dotless equalivents + if [[parts.0 === glyphs.i || parts.0 === glyphs.ukrainiani] && hasMarkAbove] : parts.0 = glyphs.dotlessi + if [parts.0 === glyphs.j && hasMarkAbove] : parts.0 = glyphs.dotlessj + + # replace below marks with trailing marks + if parts.0.anchors.lf : set parts : parts.map : function [p] : if [p === glyphs.iotaBelow] glyphs.iotaLF p + if parts.0.anchors.trailing : set parts : parts.map : function [p] : if [p === glyphs.ogonekBelow] glyphs.ogonekTR p + + # composite greek overmarks + for [local j 0] [j < parts.length] [inc j] : piecewise { + [parts.(j) === glyphs.closeApostropheAbove] : begin { + set parts.(j) null + piecewise { + [parts.[j + 1] === glyphs.graveAbove] : set parts.[j + 1] glyphs.psilivaria + [parts.[j + 1] === glyphs.acuteAbove] : set parts.[j + 1] glyphs.psilioxia + [parts.[j + 1] === glyphs.perispomeniAbove] : set parts.[j + 1] glyphs.psiliperispomeni + } + } + [parts.(j) === glyphs.invCommaAbove] : begin { + set parts.(j) null + piecewise { + [parts.[j + 1] === glyphs.graveAbove] : set parts.[j + 1] glyphs.dasiavaria + [parts.[j + 1] === glyphs.acuteAbove] : set parts.[j + 1] glyphs.dasiaoxia + [parts.[j + 1] === glyphs.perispomeniAbove] : set parts.[j + 1] glyphs.dasiaperispomeni + } + } + } + return : parts.filter [[x] -> [not [not x]]] +} +define [pad s n] : begin { + while [s.length < n] : s = '0' + s + return s +} set font.features.ccmp () foreach code [range 0x0000 0xFFFF] : if [not unicodeGlyphs`code] : begin { local str : String.fromCharCode code - local nfd : fallback customDecompositions.(str) : decompositionModify : str.normalize 'NFD' + local nfd : fallback customDecompositions.(str) : str.normalize 'NFD' if [nfd.length > 1] : begin { local parts () local allFound true - local hasMarkAbove false foreach j [range 0 nfd.length] : begin { set parts`j unicodeGlyphs`[nfd.charCodeAt j] if [not parts`j] : set allFound false - if [isAboveMark parts`j] : set hasMarkAbove true } if allFound : begin { - local aliased false local namingParts : parts.slice 0 - if [[parts.0 === glyphs.i || parts.0 === glyphs.ukrainiani] && hasMarkAbove] : parts.0 = glyphs.dotlessi - if [parts.0 === glyphs.j && hasMarkAbove] : parts.0 = glyphs.dotlessj - local glyphName : namingParts.map [[part] -> part.name] :.join '_' - if glyphs.(glyphName) : begin { - local j 2 - while glyphs.[glyphName + '.alias' + j] : inc j - set glyphName [glyphName + '.alias' + j] - set aliased true - } + set parts : subParts parts + local composition : namingParts.map [[part] -> part.name] :.join ' ' + local glyphName : 'uni' + [pad [[code.toString 16].toUpperCase] 4] create-glyph glyphName : glyph-construction { assign-unicode code include parts.0 AS_BASE foreach part [items-of : parts.slice 1] : include part } - if [not aliased] : font.features.ccmp.push : 'sub ' + [glyphName.replace [regex '_' 'g'] ' '] + ' by ' + glyphName + if [not glyphs.(composition)] : begin { + font.features.ccmp.push : 'sub ' + composition + ' by ' + glyphName + set glyphs.(composition) glyphs.(glyphName) + } } } +} + +### Generate MARK and MKMK features +set font.features.mark (.marks () .bases ()) +set font.features.mkmk (.marks () .bases ()) +set font.features.markGlyphs (.) + +define [buildAnchorDescription glyph inserter propx propy] : begin { + local buf '' + foreach key [items-of : Object.keys glyph.anchors] : buf = buf + ' ' + inserter + ' @' + key + return buf +} + +foreach glyph [items-of glyphList] : if [glyph.anchors && [begin [local anchorKeys : Object.keys glyph.anchors] anchorKeys.length]] : begin { + local isMarkGlyph false + foreach key [items-of anchorKeys] : if [glyph.anchors.(key).type == 'mark'] : set isMarkGlyph true + + if isMarkGlyph { + then { + font.features.mark.marks.push : 'markClass [' + glyph.name + '] ' + [buildAnchorDescription glyph '' 'x' 'y'] + font.features.mkmk.marks.push : 'markClass [' + glyph.name + '] ' + [buildAnchorDescription glyph '' 'x' 'y'] + font.features.mkmk.bases.push : 'pos mark [' + glyph.name + '] ' + [buildAnchorDescription glyph 'mark' 'mbx' 'mby'] + foreach key [items-of anchorKeys] : begin { + if [not font.features.markGlyphs.(key)] : set font.features.markGlyphs.(key) () + font.features.markGlyphs.(key).push glyph.name + } + } + else : font.features.mark.bases.push : 'pos base [' + glyph.name + '] ' + [buildAnchorDescription glyph 'mark' 'x' 'y'] + } } \ No newline at end of file diff --git a/glyphs/cyrillic-extended.patel b/glyphs/cyrillic-extended.patel index 793914eda..bf85331b5 100644 --- a/glyphs/cyrillic-extended.patel +++ b/glyphs/cyrillic-extended.patel @@ -95,7 +95,8 @@ create-glyph 'dje' : glyph-construction { define [GeShape top] : glyph-construction { include : LShape top include : FlipAround MIDDLE [top / 2] 1 [-1] - include : VBarRight RIGHTSB [top + ACCENT] top + include : VBarRight RIGHTSB top [top + ACCENT] + reverse-last } create-glyph 'Ge' : glyph-construction { assign-unicode 0x490 diff --git a/glyphs/latin-basic-capital.patel b/glyphs/latin-basic-capital.patel index d175e8086..0fce87fda 100644 --- a/glyphs/latin-basic-capital.patel +++ b/glyphs/latin-basic-capital.patel @@ -195,23 +195,23 @@ define [BShape top] : glyph-construction { local turnbottom : bowl / 2 include : create-stroke - :.start-from SB top + :.start-from [SB - O] top :.heads-to RIGHTWARD :.set-width 0 STROKE :.line-to [RIGHTSB - SB * 0.5 - turnbottom] top :.arc-hv-to [RIGHTSB - SB * 0.5] turntop :.arc-vh-to [RIGHTSB - SB * 0.5 - turnbottom] [bowl - STROKE] - :.line-to SB [bowl - STROKE] + :.line-to [SB - O] [bowl - STROKE] :.heads-to LEFTWARD include : create-stroke - :.start-from SB 0 + :.start-from [SB - O] 0 :.heads-to RIGHTWARD :.set-width STROKE 0 :.line-to [RIGHTSB - turnbottom] 0 :.arc-hv-to RIGHTSB turnbottom :.arc-vh-to [RIGHTSB - turnbottom] bowl - :.line-to SB bowl + :.line-to [SB - O] bowl :.heads-to LEFTWARD include : create-stroke @@ -244,14 +244,14 @@ create-glyph 'D' : glyph-construction { :.heads-to UPWARD include : create-stroke - :.start-from SB 0 + :.start-from [SB - O] 0 :.heads-to RIGHTWARD :.set-width STROKE 0 :.line-to [RIGHTSB - bsmooth] 0 :.arc-hv-to RIGHTSB dsmooth :.line-to RIGHTSB [CAP - dsmooth] :.arc-vh-to [RIGHTSB - bsmooth] CAP - :.line-to SB CAP + :.line-to [SB - O] CAP :.heads-to LEFTWARD } create-glyph 'P' : glyph-construction { @@ -267,13 +267,13 @@ create-glyph 'P' : glyph-construction { local turnRadius : [bowlTop - bowlBottom] / 2 include : create-stroke - :.start-from [SB * 1.25 + HALFSTROKE * 0.1] bowlTop + :.start-from [SB * 1.25 - O] bowlTop :.heads-to RIGHTWARD :.set-width 0 STROKE :.line-to [RIGHTSB - turnRadius] bowlTop :.arc-hv-to [RIGHTSB - O] turn :.arc-vh-to [RIGHTSB - turnRadius] bowlBottom - :.line-to [SB * 1.25 + HALFSTROKE * 0.1] bowlBottom + :.line-to [SB * 1.25 - O] bowlBottom :.heads-to LEFTWARD include : create-stroke @@ -396,9 +396,9 @@ create-glyph 'U' : glyph-construction { define [FShape] : glyph-construction { include : create-stroke :.start-from [SB * 1.5] 0 :.heads-to UPWARD :.set-width 0 STROKE :.line-to [SB * 1.5] CAP :.heads-to UPWARD - include : create-stroke :.start-from [SB * 1.5] CAP :.set-width 0 STROKE :.heads-to RIGHTWARD + include : create-stroke :.start-from [SB * 1.5 - O] CAP :.set-width 0 STROKE :.heads-to RIGHTWARD :.line-to RIGHTSB CAP :.heads-to RIGHTWARD - include : create-stroke :.start-from [SB * 1.5] [CAP * 0.54] :.set-width HALFSTROKE HALFSTROKE :.heads-to RIGHTWARD + include : create-stroke :.start-from [SB * 1.5 - O] [CAP * 0.54] :.set-width HALFSTROKE HALFSTROKE :.heads-to RIGHTWARD :.line-to [RIGHTSB - HALFSTROKE] [CAP * 0.54] :.heads-to RIGHTWARD } create-glyph 'F' : glyph-construction { @@ -413,7 +413,7 @@ create-glyph 'E' : glyph-construction { include capitalMarks include : FShape - include : create-stroke :.start-from [SB * 1.5] 0 :.set-width STROKE 0 :.heads-to RIGHTWARD + include : create-stroke :.start-from [SB * 1.5 - O] 0 :.set-width STROKE 0 :.heads-to RIGHTWARD :.line-to RIGHTSB 0 :.heads-to RIGHTWARD } define [HShape top] : glyph-construction { @@ -421,8 +421,8 @@ define [HShape top] : glyph-construction { :.line-to SB top :.heads-to UPWARD include : create-stroke :.start-from RIGHTSB 0 :.heads-to UPWARD :.set-width STROKE 0 :.line-to RIGHTSB top :.heads-to UPWARD - include : create-stroke :.start-from SB [top / 2] :.set-width HALFSTROKE HALFSTROKE :.heads-to RIGHTWARD - :.line-to RIGHTSB [top / 2] :.heads-to RIGHTWARD + include : create-stroke :.start-from [SB - O] [top / 2] :.set-width HALFSTROKE HALFSTROKE :.heads-to RIGHTWARD + :.line-to [RIGHTSB + O] [top / 2] :.heads-to RIGHTWARD } create-glyph 'H' : glyph-construction { set-width WIDTH @@ -438,7 +438,7 @@ define [LShape top] : glyph-construction { :.line-to [SB * 1.5] 0 :.heads-to DOWNWARD include : create-stroke - :.start-from [SB * 1.5] 0 + :.start-from [SB * 1.5 - O] 0 :.set-width STROKE 0 :.heads-to RIGHTWARD :.line-to RIGHTSB 0 diff --git a/glyphs/overmarks.patel b/glyphs/overmarks.patel index 11283eb2a..deaffadf5 100644 --- a/glyphs/overmarks.patel +++ b/glyphs/overmarks.patel @@ -346,7 +346,7 @@ create-glyph 'ogonekBelow' : glyph-construction { local ogonekBot : [mix belowMarkTop belowMarkBot 0.75] + markStress * 2 local ogonekLeft : markMiddle - markExtend * 0.2 local ogonekRight : markMiddle + markExtend * 0.85 - set-anchor 'trailing' MARK markMiddle 0 ogonekRight ogonekBot + set-anchor 'below' MARK markMiddle 0 markMiddle belowMarkBot include : create-stroke :.start-from markMiddle 0 @@ -358,14 +358,27 @@ create-glyph 'ogonekBelow' : glyph-construction { :.line-to ogonekRight ogonekBot :.heads-to RIGHTWARD } +create-glyph 'ogonekTR' : glyph-construction { + set-width 0 + include glyphs.ogonekBelow + local ogonekBot : [mix belowMarkTop belowMarkBot 0.75] + markStress * 2 + local ogonekRight : markMiddle + markExtend * 0.85 + set-anchor 'trailing' MARK markMiddle 0 ogonekRight ogonekBot +} create-glyph 'iotaBelow' : glyph-construction { set-width 0 assign-unicode 0x345 - set-anchor 'lf' MARK markMiddle 0 markMiddle belowMarkBot + set-anchor 'below' MARK markMiddle 0 markMiddle belowMarkBot include : VBar markMiddle belowMarkBot belowMarkTop [markHalfStroke * 2] } +create-glyph 'iotaLF' : glyph-construction { + # iotabelow glyph for /eta + set-width 0 + set-anchor 'lf' MARK markMiddle 0 markMiddle belowMarkBot + include : VBar markMiddle belowMarkBot belowMarkTop [markHalfStroke * 2] +} # Flipped below marks create-glyph 'dotBelow' : glyph-construction { set-width 0 diff --git a/makefile b/makefile index 5170020d0..7fb910407 100644 --- a/makefile +++ b/makefile @@ -28,7 +28,7 @@ $(OBJDIR)/.pass0-iosevka-bolditalic.ttf : $(FILES) | $(OBJDIR) $(ABFEAT) : $(OBJDIR)/.pass0-%.ab.fea : $(OBJDIR)/.pass0-%.ttf -@echo Autobuild feature $@ from $< -$(FEATURE) : $(OBJDIR)/.pass0-%.fea : features/common.fea $(OBJDIR)/.pass0-%.ab.fea +$(FEATURE) : $(OBJDIR)/.pass0-%.fea : $(OBJDIR)/.pass0-%.ab.fea features/common.fea cat $^ > $@ # Pass 1 : Outline cleanup and merge diff --git a/parameters.patel b/parameters.patel index 945ef10cc..93c0b66a5 100644 --- a/parameters.patel +++ b/parameters.patel @@ -39,7 +39,7 @@ define regular ( .family 'Iosevka' .style 'Regular' .weight 400 - .version 'r0.0.9' + .version 'r0.0.10' .variantSelector (.) .copyright 'Copyright (c) 2015 Belleve Invis.' ) diff --git a/support/glyph.patel b/support/glyph.patel index 7b422e468..dd01ddf6e 100644 --- a/support/glyph.patel +++ b/support/glyph.patel @@ -123,14 +123,26 @@ define [Glyph.prototype.include component copyAnchors] : begin { [[fallback anchorThis.mbx anchorThis.x] - anchorThat.x] [[fallback anchorThis.mby anchorThis.y] - anchorThat.y] ) - if [anchorThat.mbx !== nothing && anchorThat.mby !== nothing] : begin { - set this.anchors`markid ( - .x [anchorThis.x + anchorThat.mbx - anchorThat.x] - .y [anchorThis.y + anchorThat.mby - anchorThat.y] - .type anchorThis.type - .mbx anchorThis.mbx - .mby anchorThis.mby - ) + # we have a mark-to-mark position + if [anchorThat.mbx !== nothing && anchorThat.mby !== nothing] : if [anchorThis.type === 'base'] { + then { + set this.anchors`markid ( + .x [anchorThis.x + anchorThat.mbx - anchorThat.x] + .y [anchorThis.y + anchorThat.mby - anchorThat.y] + .type anchorThis.type + .mbx anchorThis.mbx + .mby anchorThis.mby + ) + } + else { + set this.anchors`markid ( + .mbx [anchorThis.mbx + anchorThat.mbx - anchorThat.x] + .mby [anchorThis.mby + anchorThat.mby - anchorThat.y] + .type anchorThis.type + .x anchorThis.x + .y anchorThis.y + ) + } } } }