Skip to content

Commit

Permalink
Support narrow/halfwidth forms as the context
Browse files Browse the repository at this point in the history
This patch includes narrow/halfwidth forms as the context of kerning,
as long as the target glyph is fullwidth.

Fixes issue #38.
  • Loading branch information
kojiishi committed Jan 4, 2022
1 parent 02678a8 commit 70f92ee
Show file tree
Hide file tree
Showing 42 changed files with 282 additions and 63 deletions.
6 changes: 6 additions & 0 deletions east_asian_spacing/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ def __init__(self):
self.cjk_colon_semicolon = {0xFF1A, 0xFF1B}
self.cjk_exclam_question = {0xFF01, 0xFF1F}

# Narrow/Halfwidth forms do not have internal spacings,
# but they can appear in the context.
# E.g., full-closing should kern if followed by a narrow-closing.
self.narrow_opening = {0x28, 0x5B, 0xFF62}
self.narrow_closing = {0x29, 0x5D, 0xFF63}

# Skip adding the features to fonts with monospace ASCII.
self.skip_monospace_ascii = False
# Determines the applicability by computing ink bounds.
Expand Down
65 changes: 43 additions & 22 deletions east_asian_spacing/spacing.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ def __init__(self,
self.middle = middle if middle is not None else GlyphDataList()
self.space = space if space is not None else GlyphDataList()

# Not-applicable left and right. They are not kerned, but they can
# appear in the context.
self.na_left = GlyphDataList()
self.na_right = GlyphDataList()

self._add_glyphs_count = 0
# For checking purposes. Because this class keeps glyph IDs, using the
# same instance for different fonts may lead to unexpected behaviors,
Expand Down Expand Up @@ -84,6 +89,8 @@ def assert_glyphs_are_disjoint(self):
assert self.middle.isdisjoint(self.right)
assert self.middle.isdisjoint(self.space)
assert self.right.isdisjoint(self.space)
assert self.left.isdisjoint(self.na_left)
assert self.right.isdisjoint(self.na_right)

def _to_str(self, glyph_ids=False):
name_and_glyph_data_lists = self._name_and_glyph_data_lists
Expand Down Expand Up @@ -148,6 +155,8 @@ def unite(self, other):
self.middle |= other.middle
self.right |= other.right
self.space |= other.space
self.na_left |= other.na_left
self.na_right |= other.na_right
self._all_glyphs |= other._all_glyphs

def add_by_ink_part(self, glyphs: Iterable[GlyphData], font):
Expand All @@ -163,16 +172,11 @@ def add_by_ink_part(self, glyphs: Iterable[GlyphData], font):

def ifilter_fullwidth(self, font: Font):
em = font.fullwidth_advance
self.left.ifilter_advance(em)
self.right.ifilter_advance(em)
self.left.ifilter_advance(em, self.na_left)
self.right.ifilter_advance(em, self.na_right)
self.middle.ifilter_advance(em)
self.space.ifilter_advance(em)

def ifilter_ink_part(self):
self.left.ifilter_ink_part(InkPart.LEFT)
self.right.ifilter_ink_part(InkPart.RIGHT)
self.middle.ifilter_ink_part(InkPart.MIDDLE)

async def add_glyphs(self, font, config):
self.assert_font(font)
config = config.for_font(font)
Expand All @@ -196,20 +200,23 @@ async def add_glyphs(self, font, config):

class _ShapeHelper(object):

def __init__(self, glyph_sets: 'GlyphSets', font, log_name=None):
def __init__(self, glyph_sets: 'GlyphSets', font: Font, log_name=None):
self._font = font
self._all_glyphs = glyph_sets._all_glyphs
self._log_name = log_name

async def shape(self,
unicodes,
language=None,
fullwidth=True,
temporary=False) -> GlyphDataList:
font = self._font
text = ''.join(chr(c) for c in unicodes)
# Unified code points (e.g., U+2018-201D) in most fonts are Latin glyphs.
features = []
# Enable "fwid" feature to get fullwidth glyphs.
features = ['fwid', 'vert'] if font.is_vertical else ['fwid']
if fullwidth: features.append('fwid')
if font.is_vertical: features.append('vert')
shaper = Shaper(font,
language=language,
script='hani',
Expand Down Expand Up @@ -259,24 +266,32 @@ async def ensure_fullwidth_advance(font: Font, config: Config) -> bool:
return False

async def get_opening_closing(self, font, config):
opening = config.cjk_opening | config.quotes_opening
closing = config.cjk_closing | config.quotes_closing
cjk_opening = config.cjk_opening | config.quotes_opening
cjk_closing = config.cjk_closing | config.quotes_closing
shaper = GlyphSets._ShapeHelper(self, font, log_name='opening_closing')
left, right, middle, space = await asyncio.gather(
shaper.shape(closing), shaper.shape(opening),
shaper.shape(cjk_closing), shaper.shape(cjk_opening),
shaper.shape(config.cjk_middle),
shaper.shape(config.fullwidth_space))
trio = GlyphSets(left, right, middle, space)
if font.is_vertical:
# Left/right in vertical should apply only if they have `vert` glyphs.
# YuGothic/UDGothic doesn't have 'vert' glyphs for U+2018/201C/301A/301B.
horizontal = await self._shape(font.horizontal_font,
opening | closing)
cjk_opening | cjk_closing)
trio.left -= horizontal
trio.right -= horizontal
else:
assert not trio.na_left
assert not trio.na_right
trio.na_left, trio.na_right = await asyncio.gather(
shaper.shape(config.narrow_closing, fullwidth=False),
shaper.shape(config.narrow_opening, fullwidth=False))
trio.assert_glyphs_are_disjoint()
if config.use_ink_bounds:
trio.ifilter_ink_part()
trio.left.ifilter_ink_part(InkPart.LEFT, self.na_left)
trio.right.ifilter_ink_part(InkPart.RIGHT, self.na_right)
trio.middle.ifilter_ink_part(InkPart.MIDDLE)
return trio

async def get_period_comma(self, font, config):
Expand All @@ -297,7 +312,9 @@ async def get_period_comma(self, font, config):
zht.clear()
trio = GlyphSets(ja, None, zht)
if config.use_ink_bounds:
trio.ifilter_ink_part()
trio.left.ifilter_ink_part(InkPart.LEFT)
trio.right.ifilter_ink_part(InkPart.RIGHT)
trio.middle.ifilter_ink_part(InkPart.MIDDLE)
trio.assert_glyphs_are_disjoint()
return trio

Expand Down Expand Up @@ -418,10 +435,13 @@ def add_from_cache(self, font, glyphs: GlyphDataList) -> GlyphDataList:

class PosValues(object):

def __init__(self, font: Font, trio) -> None:
self.left, self.right, self.middle, self.space = (
def __init__(self, font: Font, glyph_sets: 'GlyphSets') -> None:
glyph_sets.assert_glyphs_are_disjoint()
self.left, self.right, self.middle, self.space, self.na_left, self.na_right = (
tuple(font.glyph_names(sorted(glyphs.glyph_id_set)))
for glyphs in trio._glyph_data_lists)
for glyphs in (glyph_sets.left, glyph_sets.right,
glyph_sets.middle, glyph_sets.space,
glyph_sets.na_left, glyph_sets.na_right))

em = font.fullwidth_advance
# When `em` is an odd number, ceil the advance. To do this, use
Expand Down Expand Up @@ -545,7 +565,7 @@ def _build_single_pos_lookup(
return lookup

def _build_chws_lookup(self, font: Font, lookups: List[otTables.Lookup],
pos) -> List[int]:
pos: 'GlyphSets.PosValues') -> List[int]:
self.assert_font(font)
lookup_indices = []

Expand All @@ -554,7 +574,7 @@ def _build_chws_lookup(self, font: Font, lookups: List[otTables.Lookup],
pair_pos_builder = PairPosBuilder(ttfont, None)
pair_pos_builder.addClassPair(
None, pos.left, pos.left_value,
pos.left + pos.right + pos.middle + pos.space, None)
pos.left + pos.right + pos.middle + pos.space + pos.na_left, None)
lookup = pair_pos_builder.build()
assert lookup
lookup_indices.append(len(lookups))
Expand All @@ -569,8 +589,9 @@ def _build_chws_lookup(self, font: Font, lookups: List[otTables.Lookup],

chain_context_pos_builder = ChainContextPosBuilder(ttfont, None)
chain_context_pos_builder.rules.append(
ChainContextualRule([pos.right + pos.middle + pos.space],
[pos.right], [], [[single_pos_lookup]]))
ChainContextualRule(
[pos.right + pos.middle + pos.space + pos.na_right],
[pos.right], [], [[single_pos_lookup]]))
lookup = chain_context_pos_builder.build()
assert lookup
lookup_indices.append(len(lookups))
Expand Down
8 changes: 7 additions & 1 deletion references/BIZ-UDGothicR.ttc-0.G_P_O_S_.ttx.diff
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont ttLibVersion="4.26">
+<ttFont ttLibVersion="4.28">
+
+ <GPOS>
+ <Version value="0x00010000"/>
Expand Down Expand Up @@ -147,6 +147,8 @@
+ <ClassDef1>
+ </ClassDef1>
+ <ClassDef2>
+ <ClassDef glyph="bracketright" class="1"/>
+ <ClassDef glyph="parenright" class="1"/>
+ <ClassDef glyph="quotedblleft" class="1"/>
+ <ClassDef glyph="quotedblright" class="1"/>
+ <ClassDef glyph="quoteleft" class="1"/>
Expand Down Expand Up @@ -185,6 +187,7 @@
+ <ClassDef glyph="uniFF5D" class="1"/>
+ <ClassDef glyph="uniFF5F" class="1"/>
+ <ClassDef glyph="uniFF60" class="1"/>
+ <ClassDef glyph="uniFF63" class="1"/>
+ </ClassDef2>
+ <!-- Class1Count=1 -->
+ <!-- Class2Count=2 -->
Expand Down Expand Up @@ -231,6 +234,8 @@
+ <ChainContextPos index="0" Format="3">
+ <!-- BacktrackGlyphCount=1 -->
+ <BacktrackCoverage index="0">
+ <Glyph value="parenleft"/>
+ <Glyph value="bracketleft"/>
+ <Glyph value="uni3000"/>
+ <Glyph value="uni30FB"/>
+ <Glyph value="uniFF1A"/>
Expand All @@ -250,6 +255,7 @@
+ <Glyph value="uni3018"/>
+ <Glyph value="uni3016"/>
+ <Glyph value="uni301D"/>
+ <Glyph value="uniFF62"/>
+ </BacktrackCoverage>
+ <!-- InputGlyphCount=1 -->
+ <InputCoverage index="0">
Expand Down
6 changes: 6 additions & 0 deletions references/BIZ-UDGothicR.ttc-glyphs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,14 @@
# 0 U+301B 〛
# 0 U+301E 〞
# 0 U+301A 〚
# 10 U+0028 (
# 11 U+0029 )
# 61 U+005B [
# 63 U+005D ]
# 105 U+FF1F ?
# 106 U+FF01 !
# 12419 U+FF62 「
# 12420 U+FF63 」
# vertical.left
11951 # U+3001 、
11952 # U+3002 。
Expand Down
6 changes: 3 additions & 3 deletions references/BIZ-UDGothicR.ttc.tables.diff
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Font 0: "BIZ UDGothic" "Regular" PS="BIZ-UDGothic"
Font 1: "BIZ UDPGothic" "Regular" PS="BIZ-UDPGothic"
Tag Size
+GPOS 648 [0]
+GPOS 672 [0]
GSUB 43,556 [0]
GSUB 45,586 [1]
OS/2 96 [0]
Expand All @@ -14,7 +14,7 @@
-Data: 5,027,902
-Gap: 650
-Tables: 24
+Total: 5,029,202
+Data: 5,028,550
+Total: 5,029,226
+Data: 5,028,574
+Gap: 652
+Tables: 25
6 changes: 6 additions & 0 deletions references/NotoSansCJK-Bold.ttc-0.G_P_O_S_.ttx.diff
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,8 @@
+ <ClassDef1>
+ </ClassDef1>
+ <ClassDef2>
+ <ClassDef glyph="cid00010" class="1"/>
+ <ClassDef glyph="cid00062" class="1"/>
+ <ClassDef glyph="cid01396" class="1"/>
+ <ClassDef glyph="cid01397" class="1"/>
+ <ClassDef glyph="cid01398" class="1"/>
Expand Down Expand Up @@ -747,6 +749,7 @@
+ <ClassDef glyph="cid59139" class="1"/>
+ <ClassDef glyph="cid59140" class="1"/>
+ <ClassDef glyph="cid59141" class="1"/>
+ <ClassDef glyph="cid59144" class="1"/>
+ <ClassDef glyph="cid63145" class="1"/>
+ <ClassDef glyph="cid63146" class="1"/>
+ <ClassDef glyph="cid63147" class="1"/>
Expand Down Expand Up @@ -806,6 +809,8 @@
+ <ChainContextPos index="0" Format="3">
+ <!-- BacktrackGlyphCount=1 -->
+ <BacktrackCoverage index="0">
+ <Glyph value="cid00009"/>
+ <Glyph value="cid00060"/>
+ <Glyph value="cid01396"/>
+ <Glyph value="cid01404"/>
+ <Glyph value="cid01406"/>
Expand All @@ -824,6 +829,7 @@
+ <Glyph value="cid59105"/>
+ <Glyph value="cid59137"/>
+ <Glyph value="cid59140"/>
+ <Glyph value="cid59143"/>
+ <Glyph value="cid63145"/>
+ <Glyph value="cid63146"/>
+ <Glyph value="cid63148"/>
Expand Down
6 changes: 6 additions & 0 deletions references/NotoSansCJK-Bold.ttc-1.G_P_O_S_.ttx.diff
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,8 @@
+ <ClassDef1>
+ </ClassDef1>
+ <ClassDef2>
+ <ClassDef glyph="cid00010" class="1"/>
+ <ClassDef glyph="cid00062" class="1"/>
+ <ClassDef glyph="cid01396" class="1"/>
+ <ClassDef glyph="cid01397" class="1"/>
+ <ClassDef glyph="cid01398" class="1"/>
Expand Down Expand Up @@ -747,6 +749,7 @@
+ <ClassDef glyph="cid59139" class="1"/>
+ <ClassDef glyph="cid59140" class="1"/>
+ <ClassDef glyph="cid59141" class="1"/>
+ <ClassDef glyph="cid59144" class="1"/>
+ <ClassDef glyph="cid63145" class="1"/>
+ <ClassDef glyph="cid63146" class="1"/>
+ <ClassDef glyph="cid63147" class="1"/>
Expand Down Expand Up @@ -806,6 +809,8 @@
+ <ChainContextPos index="0" Format="3">
+ <!-- BacktrackGlyphCount=1 -->
+ <BacktrackCoverage index="0">
+ <Glyph value="cid00009"/>
+ <Glyph value="cid00060"/>
+ <Glyph value="cid01396"/>
+ <Glyph value="cid01404"/>
+ <Glyph value="cid01406"/>
Expand All @@ -824,6 +829,7 @@
+ <Glyph value="cid59105"/>
+ <Glyph value="cid59137"/>
+ <Glyph value="cid59140"/>
+ <Glyph value="cid59143"/>
+ <Glyph value="cid63145"/>
+ <Glyph value="cid63146"/>
+ <Glyph value="cid63148"/>
Expand Down
6 changes: 6 additions & 0 deletions references/NotoSansCJK-Bold.ttc-2.G_P_O_S_.ttx.diff
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,8 @@
+ <ClassDef1>
+ </ClassDef1>
+ <ClassDef2>
+ <ClassDef glyph="cid00010" class="1"/>
+ <ClassDef glyph="cid00062" class="1"/>
+ <ClassDef glyph="cid01396" class="1"/>
+ <ClassDef glyph="cid01397" class="1"/>
+ <ClassDef glyph="cid01398" class="1"/>
Expand Down Expand Up @@ -747,6 +749,7 @@
+ <ClassDef glyph="cid59139" class="1"/>
+ <ClassDef glyph="cid59140" class="1"/>
+ <ClassDef glyph="cid59141" class="1"/>
+ <ClassDef glyph="cid59144" class="1"/>
+ <ClassDef glyph="cid63145" class="1"/>
+ <ClassDef glyph="cid63146" class="1"/>
+ <ClassDef glyph="cid63147" class="1"/>
Expand Down Expand Up @@ -806,6 +809,8 @@
+ <ChainContextPos index="0" Format="3">
+ <!-- BacktrackGlyphCount=1 -->
+ <BacktrackCoverage index="0">
+ <Glyph value="cid00009"/>
+ <Glyph value="cid00060"/>
+ <Glyph value="cid01396"/>
+ <Glyph value="cid01404"/>
+ <Glyph value="cid01406"/>
Expand All @@ -824,6 +829,7 @@
+ <Glyph value="cid59105"/>
+ <Glyph value="cid59137"/>
+ <Glyph value="cid59140"/>
+ <Glyph value="cid59143"/>
+ <Glyph value="cid63145"/>
+ <Glyph value="cid63146"/>
+ <Glyph value="cid63148"/>
Expand Down
6 changes: 6 additions & 0 deletions references/NotoSansCJK-Bold.ttc-3.G_P_O_S_.ttx.diff
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,8 @@
+ <ClassDef1>
+ </ClassDef1>
+ <ClassDef2>
+ <ClassDef glyph="cid00010" class="1"/>
+ <ClassDef glyph="cid00062" class="1"/>
+ <ClassDef glyph="cid01396" class="1"/>
+ <ClassDef glyph="cid01397" class="1"/>
+ <ClassDef glyph="cid01398" class="1"/>
Expand Down Expand Up @@ -747,6 +749,7 @@
+ <ClassDef glyph="cid59139" class="1"/>
+ <ClassDef glyph="cid59140" class="1"/>
+ <ClassDef glyph="cid59141" class="1"/>
+ <ClassDef glyph="cid59144" class="1"/>
+ <ClassDef glyph="cid63145" class="1"/>
+ <ClassDef glyph="cid63146" class="1"/>
+ <ClassDef glyph="cid63147" class="1"/>
Expand Down Expand Up @@ -806,6 +809,8 @@
+ <ChainContextPos index="0" Format="3">
+ <!-- BacktrackGlyphCount=1 -->
+ <BacktrackCoverage index="0">
+ <Glyph value="cid00009"/>
+ <Glyph value="cid00060"/>
+ <Glyph value="cid01396"/>
+ <Glyph value="cid01404"/>
+ <Glyph value="cid01406"/>
Expand All @@ -824,6 +829,7 @@
+ <Glyph value="cid59105"/>
+ <Glyph value="cid59137"/>
+ <Glyph value="cid59140"/>
+ <Glyph value="cid59143"/>
+ <Glyph value="cid63145"/>
+ <Glyph value="cid63146"/>
+ <Glyph value="cid63148"/>
Expand Down
Loading

0 comments on commit 70f92ee

Please sign in to comment.