Bug 9350

Summary: ATSUI fails 'make check' with image backend.
Product: cairo Reporter: Brian Ewins <Brian.Ewins>
Component: quartz font backendAssignee: Carl Worth <cworth>
Status: RESOLVED FIXED QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: normal    
Priority: high    
Version: 1.3.7   
Hardware: PowerPC   
OS: Mac OS X (All)   
Whiteboard:
i915 platform: i915 features:
Bug Depends on: 9363, 9366, 9378, 9568    
Bug Blocks:    
Attachments: This is a sample of the output of the text-rotate test
Patch to correct the text-rotate behaviour
Output of text-rotate after the patch
compute font size with _cairo_matrix_compute_scale_factor
fix the extents to use screen metrics instead of ideal metrics.
output after all the atsui patches so far. note extent boxes are tighter now.
replacement for the extents fix
measure glyphs using path bounding boxes.
shows the broken behaviour with descenders before this patch
showing fixed descender handling
Demonstrating that the 'cairo' rendering didn't regress.
Same patch, without the compile warning. oops.

Description Brian Ewins 2006-12-14 19:29:47 UTC
On OS X 10.4, PPC (nb OS list here only goes up to 10.3 in this bugzilla),
building with:
./autogen.sh --disable-xlib --enable-quartz --enable-nquartz --enable-atsui
;make check
fails 12 tests. Grepping the failures:

clip-operator-image-argb32 [0]: FAIL
clip-operator-image-argb32 [25]:        FAIL
clip-operator-image-rgb24 [0]:  FAIL
clip-operator-image-rgb24 [25]: FAIL
FAIL: clip-operator
font-matrix-translation-image-argb32 [0]:       FAIL
font-matrix-translation-image-argb32 [25]:      FAIL
font-matrix-translation-image-rgb24 [0]:        FAIL
font-matrix-translation-image-rgb24 [25]:       FAIL
FAIL: font-matrix-translation
glyph-cache-pressure-image-argb32 [0]:  FAIL
glyph-cache-pressure-image-argb32 [25]: FAIL
glyph-cache-pressure-image-rgb24 [0]:   FAIL
glyph-cache-pressure-image-rgb24 [25]:  FAIL
FAIL: glyph-cache-pressure
operator-clear-image-argb32 [0]:        FAIL
operator-clear-image-argb32 [25]:       FAIL
operator-clear-image-rgb24 [0]: FAIL
operator-clear-image-rgb24 [25]:        FAIL
FAIL: operator-clear
operator-source-image-argb32 [0]:       FAIL
operator-source-image-argb32 [25]:      FAIL
operator-source-image-rgb24 [0]:        FAIL
operator-source-image-rgb24 [25]:       FAIL
FAIL: operator-source
select-font-face-image-argb32 [0]:      FAIL
select-font-face-image-argb32 [25]:     FAIL
select-font-face-image-rgb24 [0]:       FAIL
select-font-face-image-rgb24 [25]:      FAIL
FAIL: select-font-face
show-text-current-point-image-argb32 [0]:       FAIL
show-text-current-point-image-argb32 [25]:      FAIL
show-text-current-point-image-rgb24 [0]:        FAIL
show-text-current-point-image-rgb24 [25]:       FAIL
FAIL: show-text-current-point
text-antialias-gray-image-argb32 [0]:   FAIL
text-antialias-gray-image-argb32 [25]:  FAIL
text-antialias-gray-image-rgb24 [0]:    FAIL
text-antialias-gray-image-rgb24 [25]:   FAIL
FAIL: text-antialias-gray
text-antialias-none-image-argb32 [0]:   FAIL
text-antialias-none-image-argb32 [25]:  FAIL
text-antialias-none-image-rgb24 [0]:    FAIL
text-antialias-none-image-rgb24 [25]:   FAIL
FAIL: text-antialias-none
text-antialias-subpixel-image-argb32 [0]:       FAIL
text-antialias-subpixel-image-argb32 [25]:      FAIL
text-antialias-subpixel-image-rgb24 [0]:        FAIL
text-antialias-subpixel-image-rgb24 [25]:       FAIL
FAIL: text-antialias-subpixel
text-pattern-image-argb32 [0]:  FAIL
text-pattern-image-argb32 [25]: FAIL
text-pattern-image-rgb24 [0]:   FAIL
text-pattern-image-rgb24 [25]:  FAIL
FAIL: text-pattern
unbounded-operator-image-argb32 [0]:    FAIL
unbounded-operator-image-argb32 [25]:   FAIL
unbounded-operator-image-rgb24 [0]:     FAIL
unbounded-operator-image-rgb24 [25]:    FAIL
FAIL: unbounded-operator

partial fix follows.
Comment 1 Brian Ewins 2006-12-14 19:31:53 UTC
Created attachment 8117 [details]
This is a sample of the output of the text-rotate test

