Files
klammertext/sks/font/font.py
T

121 lines
5.0 KiB
Python
Raw Normal View History

import re
import klammer_base
class Subsuper(klammer_base.Klammer_base):
def __init__(self, K, position):
super().__init__(K)
self.position = position
"""
print("Subsuper:", self.args)
parts = self.args.strip().split()
if len(parts) != 2:
raise Exception(f"Two arguments required, but argument is: {self.args.strip()}")
self.base, self.script = parts
"""
def html(self):
return f"{self.base}<{self.position}>{self.script}</sub>"
def tex(self):
if self.position == "sub":
return f"${self.base}_{self.script}$"
else:
return f"${self.base}^{self.script}$"
# The typeface-declaration marker. A klammer cannot declare a typeface
# itself: in html the @font-face must be in the page's css and the files
# localized into <output>/fonts/, and in tex the \newfontfamily must be in
# the preamble -- both are @document's, and @document runs AFTER the
# klammers it contains (application is post-order). So @typeface leaves
# this marker where the typeface is needed, and @document collects the
# markers, resolves and localizes each typeface, declares it, and replaces
# the marker with whatever inline switch the target needs (a font-switch
# command for tex; for html the marker sits IN the span's font-family value
# and becomes the family name the store resolved the typeface to, which
# is what the localized css declares -- the name as WRITTEN may be the
# store's directory name, "noto-sans-egyptian-hieroglyphs", and a span
# carrying that matched no @font-face until 2026-09-12). Same shape as
# the __CAPTION__ markers.
#
# SYNC: typeface_marker_rgx in sks/document/document_class.h -- a C++/Python
# pair, so the constant cannot be single-sourced the way a .k/.py pair can
# (TODO #47); change both or neither.
def typeface_marker(name, scale):
return f"__TYPEFACE__{name}__{scale}__"
class Typeface(klammer_base.Klammer_base):
"""A temporary typeface change (@typeface). See sks/font/font.k."""
def __init__(self, K):
super().__init__(K)
def html(self):
# font-size-adjust is switched OFF for the span: the document
# normalizes families to a common x-height (font.css), which is
# meaningless for a script whose glyphs have no x-height at all --
# hieroglyphs, cuneiform -- and would resize them unpredictably.
# The family name is quoted -- an unquoted digit-initial word
# ("Source Sans 3") is invalid CSS -- with SINGLE quotes, because
# this sits inside a double-quoted html attribute. What is quoted
# here is the MARKER: @document replaces it with the resolved
# family name (see the marker note above).
style = "', serif; font-size-adjust: none"
if float(self.scale) != 1.0:
style += f"; font-size: {float(self.scale)}em"
# The STYLE is markup, so its typographically active characters are
# hidden: the html target's transforms turn a single quote into a
# curly one, which broke the css font-family value. The MARKER is
# not hidden: a hyphen in the typeface name would become a KTESC
# sequence, which on the :files path is still there when @document
# looks for the marker. The TEXT is writer content and is
# deliberately left alone -- its quotes and dashes should be
# transformed.
hide = klammer_base.hide_typographic
return (f'<span style="{hide("font-family: " + chr(39))}'
+ typeface_marker(self.name, self.scale) + hide(style) + '">'
+ f'{self.text}</span>')
def tex(self):
# The marker becomes the font-switch command; the group is what
# makes the change temporary (the retired @font emitted a bare
# \setmainfont, which changed the font for the rest of the
# document).
return "{" + typeface_marker(self.name, self.scale) + " " + self.text + "}"
def txt(self):
# A typeface cannot be expressed in plain text. Declared in the
# .k description, so this is documented behaviour rather than a
# silent per-target divergence.
return self.text
def html_fontify(text, font_symbol, font_size):
cls = {"r" : "",
"i" :"ritalic",
"b" : "bold",
"s" : "sansserif",
"t" : "monospace",
"c" : "code"}[font_symbol]
result = text
if cls:
if font_symbol == "c":
result = re.sub(" ", "&#160;", result)
cls = f'class="{cls}"'
sty = ""
if font_size != 1:
sty = f'style="font-size: {float(font_size) * 100}%"'
attr = (cls + " " + sty).strip()
if attr:
result = f'<span {attr}>{result}</span>'
return result
def tex_fontify(text, font_symbol, font_size):
command = {"r" : "\\rmfamily",
"i" :"\\it",
"b" : "\\bfseries",
"s" : "\\sffamily",
"t" : "\\ttfamily",
"c" : "\\ttfamily"}[font_symbol]
result = f"{{{command}\\scalefont{{{font_size}}}{{{text}}}}}"
return result