Bug 158573

Summary: <Tradition Chinese Font are different.
Product: [openSUSE] SUSE Linux 10.1 Reporter: Wayne Lu <waynel>
Component: TranslationsAssignee: Mike Fabian <mfabian>
Status: RESOLVED FIXED QA Contact: Karl Eichwalder <ke>
Severity: Normal    
Priority: P5 - None CC: david, tiwai, wl
Version: Beta 6   
Target Milestone: ---   
Hardware: x86   
OS: SuSE Linux 10.1   
Whiteboard:
Found By: Other Services Priority:
Business Priority: Blocker: ---
Marketing QA Status: --- IT Deployment: ---
Attachments: Message11
Message13
Message9
FZSongTi without embolden.
FZSongTi with embolden.
sazanami-mincho.png
The patch to fix (hopefully) this issue.
Patch against freetype 2.2.1
glyph uni4E31 of font sazanami-mincho.ttf
Zoom in view of the most left points.
A glyph with self-intersection contour in FZSongTi.ttf
Zoom in view of the self-intersection area.
A glyph in FZKaiTi.ttf with contours in arbitrary orientations.
A glyph in UnBatang.ttf with contours in arbitrary orientations.
A patch to implement a new algorithm using nonzero winding rule.
Patch to add Embolden benchmark into ftbench.

Description Wayne Lu 2006-03-16 09:53:12 UTC
Step
1The POP Screen display message.

Expect 
The Font are the same.

Actual
The Font not the same( light ,Weight...)
Comment 1 Wayne Lu 2006-03-16 09:55:37 UTC
Created attachment 73283 [details]
Message11
Comment 2 Wayne Lu 2006-03-16 09:58:16 UTC
Created attachment 73284 [details]
Message13

<the Problem for " ? ">
Comment 3 Wayne Lu 2006-03-16 12:32:15 UTC
Created attachment 73306 [details]
Message9

<the Problem for " ? ">
Comment 4 Zhe Su 2006-03-17 01:05:32 UTC
Seems that it's a bug of freetype embolden function. I can reproduce this issue with FZSongTi as well.
Comment 5 Zhe Su 2006-03-17 01:06:22 UTC
Created attachment 73444 [details]
FZSongTi without embolden.
Comment 6 Zhe Su 2006-03-17 01:08:12 UTC
Created attachment 73445 [details]
FZSongTi with embolden.

Comparing to the previous screenshot, you may see that there are two chars have similiar issue.
The font is not changed.
Comment 7 Zhe Su 2006-03-17 01:16:33 UTC
The issue is not always reproduceable, even for the same font size.
Comment 8 Zhe Su 2006-03-17 08:36:43 UTC
Ok. I found the issue.

