Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show font metrics #236

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions App/Resources/English.lproj/MainMenu.nib/designable.nib

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified App/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
Binary file not shown.
23 changes: 21 additions & 2 deletions Lib/fontgoggles/font/baseFont.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
from typing import Any, NamedTuple

from ..misc.properties import cachedProperty
from ..misc.hbShape import characterGlyphMapping
from . import mergeScriptsAndLanguages


class FontMetrics(NamedTuple):
xHeight: int
capHeight: int
ascender: int
descender: int


class BaseFont:

def __init__(self, fontPath, fontNumber, dataProvider=None):
Expand Down Expand Up @@ -53,6 +62,15 @@ def canReloadWithChange(self, externalFilePath):
def unitsPerEm(self):
return self.ttFont["head"].unitsPerEm

@cachedProperty
def fontMetrics(self):
return FontMetrics(
xHeight=self.ttFont["OS/2"].sxHeight,
capHeight=self.ttFont["OS/2"].sCapHeight,
ascender=self.ttFont["hhea"].ascent,
descender=self.ttFont["hhea"].descent,
)

@cachedProperty
def colorPalettes(self):
return None
Expand Down Expand Up @@ -102,7 +120,7 @@ def getGlyphRunFromTextInfo(self, textInfo, colorPalettesIndex=0, **kwargs):
else:
colorPalette = self.colorPalettes[colorPalettesIndex]

glyphs = GlyphsRun(len(text), self.unitsPerEm, direction in ("TTB", "BTT"), colorPalette)
glyphs = GlyphsRun(len(text), self.unitsPerEm, direction in ("TTB", "BTT"), self.fontMetrics, colorPalette)

for segmentText, segmentScript, segmentBiDiLevel, firstCluster in textInfo.segments:
if script is not None:
Expand Down Expand Up @@ -172,10 +190,11 @@ def varLocationChanged(self, varLocation):

class GlyphsRun(list):

def __init__(self, numChars, unitsPerEm, vertical, colorPalette=None):
def __init__(self, numChars, unitsPerEm, vertical, fontMetrics, colorPalette=None):
self.numChars = numChars
self.unitsPerEm = unitsPerEm
self.vertical = vertical
self.fontMetrics = fontMetrics
self._glyphToChars = None
self._charToGlyphs = None
self.endPos = (0, 0)
Expand Down
17 changes: 13 additions & 4 deletions Lib/fontgoggles/font/dsFont.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from fontTools.ttLib import TTFont
from fontTools.ufoLib import UFOReader
from fontTools.varLib.models import normalizeValue
from .baseFont import BaseFont
from .baseFont import BaseFont, FontMetrics
from .glyphDrawing import EmptyDrawing, GlyphDrawing
from .ufoFont import Glyph, NotDefGlyph, UFOState, extractIncludedFeatureFiles
from ..compile.compilerPool import compileUFOToPath, compileDSToBytes, CompilerError
Expand Down Expand Up @@ -196,18 +196,27 @@ def defaultInfo(self):
def unitsPerEm(self):
return self.defaultInfo.unitsPerEm

@cachedProperty
def fontMetrics(self):
return FontMetrics(
xHeight = getattr(self.defaultInfo, "xHeight", None),
capHeight = getattr(self.defaultInfo, "capHeight", None),
ascender = getattr(self.defaultInfo, "ascender", None),
descender= getattr(self.defaultInfo, "descender", None)
)

@cachedProperty
def defaultVerticalAdvance(self):
ascender = getattr(self.defaultInfo, "ascender", None)
descender = getattr(self.defaultInfo, "descender", None)
ascender = self.fontMetrics.ascender
descender = self.fontMetrics.descender
if ascender is None or descender is None:
return self.defaultInfo.unitsPerEm
else:
return ascender + abs(descender)

@cachedProperty
def defaultVerticalOriginY(self):
ascender = getattr(self.defaultInfo, "ascender", None)
ascender = self.fontMetrics.ascender
if ascender is None:
return self.defaultInfo.unitsPerEm # ???
else:
Expand Down
15 changes: 12 additions & 3 deletions Lib/fontgoggles/font/ufoFont.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ def _getShaper(self, fontData):
def unitsPerEm(self):
return self.info.unitsPerEm

@cachedProperty
def fontMetrics(self):
return FontMetrics(
xHeight = getattr(self.info, "xHeight", None),
capHeight = getattr(self.info, "capHeight", None),
ascender = getattr(self.info, "ascender", None),
descender= getattr(self.info, "descender", None)
)