The text-rotate test shows nearly-correct behaviour in the top left, but
incorrect behaviour in the bottom right.
Comment 2 Brian Ewins 2006-12-14 19:37:55 UTC
Created attachment 8118 [details] [review]
Patch to correct the text-rotate behaviour

Investigating the problem I found that when calculating the height of the font
after scaling, instead of taking the magnitude of a scaled unit vector, the
code used the y-component of a scaled sqrt(2) magnitude vector (ie (1,1)). I've
made the obvious fix in this patch, however taking the font size from the ctm
is dangerous at best; if the transform stretches the font it will give the
correct answer. So later the code should be changed to pass in the desired font
size.
Comment 3 Brian Ewins 2006-12-14 19:48:10 UTC
Created attachment 8119 [details]
Output of text-rotate after the patch

This output is still incorrect. The rectangle drawn, taken from the extents of
the drawn glyphs, is too large. What is done to produce this seems ok; the only
issue I could find is the use of ATSGlyphIdealMetrics instead of
ATSGlyphScreenMetrics. The Ideal metrics don't include the height of the glyph,
so this is currently simulated by laying out the text vertically and getting
the ideal metrics of the vertical glyphs. ATSGlyphScreenMetrics produces more
information, and may match FT output better.

This doesn't pass make test yet. The text in the rest of the failures appears
to be offset - I'll investigate that next, but it may just be related to the
incorrect extents as above. Some errors are expected due to the lack of support
for mask in the quartz backend.
Comment 4 Behdad Esfahbod 2006-12-16 19:33:36 UTC
Brian, I believe you should use _cairo_matrix_compute_scale_factors().  Check
the ft backend for example.

As for Ideal vs Screen metrics, I agree.  Our extents are "ink" extents, so
Screen should be better.

Can you attach two patches?
Comment 5 Brian Ewins 2006-12-17 02:16:34 UTC
Created attachment 8143 [details] [review]
compute font size with  _cairo_matrix_compute_scale_factor

As requested. I'm not so keen on the "CGAffineTransformMakeWithScaleFactors"
name introduced here, since there's another function already there called
"CGAffineTransformMakeWithCairoFontScale". Mine makes the transform with just
the scale factors, the other also uses the rotation. Suggestions?
Comment 6 Behdad Esfahbod 2006-12-17 09:40:22 UTC
I don't have any strong feelings about the function name.  So, should I commit
this?  How about ATSGlyphScreenMetrics?
Comment 7 Brian Ewins 2006-12-17 13:21:16 UTC
I'd say commit it. ATSUI is still marked as experimental, and there will need to
be a cleanup pass before it gets marked as supported (theres lots of ignored
error conditions in there). Its more important at this stage to get it closer to
working.

As for the screen metrics: that's a no-go. I tried it and it wasn't producing
the inked extents for me, and in any case it produces device-space extents when
the ctm_inverse isn't available (making it available means calculating the
inverse or breaking the cairo api). These apis do produce the inked extents: 

ATSUGetGlyphBounds - needs the text layout for the glyphs. we can't get hold of
this, theres no api for producing a layout from a glyph.
ATSUMeasureTextImage - needs the text, not the glyphs. Again, no use.

Also both of these work in device space. The approach I'm working on is getting
the stroked extents of the path for the glyph - that's where 9378 appeared from.
I hope to have the measurements working later tonight in some form. 

In ATSUI, fetching text extents would have to be considered part of the 'toy'
api. You can do this much more directly outside of cairo.
Comment 8 Brian Ewins 2006-12-17 18:54:41 UTC
Created attachment 8152 [details] [review]
fix the extents to use screen metrics instead of ideal metrics.

Well, after me saying this approach doesn't work, it does. I was just applying
the wrong scaling to get the measurements back into user space. I'm not 100%
sure of the y bearing calculation, and there are probably some off-by-one
errors, corrections for antialiasing etc that should be done. But this is
getting towards being 'good enough'.
Comment 9 Brian Ewins 2006-12-17 18:59:05 UTC
Created attachment 8153 [details]
output after all the atsui patches so far. note extent boxes are tighter now.

Remaining in the scope of this bug: improving tests to allow per-backend
reference images. Also coverage of tests needs to be improved: the current set
don't scale the device space to be different from user space for fonts, and
don't display any text with descenders (which would have made the extents
problem more obvious).
Comment 10 Brian Ewins 2006-12-17 19:11:43 UTC
Created attachment 8154 [details] [review]
replacement for the extents fix

Typo in previous patch - good catch Behdad. Here's an update.
Comment 11 Behdad Esfahbod 2006-12-17 19:26:54 UTC
Committed: f3b9f486cd763c7805ec041319817cfb8c51128a.
Comment 12 Brian Ewins 2006-12-20 06:44:26 UTC
Behdad: can you please roll back f3b9f486cd763c7805ec041319817cfb8c51128a.

