Skip to content

Support scale in ttf composite glyphs #18081

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

Closed
wants to merge 7 commits into from
Closed
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
739 changes: 739 additions & 0 deletions LICENSE/LICENSE_GNU_FREEFONT

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions extern/ttconv/pprdrv_tt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,61 @@ Fixed getFixed(BYTE *s)
return val;
} /* end of getFixed() */

/*
** Get a 16 bit fixed point (2.14) number.
**
** The value range is from -2.0 to a little under 2.0. The two
** most-significant bits encode the whole part in two's-complement
** format and the remaining 14 bits encode the numerator n of the
** fraction n/16384 to be added to the whole part.
**
** https://docs.microsoft.com/en-us/typography/opentype/otspec181/otff#data-types
*/
F2DOT14 getF2DOT14(BYTE *s)
{
F2DOT14 val={0, 0};

int sign = s[0] & 0x80;
int bit = (s[0] & 0x40) >> 6;
if (sign) {
val.whole = bit-2;
} else {
val.whole = bit;
}
val.fraction = ((s[0] & 0x3f) << 8) + s[1];

return val;
}

/*
** Convert a fixed-point 2.14 number to a newly-allocated string.
** Use at most six decimals but remove trailing zeroes and possibly
** the decimal point.
*/
char* F2DOT14value(F2DOT14 f)
{
const size_t maxlen = sizeof("-1.234567");
char *value = (char*)calloc(sizeof(char), maxlen);
if (value == NULL ||
snprintf(value, maxlen, "%.6f", f.whole + (float)f.fraction/16384) < 0) {
abort();
}

char *ptr = &value[maxlen-1];
while (ptr > value && *ptr == '\0') {
ptr--;
}
while (ptr > value && *ptr == '0') {
*ptr-- = '\0';
}
if (ptr > value && *ptr == '.') {
*ptr = '\0';
}

return value;
}


/*-----------------------------------------------------------------------
** Load a TrueType font table into memory and return a pointer to it.
** The font's "file" and "offset_table" fields must be set before this
Expand Down
22 changes: 20 additions & 2 deletions extern/ttconv/pprdrv_tt2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,14 +409,17 @@ void GlyphToType3::load_char(TTFONT* font, BYTE *glyph)
} /* end of load_char() */

/*
** Emmit PostScript code for a composite character.
** Emit PostScript code for a composite character.
**
** https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description
*/
void GlyphToType3::do_composite(TTStreamWriter& stream, struct TTFONT *font, BYTE *glyph)
{
USHORT flags;
USHORT glyphIndex;
int arg1;
int arg2;
F2DOT14 mat00 = {1, 0}, mat01 = {0, 0}, mat10 = {0, 0}, mat11 = {1, 0};

/* Once around this loop for each component. */
do
Expand Down Expand Up @@ -444,14 +447,21 @@ void GlyphToType3::do_composite(TTStreamWriter& stream, struct TTFONT *font, BYT

if (flags & WE_HAVE_A_SCALE)
{
mat00 = mat11 = getF2DOT14(glyph);
glyph += 2;
}
else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
{
mat00 = getF2DOT14(glyph);
mat11 = getF2DOT14(glyph+2);
glyph += 4;
}
else if (flags & WE_HAVE_A_TWO_BY_TWO)
{
mat00 = getF2DOT14(glyph);
mat01 = getF2DOT14(glyph+2);
mat10 = getF2DOT14(glyph+4);
mat11 = getF2DOT14(glyph+6);
glyph += 8;
}
else
Expand All @@ -472,7 +482,15 @@ void GlyphToType3::do_composite(TTStreamWriter& stream, struct TTFONT *font, BYT
subglyph here. However, that doesn't seem to work with
xpdf or gs (only acrobat), so instead, this just includes
the subglyph here inline. */
stream.printf("q 1 0 0 1 %d %d cm\n", topost(arg1), topost(arg2));
char *s00 = F2DOT14value(mat00), *s01 = F2DOT14value(mat01),
*s10 = F2DOT14value(mat10), *s11 = F2DOT14value(mat11);

stream.printf("q %s %s %s %s %d %d cm\n",
s00, s01, s10, s11, topost(arg1), topost(arg2));
free(s00);
free(s01);
free(s10);
free(s11);
}
else
{
Expand Down
5 changes: 5 additions & 0 deletions extern/ttconv/truetype.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ typedef struct
unsigned short int fraction;
} Fixed;

/* A 2.14 fixed point number */
typedef Fixed F2DOT14;

/* This structure tells what we have found out about */
/* the current font. */
struct TTFONT
Expand Down Expand Up @@ -86,6 +89,8 @@ struct TTFONT
ULONG getULONG(BYTE *p);
USHORT getUSHORT(BYTE *p);
Fixed getFixed(BYTE *p);
F2DOT14 getF2DOT14(BYTE *p);
char *F2DOT14value(F2DOT14 f);

/*
** Get an funits word.
Expand Down
Binary file added lib/matplotlib/tests/FreeSerifSubset.ttf
Binary file not shown.
Binary file not shown.
15 changes: 15 additions & 0 deletions lib/matplotlib/tests/test_ttconv.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,18 @@ def test_truetype_conversion(recwarn):
font=Path(__file__).with_name("mpltest.ttf"), fontsize=80)
ax.set_xticks([])
ax.set_yticks([])


@image_comparison(["ttconv_transforms.pdf"])
def test_ttconv_transforms():
matplotlib.rcParams['pdf.fonttype'] = 3
fig, ax = plt.subplots()
kw = {'font': Path(__file__).with_name("FreeSerifSubset.ttf"),
'fontsize': 14}
# characters where Free Serif uses various scales and linear transforms
# e.g. the right paren is a reflected left paren
ax.text(.1, .1, "parens, FAX, u with two diacritics: ()℻ǘ", **kw)
ax.text(.1, .2, "double arrows LURD, single arrows LURD: ⇐⇑⇒⇓←↑→↓", **kw)
ax.text(.1, .3, "corner arrows, wreath product: ↴↵≀", **kw)
ax.set_xticks([])
ax.set_yticks([])
1 change: 1 addition & 0 deletions setupext.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ def get_package_data(self):
*_pkg_data_helper('matplotlib', 'tests/tinypages'),
'tests/cmr10.pfb',
'tests/mpltest.ttf',
'tests/FreeSerifSubset.ttf',
],
'mpl_toolkits': [
*_pkg_data_helper('mpl_toolkits', 'tests/baseline_images'),
Expand Down