[Cairo] Text API

Bill Spitzak spitzak at d2.com
Wed Jul 23 18:13:10 PDT 2003

My opinion is that the "font merging" must be done at a very low level, 
probably requiring changes to XRender itself, and maybe even the server 
portion of Xlib.

The user and program do *not* want "font sets". Programs want one *short* 
string to describe the "font". The string "Times" must somehow define *every* 
glyph. If anything more complex than this short string is needed then 
programs will be forced to provide a higher-level wrapper in order to be 
user-friendly, and we will be back to the current situation where no programs 
agree on how to name fonts.

It also seems to me that a sparse array of glyphs is going to be needed 
somewhere, since only a fraction of the 2^31 possible glyphs are going to be 
defined at any time. It certainly seems to me that any decisions about the 
source of glyphs should be done by the same code implementing this sparse 


Here is my proposal for the Cairo text interface. My intention is to make it 
trivial to label GUI buttons, relatively easy to make a "dumb" UTF-8 editor, 
but also to allow a Pango-like interface use the same calls. By using the 
same calls it confirms that this is powerful enough to handle other uses, 
rather than being specialized to exactly two:

cairo_set_text_matrix() : This copies the current transformation
matrix to the "text" matrix (only the ABCD values are stored in this
matrix and it is saved/restored at the same time the main matrix
is). The reason for this seperate matrix is so you can use cairo
transforms to position labels on objects without transforming the
labels themselves (similar to OpenGL) while also allowing the
PostScript ability to transform entire drawings.

cairo_get_text_matrix() : The current transformation matrix is replaced
with a new one such that 0,0 transforms to the current point and ABCD
are set equal to the current text matrix. This is so cairo drawing
operations can be used to draw glyphs. Use gsave/grestore to get the
previous transformation back.

cairo_set_font("name", A,B,C,D) : "name" selects a font. There are no
errors, if name is not the name of a font an implementation-defined
rule is used to pick the font. ABCD is a matrix and it is multiplied
by the textmatrix to produce a matrix that transforms all the glyphs
(a square that is the "point size" tall and wide is one unit). If B is
non-zero (indicating rotation) then you probably will not get nice
output unless you position each glyph with a seperate call.  All
possible 2^31 glyphs are set to predictable values by this call, no
matter what font calls were done before. The likely implementation is
that the name itself will define a few hundred glyphs, perhaps 1000 or
so are pulled from hardcoded other names, and about 30,000 others will
be set to roughly-scaled 16x16 bitmaps of all Unicode glyphs, and all
the rest will draw en*1 or 1*1 rectangles. Fonts defining symbols
(like "Symbol") will set the first 256 glyphs for compatability with
existing software (note this is different that Xft). No glyphs other
than a tiny set defined by Unicode standards are allowed to be blank,
and none can be zero or negative width.

cairo_draw_ucs32(dx,dy, unsigned* a, int n) : dx,dy is transformed by
the text matrix and the current point (last moveto/lineto) is moved
this distance in device space. Then the first glyph identified by a[0]
is drawn with it's origin at this point. Then a value (x,0) (NOTE y ==
0!!) called the "escapement" is determined from that glyph,
transformed by the text matrix, and used to move the current point
again in device space. (notice that kerning, bidir printing,
overprinting, etc are NOT done!!!).

float cairo_measure_usc32(unsigned* a, int n) : the escapement of all
the glyphs is added together and the x is returned. Since the y is
zero it is not returned.

cairo_draw_utf8(dx,dy, unsigned char* a, int n) : The bytes a[0]
through a[n-1] are interpreted as UTF-8 and the resulting glyphs are
drawn the same as cairo_draw_ucs32. a[-1] and a[n] should not be
looked at and should be assummed to be 0 for UTF-8 parsing
rules. *THERE ARE NO ERRORS*, any sequence of bytes that is not legal
UTF-8 (including a code using more bytes than necessary!!!) will
instead be converted so each byte renders one glyph of that value (ie
in the 128-255 range). This method allows about 99.9% of ISO-8859-1
strings to be printed correctly by this interface, which we must do
to encourage programs to use it.  (There is no "ascii" interface. This
is on purpose to encourage use of UTF-8. If you really need it you
must copy each byte to an unsigned array and use cairo_draw_ucs32).

float cairo_measure_uft8(unsigned char* a, int n) : the escapement of
all the glyphs is added together and the x is returned. Since the y is
zero it is not returned.

float cairo_ascent(), cairo_descent() : return the font-defined
location of the baseline. Placing the current point at
y-(ascent-descent)/2 will visibly center the text about the position y.

cairo_list_fonts(...) : Some kind of interface to enumerate all the
strings that can be passed to cairo_set_font.

cairo_glyph_attibutes(...) : Find out information about the glyphs as
necessary for Pango. Not sure what is needed here.


The PC (politically correct) crowd is going to lynch me because it is obvious 
that my interface is biased towards European text. However, we have to face 
reality: if the programming interface is not simple enough to be understood 
while at the same time useful for a large number of programmers, it is not 
going to get used! PC has done more to prevent I18N than any redneck 
programmers ever did.

To defend against these PC attacks you can point out that kerning is also not 
supported and that the interface is useless for drawing English vertically 
(letters horizontal but above each other) thus people are encouraged to use 
Pango. There are obvious ways to "improve" this interface to support kerning 
and vertical text, but I feel it is best to compromise the design so that a 
defense against PC can be made. Also such changes make Pango harder to 
implement and thus can backfire.

                   ,~,~,~,~ ~ ~ ~ ~
     /\_       _|_========___         Bill Spitzak
 ~~~/\/\\~~~~~~\____________/~~~~~~~~ spitzak at d2.com

More information about the cairo mailing list