Currently cairo provides the following functions: cairo_text_extents cairo_glyph_extents cairo_scaled_font_glyph_extents In Pango, I need cairo_scaled_font_text_extents or cairo_text_to_glyphs. While the latter may have other uses in its own, the former does the job in my case. Here is the original report: http://bugzilla.gnome.org/show_bug.cgi?id=313551
I have had a note in the cairo TODO for quite a while: * cairo_text_glyphs: It would function as a sort of bridge between the toy and the real text APIs: > void > cairo_text_glyphs (cairo_t *cr, const unsigned char *utf8, > cairo_glyph_t *glyphs, int *num_glyphs); > > with num_glyphs as an input-output parameter. The behavior of this > function would be such that calling: > > cairo_text_glyphs (cr, string, glyphs, &num_glyphs); > cairo_show_glyphs (cr, glyphs, num_glyphs); > > would be equivalent too: > > cairo_show_text (cr, string); > > as long as the original size of glyphs/num_glyphs was large > enough. I've always liked this idea as it would allow for doing things such as text-on-a-path while still interacting with the cairo API at the "toy" level of text, not glyphs. However, as it turns out, the semantics I defined above, (the sequence of cairo_text_glyphs; cairo_show_glyphs being equivalent to cairo_show_text), looks infeasible. The problem is that the cairo_glyph_t structure does not reference a font, so it's inadequate for implementing any chars-to-glyph function that references multiple fonts. (The original proposal for cairo_glyph_t did have a font in it, but I think we removed it since it was regarded as wasteful since pango would only call cairo_show_glyphs with the same font in every glyph). I guess the chars-to-glyphs function could return a list of font,glyph-list pairs, but that gets to be pretty awkward in a C API. So, those are the current frustrations I'm having with the function I originally wanted. (Meanwhile, Owen had other objections to a chars-to-glyphs function in cairo, but I don't currently recall what they were.) But back to your needs. It appears that any chars-to-glyphs function that requires a cairo_t wouldn't help you very much, since you already have a separate solution that does not require chars-to-glyphs but does require a dummy cairo_t. Correct? So, another possibility would be a public version of an existing internal function in cairo: cairo_status_t _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, double x, double y, const char *utf8, cairo_glyph_t **glyphs, int *num_glyphs) This interface is obviously restricted to a single font, so it avoids the font-merging problems of my desired cairo_text_glyphs function described above. And it would be a rather simple change to make an appropriately modified public interface to this. I'm open to suggestions on what the interface should look like. Should it be exactly as above? We generally try to stash status values in the object being acted upon, but we also avoid doing that for functions that nominally are not modifiers of that object. So this might be one of the rare cases where we actually return a status value and expect the user to check in. Since this is off in the already-"hard"-to-use scaled-font piece of cairo's API, I think I would be fine with that decision. Alternately, given that this function already exists in cairo, along with cairo_scaled_font_glyph_extents, it doesn't look like it would be too hard to implement cairo_scaled_font_text_extents instead. It probably should take an x,y pair in contrast to cairo_text_extents (which gets the x,y from the path's current point). Anyway, there are some thoughts from me. Let's get a patch together and look at it on the list. (Or if the various cairo_scaled_font_get_* functions from bug #5496 give you a not-too-ugly solution in pango, then we can avoid making a decision here.) -Carl
Thanks Carl for the detailed reply. I have mixed feelings about adding cairo_text_glyphs. On one hand, I see it useful for doing text on a path too, on the other hand, I like to see the toy API as limited as possible, for reasons that we both know, but most users of cairo don't know: that the toy API is not going to do i18n text anything near what Pango does anytime, unless you duplicate/copy Pango into cairo. So the more limited it is, the more people will use Pango or another real text rendering engine, and that makes their applications much more useful to the world. Back to my need, when cairo_scaled_font_t getters are committed, I have a solution using a dummy cairo_t. I create a 0x0 image surface, that should work good enough. So, yes, anything needing a cairo_t is not going to help me more here. I personally am not satisfied with the that way, so I'm calling that ugly and prefer adding cairo_scaled_font_text_extents, but if you really think it's going to make new problems later, I'm not insisting on it. I'm with you in implementing cairo_scaled_font_text_extents to fix this bug. Lets postpone exposing text_glyphs to when we exactly know where the toy api is going. I prefer: cairo_public void cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font, const char *utf8, cairo_text_extents_t *extents); Like cairo_scaled_font_glyph_extents, and I'd say it should use (0,0) as (x,y), but that's your decision. behdad
(In reply to comment #2) > So the more limited it is, the more people will use Pango or another real text > rendering engine, and that makes their applications much more useful to the world. OK. You, Owen, and Keith have all raised the same concern about this function. I fold. I won't add it, and we can all rest assured that people won't mistake cairo's toy API for anything but a toy. > cairo_public void > cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font, > const char *utf8, > cairo_text_extents_t *extents); > > Like cairo_scaled_font_glyph_extents, and I'd say it should use (0,0) as (x,y), > but that's your decision. As a rule, I do like fewer arguments rather than more. But I am a bit concerned that there might be a missing x,y offset here. There's no cairo_t here so the user couldn't just work around it with something like cairo_translate, right? But I also put a lot of trust in you as one of the primary users of this API. Are you quite convinced that nobody would ever need anything but (0,0) here?
Isn't the (x,y) simply added to the x,y in the extents? I mean, if there's no transformation involved, I prefer using (0,0). But if dropping (x,y) means somebody would need to create a dummy cairo_t, set ctm, etc, then I withdraw.
> Isn't the (x,y) simply added to the x,y in the extents? Uhm, yeah, I guess so. In that case, please move forward with your API as proposed. It looks good. -Carl
Created attachment 4345 [details] [review] patch. Patch for cairo_scaled_font_text_extents. Well, I reworked the pango patch and the "create dummy cairo_t" approach works perfectly now, just that it's ugly. I will switch to this function when 1.2 is out...
Created attachment 4403 [details] [review] Updated patch Oops, forgot to free the glyphs array. Fixed.
[copying my recent post to cairo@cairographics.org which reviews the latest patch here] The indentation for the patch needs to be changed from two spaces to cairo's standard of four spaces (see cairo/CODING_STYLE for more details). Beyond that, I would like to see a little bit more detail in the documentation to describe what the returned extents actually are, (that is how they correspond to something that might be drawn). I recognize that you modelled the new documentation from the existing documentation for cairo_scaled_font_glyph_extents---it should be fixed as well. For example, the documentation for cairo_text_extents has the following paragraph: * Gets the extents for a string of text. The extents describe a * user-space rectangle that encloses the "inked" portion of the text, * (as it would be drawn by cairo_show_text()). Additionally, the * x_advance and y_advance values indicate the amount by which the * current point would be advanced by cairo_show_text(). This makes very clear the strong association between the values returned by cairo_text_extents and the effects of cairo_show_text. (There's also a second paragraph about whitespace character which you may just want to copy verbatim.) For cairo_scaled_font_text_extents, the first paragraph is a bit trickier to write since the drawing operation to reference is cairo_show_text, but only if the cairo_t is using the same scaled font. Maybe the right way to describe the operation would be to have the literal code necessary to achieve the same effect. Maybe something like: cairo_font_face_t *font_face; cairo_matrix_t font_matrix, ctm; cairo_font_options_t font_options; font_face = cairo_scaled_font_get_font_face (scaled_font); cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix); cairo_scaled_font_get_ctm (scaled_font, &ctm); cairo_scaled_font_get_font_options (scaled_font, &font_options); cairo_set_font_face (cr, font_face); cairo_set_font_matrix (cr, &font_matrix); cairo_set_matrix (cr, &ctm); cairo_set_font_options (cr, &font_options); cairo_show_text (cr, text); Though, now that I type that all out, maybe it would be easier to just describe it with text, saying something like "as it would be drawn by cairo_show_text if the cairo graphics state were set to the same font_face, font_matrix, ctm, and font_options as @scaled_font). Anyway, I'll let you take a whack at the complete paragraph. Does anybody see any problem with adding this new cairo_scaled_font_text_extents function? I've been convinced that this makes sense *instead of* ever adding any sort of text_to_glyphs functionality within cairo.
Created attachment 4423 [details] [review] updated patch with correct indentation and better docs Ok, attaching a final patch with better documentation and correct indentation.
Looks good to me. Please commit! -Carl
2006-01-22 Behdad Esfahbod <behdad@behdad.org> * src/cairo.h, doc/public/cairo-sections.txt: Add cairo_scaled_font_text_extents. * src/cairo-scaled-font.c (cairo_scaled_font_text_extents): New function. * src/cairo-scaled-font.c (cairo_scaled_font_glyph_extents): Improve documentation.
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.