def _getGlyph(self, glyphName, layerName=None):
glyph = self._cachedGlyphs.get((layerName, glyphName))
if glyph is None:
Expand Down Expand Up @@ -161,16 +170,16 @@ def _getHorizontalAdvance(self, glyphName):

@cachedProperty
def defaultVerticalAdvance(self):
ascender = getattr(self.info, "ascender", None)
descender = getattr(self.info, "descender", None)
ascender = self.fontMetrics.ascender
descender = self.fontMetrics.descender
if ascender is None or descender is None:
return self.info.unitsPerEm
else:
return ascender + abs(descender)

@cachedProperty
def defaultVerticalOriginY(self):
ascender = getattr(self.info, "ascender", None)
ascender = self.fontMetrics.ascender
if ascender is None:
return self.info.unitsPerEm # ???
else:
Expand Down
9 changes: 9 additions & 0 deletions Lib/fontgoggles/mac/drawing.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,12 @@ def drawText(txt, pt, color, font):
attrs = {AppKit.NSFontAttributeName: font,
AppKit.NSForegroundColorAttributeName: color}
AppKit.NSString.drawAtPoint_withAttributes_(txt, pt, attrs)


def drawLine(pt1, pt2, color, width):
line = AppKit.NSBezierPath.bezierPath()
line.moveToPoint_(AppKit.NSMakePoint(*pt1))
line.lineToPoint_(AppKit.NSMakePoint(*pt2))
line.setLineWidth_(width)
nsColorFromRGBA(color).set()
line.stroke()
31 changes: 28 additions & 3 deletions Lib/fontgoggles/mac/fontList.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from fontgoggles.font import defaultSortSpec, sniffFontType, sortedFontPathsAndNumbers
from fontgoggles.mac.drawing import (
blendRGBA,
drawLine,
nsColorFromRGBA,
nsRectFromRect,
rgbaFromNSColor,
Expand Down Expand Up @@ -267,7 +268,8 @@ class FontList(Group):
def __init__(self, project, projectProxy, width, itemSize, vertical=False,
relativeFontSize=0.7, relativeHBaseline=0.25,
relativeVBaseline=0.5, relativeMargin=0.1,
showFontFileName=True, selectionChangedCallback=None,
showFontFileName=True, showMetrics=True,
selectionChangedCallback=None,
glyphSelectionChangedCallback=None, arrowKeyCallback=None):
super().__init__((0, 0, width, 900))
self.project = None # Dummy, so we can set up other attrs first
Expand All @@ -287,6 +289,7 @@ def __init__(self, project, projectProxy, width, itemSize, vertical=False,
self.projectProxy = projectProxy
self.setupFontItems()
self.showFontFileName = showFontFileName
self.showMetrics = showMetrics

def _glyphSelectionChanged(self):
if self._glyphSelectionChangedCallback is not None:
Expand Down Expand Up @@ -439,6 +442,12 @@ async def relativeMargin(self):
for fontItem in self.iterFontItems():
fontItem.relativeMargin = self.relativeMargin

@hookedProperty
@asyncTaskAutoCancel
async def showMetrics(self):
for fontItem in self.iterFontItems():
fontItem.showMetrics = self.showMetrics

@suppressAndLogException
def resizeFontItems(self, itemSize, centerPoint=None):
if not self.project.fonts:
Expand Down Expand Up @@ -568,7 +577,7 @@ def refitFontItems(self):
h = itemSize
fontItem = FontItem((x, y, w, h), fontItemInfo.fontKey, index, self.vertical,
self.align, self.relativeFontSize, self.relativeHBaseline,
self.relativeVBaseline, self.relativeMargin)
self.relativeVBaseline, self.relativeMargin, self.showMetrics)
setattr(self, fontItemInfo.identifier, fontItem)
if fontItemInfo.font is not None:
# Font is already loaded, but the text needs to be updated.
Expand Down Expand Up @@ -899,9 +908,10 @@ class FontItem(Group):
relativeHBaseline = delegateProperty("glyphLineView")
relativeVBaseline = delegateProperty("glyphLineView")
relativeMargin = delegateProperty("glyphLineView")
showMetrics = delegateProperty("glyphLineView")

def __init__(self, posSize, fontKey, fontListIndex, vertical, align,
relativeSize, relativeHBaseline, relativeVBaseline, relativeMargin):
relativeSize, relativeHBaseline, relativeVBaseline, relativeMargin, showMetrics):
super().__init__(posSize)
# self._nsObject.setWantsLayer_(True)
# self._nsObject.setCanDrawSubviewsIntoLayer_(True)
Expand All @@ -914,6 +924,7 @@ def __init__(self, posSize, fontKey, fontListIndex, vertical, align,
self.relativeHBaseline = relativeHBaseline
self.relativeVBaseline = relativeVBaseline
self.relativeMargin = relativeMargin
self.showMetrics = showMetrics
self.align = align
self.selected = False
if vertical:
Expand Down Expand Up @@ -1018,6 +1029,7 @@ class FGGlyphLineView(AppKit.NSView):
relativeHBaseline = hookedProperty(_scheduleRedraw, default=0.25)
relativeVBaseline = hookedProperty(_scheduleRedraw, default=0.5)
relativeMargin = hookedProperty(_scheduleRedraw, default=0.1)
showMetrics = hookedProperty(_scheduleRedraw, default=True)

def init(self):
self = super().init()
Expand Down Expand Up @@ -1250,6 +1262,18 @@ def drawRect_(self, rect):
dx, dy = self.origin

invScale = 1 / self.scaleFactor

if self.showMetrics:
xHeight = dy + self._glyphs.fontMetrics.xHeight * self.scaleFactor
capHeight = dy + self._glyphs.fontMetrics.capHeight * self.scaleFactor
ascender = dy + self._glyphs.fontMetrics.ascender * self.scaleFactor
descender = dy + self._glyphs.fontMetrics.descender * self.scaleFactor
drawLine((0,dy), (self.bounds().size.width, dy), colors.selectedSpaceColor, 2)
drawLine((0,xHeight), (self.bounds().size.width, xHeight), colors.hoverSpaceColor, 2)
drawLine((0,capHeight), (self.bounds().size.width, capHeight), colors.hoverSpaceColor, 2)
drawLine((0,ascender), (self.bounds().size.width, ascender), colors.hoverColor, 1)
drawLine((0,descender), (self.bounds().size.width, descender), colors.hoverColor, 1)

rect = rectFromNSRect(rect)
rect = scaleRect(offsetRect(rect, -dx, -dy), invScale, invScale)

Expand Down Expand Up @@ -1371,6 +1395,7 @@ class GlyphLine(Group):
relativeHBaseline = delegateProperty("_nsObject")
relativeVBaseline = delegateProperty("_nsObject")
relativeMargin = delegateProperty("_nsObject")
showMetrics = delegateProperty("_nsObject")


class FGUnclickableTextField(AppKit.NSTextField):
Expand Down
7 changes: 7 additions & 0 deletions Lib/fontgoggles/mac/mainWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ def syncUISettingsWithProject(self):
uiSettings.windowPosition = [x, y, w, h]
uiSettings.fontListItemSize = self.fontList.itemSize
uiSettings.fontListShowFontFileName = self.fontList.showFontFileName
uiSettings.fontListShowMetrics = self.fontList.showMetrics

uiSettings.characterListVisible = self.w.mainSplitView.isPaneReallyVisible("characterList")
uiSettings.characterListSize = self.w.mainSplitView.paneSize("characterList")
Expand Down Expand Up @@ -245,6 +246,7 @@ def setupFontListGroup(self):
relativeVBaseline=self.project.textSettings.relativeVBaseline,
relativeMargin=self.project.textSettings.relativeMargin,
showFontFileName=self.project.uiSettings.fontListShowFontFileName,
showMetrics=self.project.uiSettings.fontListShowMetrics,
selectionChangedCallback=self.fontListSelectionChangedCallback,
glyphSelectionChangedCallback=self.fontListGlyphSelectionChangedCallback,
arrowKeyCallback=self.fontListArrowKeyCallback)
Expand Down Expand Up @@ -1031,6 +1033,9 @@ def showFormattingOptions_(self, sender):
def showFontFileName_(self, sender):
self.fontList.showFontFileName = not self.fontList.showFontFileName

def showMetrics_(self, sender):
self.fontList.showMetrics = not self.fontList.showMetrics

@suppressAndLogException
def validateMenuItem_(self, sender):
action = sender.action()
Expand All @@ -1047,6 +1052,8 @@ def validateMenuItem_(self, sender):
isVisible = self.w.mainSplitView.isPaneReallyVisible("formattingOptions")
elif action == "showFontFileName:":
isVisible = self.fontList.showFontFileName
elif action == "showMetrics:":
isVisible = self.fontList.showMetrics
elif action in ("previousTextLine:", "nextTextLine:"):
return bool(self.textEntry.textFilePath)
elif action == "copy:":
Expand Down
1 change: 1 addition & 0 deletions Lib/fontgoggles/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ class UISettings:
windowPosition: typing.Union[None, list] = None
fontListItemSize: float = 150
fontListShowFontFileName: bool = True
fontListShowMetrics: bool = True
characterListVisible: bool = True
characterListSize: float = 98
glyphListVisible: bool = True
Expand Down