See the source code of FT_Outline_Embolden():

  FT_EXPORT_DEF( FT_Error )
  FT_Outline_Embolden( FT_Outline*  outline,
                       FT_Pos       strength )
  {
    FT_Vector*  points;
    FT_Vector   v_prev, v_first, v_next, v_cur;
    FT_Angle    rotate, angle_in, angle_out;
    FT_Int      c, n, first;


    if ( !outline )
      return FT_Err_Invalid_Argument;

    if ( strength == 0 )
      return FT_Err_Ok;

    if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_TRUETYPE )
      rotate = -FT_ANGLE_PI2;
    else
      rotate = FT_ANGLE_PI2;

    points = outline->points;

    first = 0;
    for ( c = 0; c < outline->n_contours; c++ )
    {
      int  last = outline->contours[c];


It calls FT_Outline_Get_Orientation() to get correct rotation angle of embolden vector. But sometimes, FT_Outline_Get_Orientation() returns FT_ORIENTATION_POSTSCRIPT instead of FT_ORIENTATION_TRUETYPE, it's of course wrong for TrueType font.

I'll investigate FT_Outline_Get_Orientation() to see what's wrong in it.
Comment 9 Mike Fabian 2006-03-17 11:08:11 UTC
Created attachment 73674 [details]
sazanami-mincho.png

It is also reproducible with "Sazanami Mincho" (??????).
Comment 10 Zhe Su 2006-03-17 17:12:16 UTC
Created attachment 73726 [details]
The patch to fix (hopefully) this issue.

This patch should fix the most cases of this issue. Please try, if it's ok, then please apply.
Comment 11 Zhe Su 2006-03-20 04:51:28 UTC
You can find the testing package with this patch in /work/built/mbuild/magellan-zsu-46/i386/

patch for bug #159166 is also included.

Please try the package, if it's ok then I'll commit the package.
Comment 12 Mike Fabian 2006-03-20 11:05:22 UTC
Apparently it doesn't fix the issue for "Sazanami Gothic", I can
still reproduce the problem seen in the screen shot in comment #9.
Comment 13 Zhe Su 2006-03-20 15:40:21 UTC
It's so strange that I can't reproduce this issue with ftview, though it's visible in gucharmap and other gtk applications.
Comment 14 Zhe Su 2006-03-20 16:35:21 UTC
Ok. I know the reason.
The issue shows in comment #9 is caused by hinting. The patch in #10 is correct. But because embolden is down after hinting, after applying hinting, the micro orientation (near the most left points) of some glyphs will be inverted strangely. Because FT_Outline_Get_Orientation() determines the orientation by comparing the angles between the most left point and its previous and next points, when there are two or more points with same minimum x coordinator, and their y coordinators are swapped strangely by hinting, wrong result will be returned.

I just submit the patch with this patch, because it fixes most of the issues.
I'll continue to investigate this strange issue to find out a way.
Comment 15 Mike Fabian 2006-03-20 16:58:32 UTC
OK, thank you for your great investigation.
Comment 16 Werner Lemberg 2006-03-21 16:11:06 UTC
It's a bad idea IMHO to hint glyphs before emboldening.  It should be done
afterwards (using the autohinter) -- something to discuss on the freetype-devel
mailing list...

For the moment I suggest to disable hinting while embolding.
Comment 17 Mike Fabian 2006-03-21 16:19:27 UTC
Werner> For the moment I suggest to disable hinting while embolding.

How can this be done?
Comment 18 Werner Lemberg 2006-03-21 16:32:52 UTC
Hehe, it can't :-)  As I've said, this is something to discuss on
freetype-devel...
Comment 19 Werner Lemberg 2006-03-21 21:36:52 UTC
I've applied the suggested patch, thanks.
Comment 20 Zhe Su 2006-03-31 09:51:08 UTC
A new fontconfig package has been submitted into STABLE, which turns off hinting when do embolden. It should workaround all rest issues.

Closing this bug as fixed.
Comment 21 Mike Fabian 2006-03-31 10:26:06 UTC
Good idea to do that in the fontconfig setup. Thank you!

Comment 22 Mike Fabian 2006-06-22 14:17:53 UTC
I have just verified that the problem doesn't occur anymore with the
unpatched freetype 2.2.1, i.e. this bug fix has been properly included
upstream. Thank you!

Comment 23 Werner Lemberg 2006-10-12 05:19:48 UTC
In

  http://lists.nongnu.org/archive/html/freetype/2006-10/msg00000.html

we got a report that the patch fails if a contour consists of only
off-line points.  The mentioned font (VL-Gothic-Regular) contains a couple
of such glyphs, most notably `zero', `sigma', and `omega'.  The latter
two have weird overlapping contours so it's probably not important to fix.
Anyway, the `zero' shape is a full valid glyph shape, so we have to fix
it...
Comment 24 Zhe Su 2006-10-13 06:24:29 UTC
I improved the algorithm to take into account implicit on-curve points. The  VL-Gothic-Regular font issue should be fixed by this enhancement. However I found that it still can't solve all the issues, for example glyph uni4e31, uni4e38 in font sazanami-mincho.ttf.

It seems that we need a totally different algorithm to solve this issue completely.
Comment 25 Zhe Su 2006-10-13 06:26:23 UTC
Created attachment 101395 [details]
Patch against freetype 2.2.1

It's a patch against freetype 2.2.1, which improves the orientation detection algorithm to take into account implicit on-curve points.
Comment 26 Zhe Su 2006-10-13 06:34:29 UTC
Created attachment 101396 [details]
glyph uni4E31 of font sazanami-mincho.ttf

This glyph can't be handle by the new algorithm. There are many similar glyphs in this font which have similar issues.
Comment 27 Zhe Su 2006-10-13 06:41:38 UTC
Created attachment 101397 [details]
Zoom in view of the most left points.

You can see that, because the new algorithm will only take on-curve (both explicit and implicit) points into account, the most left (xmin) point is 26, the previous point is 24, the next point is 28. But the angle 24-26-28 is inverted comparing to the contour orientation, then we will get wrong result.

If we take off-curve points into account, this issue will be avoided, but we will get wrong result on many other glyphs.
Comment 28 Werner Lemberg 2006-10-13 14:00:56 UTC
Regarding a new algorithm, perhaps the method I've implemented in
mf2pt1 might help (you can get version 2.2 from CTAN; have a look
at function `is_clockwise' in file mf2pt1.mp).  It was necessary
to add it because the built-in code of MetaPost was faulty then.

Here a description:

. Find a point P on the path which has a non-zero direction.

. Construct a ray of ``infinite'' length, starting in the
  vicinity of P which intersects the path at this point.

. Use the MetaPost function `intersectiontimes' to find the
  intersection.  If the direction of the path at this point
  is (near) zero, or if we have a grazing intersection,
  get a new ray.

. Shorten the ray so that it starts right after the
  intersection.  Repeat the previous step until no
  intersection is found.  Then go back to the last
  intersection and compare the path's direction with the
  direction of the ray.  According to the `nonzero winding
  number' rule we have found a clockwise oriented path it
  it crosses the ray from left to right.

This method completely avoids any problems with the geometry of
Bézier curves.  If problems arise, a different ray is tried.
Since it isn't necessary to analyze the whole path it runs quite fast
in spite of using `intersectiontimes' which is a quite slow.
Comment 29 Zhe Su 2006-10-13 14:33:39 UTC
Sorry that I can't fully understand this algorithm and the is_clockwise code. Is there any article and diagram describing this algorithm?

According to my understanding, I have a question regarding this algorithm. Is it required to calculate the intersection points between the ray and contour? Because the contour contains not only straight lines but also Bezier curves, is it simple enough to calculate the intersection between ray and Bezier curves?

The current algorithm is correct for polygons with only straight lines.
Comment 30 Zhe Su 2006-10-13 14:50:19 UTC
I have new question: For truetype fonts, is it possible that the outer contour of a glyph has POSTSCRIPT orientation instead of TRUETYPE orientation? Why do we need to check the orientation of the contour instead of just assume that it's always TRUETYPE orientation?
Comment 31 Zhe Su 2006-10-13 16:19:54 UTC
Hmm, very interesting that sazanami-mincho.ttf is a font with POSTSCRIPT orientation instead of TRUETYPE orientation.
Comment 32 Werner Lemberg 2006-10-13 22:49:58 UTC
For an explanation of the nonzero winding rule, see for example

  http://www.asppdf.com/manual_04.html

(or look up something similar in the PS Reference Manual).

The above mentioned algorithm can be enormously simplified because font
contours are much more well-behaved than arbitrary Bézier curves; most
notably, they don't contain self-intersections or cusps.  Under these
assumptions it is sufficient to determine the orientation of the
`envelope' determined by the Bézier control points, this is, to find
the orientation of the polygon spanned up by the on and off line
points.  For simplicity, only consider horizontal rays -- the above
algorithm then gets reduced to comparing x and y values (probably
adding a vertical offset to avoid rays which pass through one of the
points).

A remark: Cusps and self-intersections (`loops') can only happen
for third-order curves.  It is also possible to construct third-order
Bézier curves which looks quite normal, but where the connection lines
between the control points do cross. I suggest that we ignore such
cases also.
Comment 33 Zhe Su 2006-10-14 15:33:41 UTC
Now I understand the algorithm. But I found that some fonts (especially CJK fonts) do have quite a few glyphs with self-intersections. It's possible to get false detection if the ray is inappropriate.
Comment 34 Zhe Su 2006-10-14 15:34:51 UTC
Created attachment 101492 [details]
A glyph with self-intersection contour in FZSongTi.ttf

A sample glyph with self-intersection.
Comment 35 Zhe Su 2006-10-14 15:35:51 UTC
Created attachment 101493 [details]
Zoom in view of the self-intersection area.

The self-intersection is obvious.
Comment 36 Werner Lemberg 2006-10-14 19:22:11 UTC
Well, the self-intersection in this glyph is clearly a bug in the font.
On the other hand, it's quite unlikely that a ray hits this small part
of the outline.  We might implement an additional `paranoid' mode which
uses two rays: If the results differ, a third ray finally decides the
orientation.
Comment 37 David Turner 2006-10-18 08:42:49 UTC
Hello everyone,

I'm pretty new here, but I'd like to make a few statements.

First of all, the TrueType specification clearly wasn't designed with easy emboldening in mind, since it explicitely allows:

- two contours to intersect (note: this is note the same than a single self-intersecting contour). See 

  http://developer.apple.com/textfonts/TTRefMan/RM01/Chap1.html#intersecting

- contours in arbitrary drawing directions, see the graphics in:

  http://developer.apple.com/textfonts/TTRefMan/RM02/Chap2.html#distinguishing

  note that even if all contours are oriented uniformly, you could have a reversal of the drawing direction in a composite glyph using, for example a mirroring transform (i've seen this implemented in a font to generate the reversed cyrillic R, for example)


this is a lot less strict than the Postscript font design rules, which allow the emboldening algorithm to work flawlessly for any compliant font.

Generally speaking, the current algorithm tries to do its job very quickly by simply "displacing" the glyph outline towards the "exterior" direction. It is quick because it doesn't try to compute new points in the outline, or see if there are intersections. And it works well in a *lot* of cases :-)

it simply assumes that the glyph is wel-formed, computes its orientation, then apply the relevant displacements to all points.

A general-purpose emboldening algorithm is something *very* different that must be capable of computing all intersections in the glyph (not only in each contour), and tesselate the result appropriately when these are found. This involves a lot of complex mathematics, with very subtle and hard-to-fix rounding issues; while it is possible to implement something like this, its performance will most certainly suck (witness the performance of the Cairo tesselators, where the original one is a drag and the new "optimized" one only provides massive speed-ups in complex/theorical cases, while being slower in practical ones at the moment; all this means is that writing an efficient tesselator is *hard* stuff). And consider that what we need here is considerably more difficult than what is used in Cairo, since we need to deal with Bezier arcs, not only line segments.

in an ideal world, we should be able to quickly determine if a glyph is well-formed, and use the short-cut when this is the case. When note, we should be able to use the slow algorithm (when and if it exists).

however, I'm for a more practical approach at the moment. I'll try to submit a patch that will do the following:

- to compute the global orientation, try to compute the orientation of all 4 borders of the glyph (top/bottom/left/right)

- if they all match, return the corresponding value

- if only 3 of them match, return their value since it probably means a self-intersecting gizmo like the one in the FZSongTi.ttf

- the only alternative is where we have 2 opposite values in equal numbers (2+2), in this case, we have a problem, and do *nothing*, at least we'll have something nicer to display.

what do you think about it ? It's only a slightly refined heuristic that doesn't force us to actually compute overlaps/intersections, but I hope it should be enough for the curious cases we're seeing.

Comment 38 Zhe Su 2006-10-18 08:59:45 UTC
I'm implementing the algorithm that Werner mentioned. I'll give you result asap.

I had tried to improve the patch posted in Comment #25 to test four borders, but it seems that it still can't handle some glyphs in FZSongTi.ttf and sazanami-mincho.ttf.

However, I'm willing to test your patch to see whether it's better or not.
Comment 39 Zhe Su 2006-10-18 10:57:18 UTC
I just found that some fonts really have many contours in arbitrary drawing directions, such as UnBatang.ttf, FZKaiTi.ttf.
I believe that many other fonts may have the same issue.
So I think, besides FT_Outline_Get_Orientation, we need fix FT_Outline_Embolden as well. One possible solution is to check each contour's orientation separately in FT_Outline_Embolden, instead of checking the whole glyph's orientation. However I don't know how much performance impact will be introduced by it.

I'll try this approach and give you feedback asap.
Comment 40 Zhe Su 2006-10-18 10:59:54 UTC
Created attachment 101863 [details]
A glyph in FZKaiTi.ttf with contours in arbitrary orientations.

The left part of this glyph is clockwise while the right part is counter-clockwise.
Comment 41 Zhe Su 2006-10-18 11:00:43 UTC
Created attachment 101864 [details]
A glyph in UnBatang.ttf with contours in arbitrary orientations.
Comment 42 David Turner 2006-10-18 14:17:31 UTC
Oh my god, these fonts are so wicked !! the control polygon is even self-intersection in patch 101863, while the outline isn't. there are local extrema on bezier curves everywhere; there is no way we're going to correctly embolden them with our "quick" algorithm, even if we improve the heuristics.

besides, checking the orientation of each contour is not going to help a lot, because you'll still need to decide wether the contour is an interior or exterior one, which quickly becomes non trivial if you're not on the glyph's bounding box.

we're either going to some *serious* code to deal with these or think differently about the problem (e.g. embolden the bitmaps, instead of the vectors)
Comment 43 Zhe Su 2006-10-19 11:07:14 UTC
Created attachment 102025 [details]
A patch to implement a new algorithm using nonzero winding rule.

It's a patch to implement the algorithm mentioned in comment #28, #32 and #36.

Most of those weird glyphs can be handled correctly, except those with arbitrary contour orientations.

Please have a try.
Comment 44 Werner Lemberg 2006-10-23 11:29:07 UTC
This looks good IMHO -- definitely better than the current code.
Have you done some timings?  And can you write a ChangeLog entry so that
I can easily add it to the FreeType CVS?
Comment 45 Zhe Su 2006-10-23 12:34:48 UTC
I don't know how to do benchmark easily, do you have any suggestion? Is there any existing benchmark code that I can use?

The ChangeLog entry can be:

* Algorithm used by FT_Outline_Get_Orientation() was improved by using "Nonzero winding rule", so that most weird glyphs can be handled correctly, except those with arbitrary contour orientation. Correctness of outline embolden can be improved a lot by this improvement.
Comment 46 Zhe Su 2006-10-23 14:41:01 UTC
It seems that the performance of the new algorithm is almost same as the old one.

I patched ftbench to do the benchmark. The benchmark result of the new algorithm of FZSongTi.ttf is around 175 us/op. While the result of old algorithm around 170 us/op.

Please help test it again.
Comment 47 Zhe Su 2006-10-23 14:42:43 UTC
Created attachment 102295 [details]
Patch to add Embolden benchmark into ftbench.

Please try this patch. It's correct and helpful, please merge it into ft2demos.
Comment 48 David Turner 2006-10-23 16:00:40 UTC
Both patches are now in the FreeType CVS, thanks a lot !

- David
Comment 49 Zhe Su 2006-10-24 07:51:27 UTC
Thanks a lot.

Mike, could you please upgrade our freetype2 and ft2demos packages to the latest cvs version? Or apply these two patches?

I think the package of SLE10 should be fixed as well.
Comment 50 Mike Fabian 2006-10-27 16:56:25 UTC
freetype2 and ft2demos updated to 2.2.1.20061027 submitted to STABLE.
Comment 51 Mike Fabian 2007-03-21 15:45:04 UTC
FIXED.