It looks much better on the test cases, but thats because the test cases aren't
testing enough. Theres no descenders in there, and if you change the test text
to eg 'cairg', the descender hangs outside of the extents. So its not really
improving things any, and in fact contains a typo which causes a warning, so
just nuke it.

The current method of calculating glyph sizes does not and cannot work. There is
in fact no way to calculate the y-bearing in ATSUI without starting with a text
layout, or measuring the paths directly.

The old code suckered me into thinking that it must've been close and just
needed tinkering, but its not. The y-bearing in both Ideal and Screen vertical
metrics are from the origin of a vertical layout,  which is at the top-centre,
to the  top of the glyph, . The y-bearing in an horizontal layout  is from the
baseline to the top of the glyph. The two can only be related if we also know
the distance from the origin of a vertical layout to the baseline of the glyph.

However we can't get this figure from ATSUI, and we'd need to, because its
making it up internally. Vera Sans doesn't store any vertical metrics, so its
not coming from the font.

The width and height we're calculating are also wrong (in that they are
typographic bounds). Width and height could be calculated from the stroke_extent
of the path of the glyph, and can also give us the y-bearing (just do this
bounding box calculation with the path origin at 0,0). 

In practice, people using ATSUI should not attempt to get glyph extents from
cairo, but should use ATSUGetGlyphBounds (which provides dev-space bounding
trapezoids, but only up to 31 at a time), or ATSUMeasureTextImage, which
measures the dev-space bbox of whole lines of text. Possibly we could expose
some ATSUI-specific api to fill extents in the cache from the glyph bounds, but
I'd rather leave that until someone has a use case.

In the meantime, we can measure the bounding box of the paths with something like:
typedef struct cairo_atsui_path_ref {
   CGMutablePathRef path;
   CGAffineTransform ctm;
}
//...
cairo_atsui_path_ref_t callbackData;
callbackData.path = CGPathCreateMutable();
callbacData.ctm = CGAffineTransformMake(...); // use appropriate cairo bits
status = ATSUGlyphGetCubicPaths (style, glyphID, 
   // these procs are all one-liners calling eg CGPathAddCurveToPoint 
   move_to_proc, line_to_proc, curve_to_proc, close_path_proc, 
   &callbackData, &status);
if (!status) {
	CGRect rect = CGPathGetBoundingBox(path);
	// etc
}
CGPathRelease(path);

I'll come up with a patch based on this approach, this time tested on a wider
variety of text (eg using c-cedilla, A-circumflex, to get ink above the
capheight and below the baseline).

Sorry for the churn. 
Comment 13 Behdad Esfahbod 2006-12-20 09:04:31 UTC
So, none of the patch is useful?

As for getting extents from cairo versus ATSUI, I don't agree.  The entire point
of cairo is to let people deal with one API.  Anyway, if you don't have a better
fix, I'll just revert this.
Comment 14 Brian Ewins 2006-12-21 15:04:49 UTC
Created attachment 8190 [details] [review]
measure glyphs using path bounding boxes. 

I don't disagree on the single api Behdad, and I'm trying to make it work! I'm
just observing that at the point where an atsui user would get glyphs for
themselves (ie they aren't using the toy api) then they have all the
information needed to make one call to measure their text directly using atsui.


In any case: this latest patch fixes the issue properly, as I described above.
I've created it to be applied directly without the revert. A few test images
follow to show what changed.

NB since this uses paths to get the glyph extents, which means no bitmap fonts.
AFAIK bitmap fonts are unsupported in ATSUI.
Comment 15 Brian Ewins 2006-12-21 15:06:18 UTC
Created attachment 8191 [details]
shows the broken behaviour with descenders before this patch

The descenders poke outside of the bounding box in this image.
Comment 16 Brian Ewins 2006-12-21 15:07:14 UTC
Created attachment 8192 [details]
showing fixed descender handling
Comment 17 Brian Ewins 2006-12-21 15:09:26 UTC
Created attachment 8193 [details]
Demonstrating that the 'cairo' rendering didn't regress.
Comment 18 Brian Ewins 2006-12-21 15:58:38 UTC
Created attachment 8194 [details] [review]
Same patch, without the compile warning. oops.
Comment 19 Behdad Esfahbod 2006-12-23 12:34:47 UTC
Committed. 261d6b805c77dacb27d29d054e48ed548f1fbcc5
Comment 20 Brian Ewins 2007-01-07 06:17:06 UTC
Comment on attachment 8143 [details] [review]
compute font size with  _cairo_matrix_compute_scale_factor

Committed first patch as d30b1bf157126668c4309731022b2ded2ad09571
Comment 21 Brian Ewins 2007-03-24 05:42:53 UTC
This bug has outlived its usefulness. Most of the issues it describes are now patched, with one exception - the tests can't be made to pass with freetype-based images. This is covered in bug 9465.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.