-
Notifications
You must be signed in to change notification settings - Fork 43
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
Optional cross-platform outline rendering mode #451
base: master
Are you sure you want to change the base?
Changes from 20 commits
c5d4e18
6ab0e28
40e0ec2
2828b01
ea05cf2
5885f0a
fb7a92f
b7a40ef
80050f2
49ead8c
7341e09
efd022e
fa56b6a
08a5ab8
5b07f18
c4f2ff5
5be6bb6
637fb2f
cbe8cd3
6347a73
343669e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
from fontTools.pens.recordingPen import RecordingPen | ||
|
||
""" | ||
An abstraction on top of CocoaPen / any Mac-specific operations | ||
so that fontGoggles can function as a platform-agnostic library | ||
""" | ||
|
||
|
||
CAN_COCOA = True | ||
|
||
try: | ||
from fontTools.pens.cocoaPen import CocoaPen | ||
# TODO some other feature detection? | ||
except ImportError: | ||
CAN_COCOA = False | ||
|
||
|
||
class Platform(): | ||
UseCocoa = CAN_COCOA | ||
|
||
@staticmethod | ||
def pathFromArrays(font, points, tags, contours): | ||
if Platform.UseCocoa: | ||
from ..mac.makePathFromOutline import makePathFromArrays | ||
return makePathFromArrays(points, tags, contours) | ||
else: | ||
rp = RecordingPen() | ||
font.draw(rp) | ||
return rp | ||
|
||
@staticmethod | ||
def pathFromGlyph(font, gid): | ||
if Platform.UseCocoa: | ||
from ..mac.makePathFromOutline import makePathFromGlyph | ||
return makePathFromGlyph(font, gid) | ||
else: | ||
rp = RecordingPen() | ||
font.draw_glyph_with_pen(gid, rp) | ||
return rp | ||
|
||
@staticmethod | ||
def convertRect(r): | ||
if Platform.UseCocoa: | ||
from ..mac.drawing import rectFromNSRect | ||
return rectFromNSRect(r) | ||
|
||
@staticmethod | ||
def convertColor(c): | ||
if Platform.UseCocoa: | ||
from ..mac.drawing import nsColorFromRGBA | ||
return nsColorFromRGBA(c) | ||
|
||
@staticmethod | ||
def drawCOLRv1Glyph(colorFont, glyphName, colorPalette, defaultColor): | ||
if Platform.UseCocoa: | ||
from AppKit import NSGraphicsContext | ||
from blackrenderer.backends.coregraphics import CoreGraphicsCanvas | ||
|
||
cgContext = NSGraphicsContext.currentContext().CGContext() | ||
colorFont.drawGlyph( | ||
glyphName, | ||
CoreGraphicsCanvas(cgContext), | ||
palette=colorPalette, | ||
textColor=defaultColor, | ||
) | ||
else: | ||
raise NotImplementedError() | ||
|
||
|
||
class PlatformPenWrapper(): | ||
def __init__(self, glyphSet, path=None): | ||
if Platform.UseCocoa: | ||
self.pen = CocoaPen(glyphSet, path=path) | ||
else: | ||
self.pen = RecordingPen() | ||
|
||
def draw(self, pen): | ||
self.pen.draw(pen) | ||
|
||
def getOutline(self): | ||
if isinstance(self.pen, CocoaPen): | ||
return self.pen.path | ||
else: | ||
return self.pen | ||
stenson marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import pytest, sys | ||
from asyncio import run | ||
from fontgoggles.font import getOpener | ||
from fontgoggles.misc.textInfo import TextInfo | ||
from testSupport import getFontPath | ||
from fontTools.pens.recordingPen import RecordingPen | ||
|
||
from fontgoggles.misc.platform import Platform | ||
|
||
font_paths = [ | ||
"MutatorSans.ttf", | ||
"MutatorSansBoldWide.ufo", | ||
"MutatorSans.designspace", | ||
] | ||
|
||
|
||
def test_cocoaAndNoCocoa(): | ||
def getDrawings(path): | ||
fontPath = getFontPath(path) | ||
_, opener, _ = getOpener(fontPath) | ||
font = opener(fontPath, 0) | ||
run(font.load(sys.stderr.write)) # to test support for non-async | ||
|
||
textInfo = TextInfo("abc") | ||
glyphs = font.getGlyphRunFromTextInfo(textInfo) | ||
glyphNames = [g.name for g in glyphs] | ||
glyphDrawings = list(font.getGlyphDrawings(glyphNames, True)) | ||
|
||
assert len(glyphs) == 3 | ||
assert len(glyphDrawings) == 3 | ||
|
||
return glyphDrawings | ||
|
||
for font_path in font_paths: | ||
glyphDrawings = getDrawings(font_path) | ||
for g in glyphDrawings: | ||
assert "NSBezierPath" in str(type(g.path)) | ||
|
||
Platform.UseCocoa = False | ||
stenson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
for font_path in font_paths: | ||
glyphDrawings = getDrawings(font_path) | ||
for g in glyphDrawings: | ||
assert isinstance(g.path, RecordingPen) | ||
stenson marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,15 +4,15 @@ py2app==0.28.8 | |
pyobjc==10.3.1 | ||
corefoundationasyncio==0.0.1 | ||
cocoa-vanilla==0.6.0 | ||
blackrenderer==0.6.0 | ||
fonttools[woff,lxml,unicode,ufo,type1]==4.53.1 | ||
### blackrenderer==0.6.0 # moved to setup.py | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These should stay, as they get updated by dependabot. Also, in setup.py you should ideally not pin dependencies, although you are right they should be mentioned (but either without version, or with a minimal version). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Totally makes sense. I did keep the pinned |
||
### fonttools[woff,lxml,unicode,ufo,type1]==4.53.1 # moved to setup.py | ||
# Temporarily add support for experimental extensions to the not-yet-official COLRv1 format: | ||
# fonttools[woff,ufo,type1,unicode,lxml] @ git+https://github.com/justvanrossum/fonttools@colrv1-varco | ||
uharfbuzz==0.42.0 | ||
python-bidi==0.4.2 # pin for now | ||
### uharfbuzz==0.42.0 # moved to setup.py | ||
### python-bidi==0.4.2 # pin for now # moved to setup.py | ||
jundo==0.1.2 | ||
ufo2ft==3.2.8 | ||
numpy==2.1.1 | ||
unicodedata2==15.1.0 | ||
### ufo2ft==3.2.8 # moved to setup.py | ||
### numpy==2.1.1 # moved to setup.py | ||
### unicodedata2==15.1.0 | ||
git+https://github.com/BlackFoundryCom/rcjk-tools/ | ||
delocate==0.11.0 # pin for now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to get rid of this additional class. All its methods are static, so might as well be functions in this module. If you like the "[Pp]latform" prefix in the client code, you could import the module "platform" instead of its contents, but I don't mind if you'd just import the needed names, ie.
from ..misc.platform import pathFromGlyph
.(Although then perhaps it's nicer to stick with the original funtion names, eg.
makePathFromGlyph
)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense! I went with just importing the names. The idea of the
Platform
class was just to have an easy way to set the global variable (Platform.UseCocoa
) but it’s just as easy to importas platform
and then setplatform.USE_COCOA
(as in the updated noCocoa test)