Robmaister / SharpFont

Cross-platform FreeType bindings for .NET - Need maintainer
Other
286 stars 104 forks source link

FT_Outline_Embolden failed with Invalid_Argument exception for some fonts #139

Open mkalex777 opened 2 years ago

mkalex777 commented 2 years ago

I catch a strange issue with custom font (Ubuntu-B.ttf with merged other fonts for different codepages). It worked well until I'm try to render some specific glyph (unicode 0x2003 which is actually is not a symbol, but a space).

By default font is too thin, so I added embolden call. And text looks good.

Here is my code which fails on attempt to render that specific glyph:

        private void LoadChar(Library library, Face face, char code, int fontSize)
        {
            face.SelectCharmap(Encoding.Unicode);
            var index = face.GetCharIndex((uint)code);

            // load glyph image into the slot (erase previous one)
            face.LoadGlyph((uint)index, LoadFlags.ForceAutohint, LoadTarget.Normal);

            this.AdvanceX = (float)face.Glyph.LinearHorizontalAdvance;
            this.AdvanceY = (float)face.Glyph.Metrics.VerticalAdvance;

            face.Glyph.Outline.Embolden(0.7);  // <-- here is a problem

            // convert to an anti-aliased bitmap
            face.Glyph.RenderGlyph(RenderMode.Normal);

            //Account for freetype spacing rules
            var size = (int)(face.Glyph.LinearVerticalAdvance.ToSingle() + 0.5f);
            var offx = face.Glyph.BitmapLeft;
            var offy = (int)(size - face.Glyph.BitmapTop - size / 6);

            LoadTexture(this.ListId, this.TextureId, face.Glyph.Bitmap, offx, offy);
        }

When I trying to render glyph for unicode character 0x2003, I got InvalidArgument exception for the call face.Glyph.Outline.Embolden(0.7).

I inspected the source code and found that this issue happens in freetype.dll, see ftoutln.c, function FT_Outline_EmboldenXY.

Here is problematic source code:

    orientation = FT_Outline_Get_Orientation( outline );
    if ( orientation == FT_ORIENTATION_NONE )
    {
      if ( outline->n_contours )
        return FT_THROW( Invalid_Argument );
      else
        return FT_Err_Ok;
    }

it turns that problematic glyph in my font has outline->n_contours=1 and orientation FT_ORIENTATION_NONE, so it raise exception.

I'm not sure what is going wrong here. Can you please help?

At the moment I added this kludge as a workaround to bypass this condition:

if (face.Glyph.Outline.GetOrientation() != Orientation.None || face.Glyph.Outline.Contours.Length == 0)
    face.Glyph.Outline.Embolden(0.7);

It works, but I feel that I didn't realize some important detail, so probably there is possible better solution.

SFML library which also uses freetype library works ok with the same font. I'm not sure if it has Embolden call, but it shows the same emboldened glyphs as my code above.

I'm using freetype 2.9.1 with your x64 patch.

I understand that this issue is related to freetype library, but I didn't found the option to open issue for freetype library, because it is hosted on freetype.org with no issue tracking. I'm sure you have good experience with freetype library, so I'm added my question here on github. Thanks

HinTak commented 2 years ago

FreeType has recently moved to gitlab from gnu savannah, I think. Issues used to be filed at gnu savannah - that's older than github by about 20 years! github is itself quite young, and much younger than freetype, by 20 years. github is less than 10 years old while freetype is close to 30. Now freetype is at gitlab - since a year or two ago? Alternatively bugs and discussions about actual freetype source code, as you did, happens at "freetype-devel nongnu.org" mailing list.

I think n_contours =! 0 and FT_ORIENTATION_NONE is invalid - for embolden to work, one needs to be able to tell what's "inside" and what's "outside", to move the contours in the outside direction. So it needs to be anything except _NONE if there is any contours at all. (no contours is fine - nothing to embolden, hence != 0, such as the space glyph).

ie. that glyph in that font is invalid as far as emboldening is concerned.