Skip to content

Commit

Permalink
Merge pull request #53 from fonttools/bounds-sidebearings
Browse files Browse the repository at this point in the history
Add getBounds, getControlBouds, get/set*Margin methods
  • Loading branch information
anthrotype authored Feb 21, 2020
2 parents 755ef43 + 54f21d6 commit 83ffcf5
Show file tree
Hide file tree
Showing 6 changed files with 362 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/ufoLib2/objects/anchor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ class Anchor(AttrDictMixin):
name = attr.ib(default=None, type=Optional[str])
color = attr.ib(default=None, type=Optional[str])
identifier = attr.ib(default=None, type=Optional[str])

def move(self, delta):
x, y = delta
self.x += x
self.y += y
4 changes: 4 additions & 0 deletions src/ufoLib2/objects/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ class Component:
)
identifier = attr.ib(default=None, type=Optional[str])

def move(self, delta):
x, y = delta
self.transformation = self.transformation.translate(x, y)

# -----------
# Pen methods
# -----------
Expand Down
4 changes: 4 additions & 0 deletions src/ufoLib2/objects/contour.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ def open(self):
return True
return self.points[0].type == "move"

def move(self, delta):
for point in self.points:
point.move(delta)

# -----------
# Pen methods
# -----------
Expand Down
103 changes: 103 additions & 0 deletions src/ufoLib2/objects/glyph.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from collections import namedtuple
from copy import deepcopy
from typing import Any, Dict, List, Optional, Union

import attr
from fontTools.misc.transform import Transform
from fontTools.pens.pointPen import PointToSegmentPen, SegmentToPointPen
from fontTools.pens.boundsPen import BoundsPen, ControlBoundsPen

from ufoLib2.objects.anchor import Anchor
from ufoLib2.objects.contour import Contour
Expand Down Expand Up @@ -186,6 +188,14 @@ def copyDataFromGlyph(self, glyph):
pointPen = self.getPointPen()
glyph.drawPoints(pointPen)

def move(self, delta):
for contour in self.contours:
contour.move(delta)
for component in self.components:
component.move(delta)
for anchor in self.anchors:
anchor.move(delta)

# -----------
# Pen methods
# -----------
Expand Down Expand Up @@ -231,3 +241,96 @@ def verticalOrigin(self, value):
self.lib["public.verticalOrigin"] = value
elif "public.verticalOrigin" in self.lib:
del self.lib["public.verticalOrigin"]

# bounds and side-bearings

BoundingBox = namedtuple("BoundingBox", "xMin yMin xMax yMax")

def getBounds(self, layer=None):
if layer is None and self.components:
raise TypeError("layer is required to compute bounds of components")

pen = BoundsPen(layer)
self.draw(pen)
return pen.bounds if pen.bounds is None else self.BoundingBox(*pen.bounds)

def getControlBounds(self, layer=None):
if layer is None and self.components:
raise TypeError("layer is required to compute bounds of components")

pen = ControlBoundsPen(layer)
self.draw(pen)
return pen.bounds if pen.bounds is None else self.BoundingBox(*pen.bounds)

def getLeftMargin(self, layer=None):
bounds = self.getBounds(layer)
if bounds is None:
return None
return bounds.xMin

def setLeftMargin(self, value, layer=None):
bounds = self.getBounds(layer)
if bounds is None:
return None
diff = value - bounds.xMin
if diff:
self.width += diff
self.move((diff, 0))

def getRightMargin(self, layer=None):
bounds = self.getBounds(layer)
if bounds is None:
return None
return self.width - bounds.xMax

def setRightMargin(self, value, layer=None):
bounds = self.getBounds(layer)
if bounds is None:
return None
self.width = bounds.xMax + value

def getBottomMargin(self, layer=None):
bounds = self.getBounds(layer)
if bounds is None:
return None
if self.verticalOrigin is None:
return bounds.yMin
else:
return bounds.yMin - (self.verticalOrigin - self.height)

def setBottomMargin(self, value, layer=None):
bounds = self.getBounds(layer)
if bounds is None:
return None
# blindly copied from defcon Glyph._set_bottomMargin; not sure it's correct
if self.verticalOrigin is None:
oldValue = bounds.yMin
self.verticalOrigin = self.height
else:
oldValue = bounds.yMin - (self.verticalOrigin - self.height)
diff = value - oldValue
if diff:
self.height += diff

def getTopMargin(self, layer=None):
bounds = self.getBounds(layer)
if bounds is None:
return None
if self.verticalOrigin is None:
return self.height - bounds.yMax
else:
return self.verticalOrigin - bounds.yMax

def setTopMargin(self, value, layer=None):
bounds = self.getBounds(layer)
if bounds is None:
return
if self.verticalOrigin is None:
oldValue = self.height - bounds.yMax
else:
oldValue = self.verticalOrigin - bounds.yMax
diff = value - oldValue
if oldValue != value:
# Is this still correct when verticalOrigin was not previously set?
self.verticalOrigin = bounds.yMax + value
self.height += diff
5 changes: 5 additions & 0 deletions src/ufoLib2/objects/point.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ class Point:
def segmentType(self):
# alias for backward compatibility with defcon API
return self.type

def move(self, delta):
x, y = delta
self.x += x
self.y += y
Loading

0 comments on commit 83ffcf5

Please sign in to comment.