michael@0: #!/usr/bin/python michael@0: # vim: set shiftwidth=4 tabstop=8 autoindent expandtab: michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: # For general fontforge documentation, see: michael@0: # http://fontforge.sourceforge.net/ michael@0: # For fontforge scripting documentation, see: michael@0: # http://fontforge.sourceforge.net/scripting-tutorial.html michael@0: # http://fontforge.sourceforge.net/scripting.html michael@0: # and most importantly: michael@0: # http://fontforge.sourceforge.net/python.html michael@0: michael@0: # To install what you need, on Ubuntu, michael@0: # sudo apt-get install python-fontforge michael@0: michael@0: from __future__ import print_function michael@0: import fontforge michael@0: michael@0: em = 1000 michael@0: michael@0: def newMathFont(aName): michael@0: print("Generating %s.otf..." % aName, end="") michael@0: mathFont = fontforge.font() michael@0: mathFont.fontname = aName michael@0: mathFont.familyname = aName michael@0: mathFont.fullname = aName michael@0: mathFont.copyright = "Copyright (c) 2014 Mozilla Corporation" michael@0: mathFont.encoding = "UnicodeFull" michael@0: michael@0: # Create a space character. Also force the creation of some MATH subtables michael@0: # so that OTS will not reject the MATH table. michael@0: g = mathFont.createChar(ord(" "), "space") michael@0: g.width = em michael@0: g.italicCorrection = 0 michael@0: g.topaccent = 0 michael@0: g.mathKern.bottomLeft = tuple([(0,0)]) michael@0: g.mathKern.bottomRight = tuple([(0,0)]) michael@0: g.mathKern.topLeft = tuple([(0,0)]) michael@0: g.mathKern.topRight = tuple([(0,0)]) michael@0: mathFont[ord(" ")].horizontalVariants = "space" michael@0: mathFont[ord(" ")].verticalVariants = "space" michael@0: return mathFont michael@0: michael@0: def saveMathFont(aFont): michael@0: aFont.em = em michael@0: aFont.ascent = aFont.descent = em/2 michael@0: aFont.hhea_ascent = aFont.os2_typoascent = aFont.os2_winascent = em/2 michael@0: aFont.descent = aFont.hhea_descent = em/2 michael@0: aFont.os2_typodescent = aFont.os2_windescent = em/2 michael@0: aFont.hhea_ascent_add = aFont.hhea_descent_add = 0 michael@0: aFont.os2_typoascent_add = aFont.os2_typodescent_add = 0 michael@0: aFont.os2_winascent_add = aFont.os2_windescent_add = 0 michael@0: aFont.os2_use_typo_metrics = True michael@0: aFont.generate(aFont.fontname + ".otf") michael@0: print(" done.") michael@0: michael@0: ################################################################################ michael@0: # Glyph variants and constructions michael@0: f = newMathFont("stretchy") michael@0: nvariants = 3 michael@0: michael@0: # Draw boxes for the size variants and glues michael@0: for i in range(0, nvariants): michael@0: s = em * (i + 1) michael@0: michael@0: g = f.createChar(-1, "h%d" % i) michael@0: p = g.glyphPen() michael@0: p.moveTo(0, -em) michael@0: p.lineTo(0, em) michael@0: p.lineTo(s, em) michael@0: p.lineTo(s, -em) michael@0: p.closePath() michael@0: g.width = s michael@0: michael@0: g = f.createChar(-1, "v%d" % i) michael@0: p = g.glyphPen() michael@0: p.moveTo(0, 0) michael@0: p.lineTo(0, s) michael@0: p.lineTo(2 * em, s) michael@0: p.lineTo(2 * em, 0) michael@0: p.closePath(); michael@0: g.width = 2 * em michael@0: michael@0: # Draw some pieces for stretchy operators michael@0: s = em * nvariants michael@0: michael@0: g = f.createChar(-1, "left") michael@0: p = g.glyphPen() michael@0: p.moveTo(0, -2 * em) michael@0: p.lineTo(0, 2 * em) michael@0: p.lineTo(s, em) michael@0: p.lineTo(s, -em) michael@0: p.closePath(); michael@0: g.width = s michael@0: michael@0: g = f.createChar(-1, "right") michael@0: p = g.glyphPen() michael@0: p.moveTo(0, -em) michael@0: p.lineTo(0, em) michael@0: p.lineTo(s, 2 * em) michael@0: p.lineTo(s, -2 * em) michael@0: p.closePath(); michael@0: g.width = s michael@0: michael@0: g = f.createChar(-1, "hmid") michael@0: p = g.glyphPen() michael@0: p.moveTo(0, -em) michael@0: p.lineTo(0, em) michael@0: p.lineTo(s, 2 * em) michael@0: p.lineTo(2 * s, em) michael@0: p.lineTo(2 * s, -em) michael@0: p.lineTo(s, -2 * em) michael@0: p.closePath(); michael@0: g.width = 2 * s michael@0: michael@0: g = f.createChar(-1, "bottom") michael@0: p = g.glyphPen() michael@0: p.moveTo(0, 0) michael@0: p.lineTo(0, s) michael@0: p.lineTo(2 * em, s) michael@0: p.lineTo(4 * em, 0) michael@0: p.closePath(); michael@0: g.width = 4 * em michael@0: michael@0: g = f.createChar(-1, "top") michael@0: p = g.glyphPen() michael@0: p.moveTo(0, 0) michael@0: p.lineTo(4 * em, 0) michael@0: p.lineTo(2 * em, -s) michael@0: p.lineTo(0, -s) michael@0: p.closePath(); michael@0: g.width = 4 * em michael@0: michael@0: g = f.createChar(-1, "vmid") michael@0: p = g.glyphPen() michael@0: p.moveTo(0, s) michael@0: p.lineTo(2 * em, s) michael@0: p.lineTo(4 * em, 0) michael@0: p.lineTo(2 * em, -s) michael@0: p.lineTo(0, -s) michael@0: p.closePath(); michael@0: g.width = 3 * em michael@0: michael@0: # Create small rectangle of various size for some exotic arrows that are michael@0: # unlikely to be stretchable with standard fonts. michael@0: hstretchy = [ michael@0: 0x219C, # leftwards wave arrow michael@0: 0x219D, # rightwards wave arrow michael@0: 0x219E, # leftwards two headed arrow michael@0: 0x21A0, # rightwards two headed arrow michael@0: 0x21A2 # leftwards arrow with tail michael@0: ] michael@0: vstretchy = [ michael@0: 0x219F, # upwards two headed arrow michael@0: 0x21A1, # downwards two headed arrow michael@0: 0x21A5, # upwards arrow from bar michael@0: 0x21A7, # downwards arrow from bar michael@0: 0x21A8 # up down arrow with base michael@0: ] michael@0: for i in range(0, 1 + nvariants + 1): michael@0: s = (i + 1) * em/10 michael@0: michael@0: g = f.createChar(hstretchy[i]) michael@0: p = g.glyphPen() michael@0: p.moveTo(0, -em/10) michael@0: p.lineTo(0, em/10) michael@0: p.lineTo(s, em/10) michael@0: p.lineTo(s, -em/10) michael@0: p.closePath() michael@0: g.width = s michael@0: michael@0: g = f.createChar(vstretchy[i]) michael@0: p = g.glyphPen() michael@0: p.moveTo(0, 0) michael@0: p.lineTo(0, s) michael@0: p.lineTo(2 * em/10, s) michael@0: p.lineTo(2 * em/10, 0) michael@0: p.closePath(); michael@0: g.width = 2 * em/10 michael@0: michael@0: # hstretchy[0] and vstretchy[0] have all the variants and the components. The others only have one of them. michael@0: s = em * nvariants michael@0: michael@0: f[hstretchy[0]].horizontalVariants = "uni219C h0 h1 h2" michael@0: f[hstretchy[0]].horizontalComponents = (("left", False, 0, 0, s), \ michael@0: ("h2", True, 0, 0, s), ("hmid", False, 0, 0, 2 * s), ("h2", True, 0, 0, s), \ michael@0: ("right", False, 0, 0, s)) michael@0: michael@0: f[hstretchy[1]].horizontalVariants = "uni219D h0" michael@0: f[hstretchy[2]].horizontalVariants = "uni219E h1" michael@0: f[hstretchy[3]].horizontalVariants = "uni21A0 h2" michael@0: f[hstretchy[4]].horizontalVariants = "uni21A2 h2" michael@0: f[hstretchy[4]].horizontalComponents = f[hstretchy[0]].horizontalComponents michael@0: michael@0: f[vstretchy[0]].verticalVariants = "uni219F v0 v1 v2" michael@0: f[vstretchy[0]].verticalComponents = (("bottom", False, 0, 0, s), \ michael@0: ("v2", True, 0, 0, s), ("vmid", False, 0, 0, 2 * s), ("v2", True, 0, 0, s), \ michael@0: ("top", False, 0, 0, s)) michael@0: michael@0: f[vstretchy[1]].verticalVariants = "uni21A1 v0" michael@0: f[vstretchy[2]].verticalVariants = "uni21A5 v1" michael@0: f[vstretchy[3]].verticalVariants = "uni21A7 v2" michael@0: f[vstretchy[4]].verticalVariants = "uni21A8" michael@0: f[vstretchy[4]].verticalComponents = f[vstretchy[0]].verticalComponents michael@0: michael@0: ################################################################################ michael@0: # Testing DisplayOperatorMinHeight michael@0: f.math.DisplayOperatorMinHeight = 8 * em michael@0: largeop = [0x2A1B, 0x2A1C] # integral with overbar/underbar michael@0: michael@0: # Draw boxes of size 1, 2, 7, 8, 9em. michael@0: for i in [1, 2, 7, 8, 9]: michael@0: s = em * i michael@0: if i == 1 or i == 2: michael@0: g = f.createChar(largeop[i-1]) michael@0: else: michael@0: g = f.createChar(-1, "L%d" % i) michael@0: p = g.glyphPen() michael@0: p.moveTo(0, 0) michael@0: p.lineTo(0, s) michael@0: p.lineTo(s, s) michael@0: p.lineTo(s, 0) michael@0: p.closePath(); michael@0: g.width = s michael@0: michael@0: f[largeop[0]].verticalVariants = "uni2A1B L7 L8 L9" michael@0: f[largeop[1]].verticalVariants = "uni2A1C L8" michael@0: michael@0: saveMathFont(f)