Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix integer types for font metrics in PyGlyph class #7781

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

Merged
merged 1 commit into from
Jan 11, 2017

Conversation

AdamWill
Copy link
Contributor

The PyGlyph class defined in the freetype wrapper code pulls
in some font metric values from freetype when initialized. All
these values have type FT_Pos in freetype, which is a signed
long, but in the PyMemberDef structure used to store those
values in the Python class, their types were set to T_INT -
signed int. We should set them to T_LONG instead. This fixes
several hundred test suite errors on big-endian arches.

The PyGlyph class defined in the freetype wrapper code pulls
in some font metric values from freetype when initialized. All
these values have type FT_Pos in freetype, which is a signed
long, but in the PyMemberDef structure used to store those
values in the Python class, their types were set to T_INT -
signed int. We should set them to T_LONG instead. This fixes
several hundred test suite errors on big-endian arches.
@AdamWill
Copy link
Contributor Author

@mdboom (original author)

Copy link
Member

@QuLogic QuLogic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're not even an abstract FT_Pos; the PyGlyph struct defines them as long directly!

@AdamWill
Copy link
Contributor Author

Oh, I was just going by the API reference, which says FT_Pos:

https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Glyph_Metrics

@QuLogic
Copy link
Member

QuLogic commented Jan 10, 2017

It appears that FT_Bbox is composed of FT_Pos, which means that this line is probably wrong, too.

@QuLogic
Copy link
Member

QuLogic commented Jan 10, 2017

the API reference, which says FT_Pos:

Yes, but the lines you've changed are about PyGlyph, not FT_Glyph; it is a bug, just a slightly different one from the original explanation.

@AdamWill
Copy link
Contributor Author

sounds plausible! could account for some of the remaining errors. I was gonna take a look at 'em tomorrow.

@AdamWill
Copy link
Contributor Author

AdamWill commented Jan 10, 2017

well, I think if I'm following the code right, we're dealing with TruetypeFonts._get_info here, it's the Bunch called metrics defined there whose values are ultimately producing the divide-by-zero. Those metrics come from glyph, which we get from font.load_char, so now we're back in good ol' PyFT2Font. PyFT2Font.load_char calls load_char from the C++ code, which calls freetype FT_Load_Char, then creates a new PyGlyph instance using the result of a self->x->get_face() call as the face arg. get_face is defined in ft2font.h, thus:

FT_Face &get_face()

...which means it returns an FT_Face, right? The PyGlyph init stuff then uses values from face->glyph for all the attributes in question. Per https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec , that's an FT_GlyphSlot, and per https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_GlyphSlotRec , face->glyph->metrics (where most of the values come from) is a FT_Glyph_Metrics struct...which is the one whose values are FT_Pos types. face->glyph->linearHoriAdvance (the one value that's not pulled from metrics) is defined as type FT_Fixed, which is also a signed long.

Did I get anything wrong? :)

edit: ahhh, but I see what you mean: up in the PyGlyph struct typedef, the values are all defined as longs. I missed that PyGlyph_new is just initializing the values in that struct from the freetype values, then the PyMemberDef is reading them from the PyGlyph struct. Sorry, I'm still working through this C/Python interface stuff, it's all new to me (also I don't really know C, but don't tell anyone). Tum ti tum. It was the right patch anyway, though! So yay for that.

@QuLogic
Copy link
Member

QuLogic commented Jan 10, 2017

This is correct, but you've gone just a bit too deep. Assigning anything to the members of PyGlyph is fine, because both it and any of the FT_* structs all use longs (effectively).

The problem is solely within the PyMemberDef which you've corrected because that's the point where things are passed around as pointers to the wrong type. Or to be more exact, that's the point where the things are defined as offset+size in the struct and somewhere deep in Python is where things go wrong as it tries to use that incorrect definition.

I think I may have found a couple more incorrect pointer types; if you don't mind, I can push them to this PR directly.

@AdamWill
Copy link
Contributor Author

AdamWill commented Jan 10, 2017

I have a branch with several more myself:

AdamWill@61f256b

how does that compare to yours?

@QuLogic
Copy link
Member

QuLogic commented Jan 10, 2017

Oh, you've got a pretty good head start there; I'll leave you to it.

@AdamWill
Copy link
Contributor Author

That's all the ones I saw, I think. I guess I'll send that as a separate PR, and you can add any others you've spotted to it...

@codecov-io
Copy link

Current coverage is 62.12% (diff: 100%)

Merging #7781 into master will not change coverage

@@             master      #7781   diff @@
==========================================
  Files           174        174          
  Lines         56028      56028          
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
  Hits          34805      34805          
  Misses        21223      21223          
  Partials          0          0          

Powered by Codecov. Last update 109251f...bf970bd

@dopplershift dopplershift added this to the 2.0 (style change major release) milestone Jan 10, 2017
@AdamWill
Copy link
Contributor Author

On the topic of when this was broken, similarly to #7791 , this was changed in ba40160 , "Remove use of PyCXX in core C++ extensions", which has been around since (I think) 1.5.0. Again, I can't say for 100% sure if the old code worked, but it was different, and I think more likely to have worked:

Glyph* o = obj.getCxxObject();

o->glyphInd = ind;
FT_BBox bbox;
FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_subpixels, &bbox);

o->setattro("width",        Py::Int(face->glyph->metrics.width / hinting_factor));
o->setattro("height",       Py::Int(face->glyph->metrics.height));
o->setattro("horiBearingX", Py::Int(face->glyph->metrics.horiBearingX / hinting_factor));
o->setattro("horiBearingY", Py::Int(face->glyph->metrics.horiBearingY));
o->setattro("horiAdvance",  Py::Int(face->glyph->metrics.horiAdvance));
o->setattro("linearHoriAdvance",  Py::Int(face->glyph->linearHoriAdvance / hinting_factor));
o->setattro("vertBearingX", Py::Int(face->glyph->metrics.vertBearingX));

o->setattro("vertBearingY", Py::Int(face->glyph->metrics.vertBearingY));
o->setattro("vertAdvance",  Py::Int(face->glyph->metrics.vertAdvance));

@mdboom
Copy link
Member

mdboom commented Jan 11, 2017

👍

@mdboom mdboom merged commit 4b363c1 into matplotlib:master Jan 11, 2017
@mdboom
Copy link
Member

mdboom commented Jan 11, 2017

Backported to v2.x as 50237bd

mdboom added a commit that referenced this pull request Jan 11, 2017
Fix integer types for font metrics in PyGlyph class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants