Re: GNOME font library RFC



On 27 May 2000, Owen Taylor wrote:

Comments are between text, resulting thoughts are at end.

> into designing something, is to conserve effort and fix the font problem
> for Unix, and not just fix the font problem for GNOME. That is, make something
> that can be used as the next generation font API for X.
> 
> Yes, that is a big job, but you already seem to have some pretty 
> ambitious ideas.

Probably it is doable, using only X, Gtk+, libart and ORBit dependencies,
so it should be usable for more programs. And running X should be not
required for anything, but GdkFonts.
Also, the start should be working client-side API, which can at first used
as stand-alone library, like the existing system in gnome-print. Designing
waterproof client-server API is next step, but ideally frontend should not
depend on actual backend implementation.

> For the more client-side stuff. I would encourage you to again save
> effort and work on GnomeText-Font-Print / Pango integration. 

I have not had much time to look into Pango, but AFAIK, it is more
interested in positioned glyph-array compositing on text streams.
GnomeFont should be database keeper + rasterizer. So these should be
complementary projects. Of course, it will be good, if general API would
be rationally thought out, considering the needs of both.

The problem is:
- if all programs will interface to pango, which itself will interface
to gnome-font, then there should be access to rasterization, outline
generation and font fetching from pango.
Alternatively, if gnome-font == pango-font, then you can use pango API for
glyphlist generation and gnome-font API for rasterization and outlines.

> 
> > The initial API draft for client (mostly copied from existing font API) is
> > included in end of document. I am especially interested in special needs
> > of pango-like multilanguage text handling.
> > Also - maybe specific font should have rotation parameter - but then
> > possibly rotation is not enough, and full affine transform would be
> > better.
> > I am not sure, how to deal with ligatures. I prefer, if font handles them
> > internally, as there can be fonts with huge amounts of complex ligatures -
> > but maybe user program should still have a way to access full
> > ligature list.
> 
> Fonts cannot handle them internally (at least, not without very
> sophisticated and complicated font systems, like Quickdraw GX's finite
> state machines). This is because rendering many languages requires
> interaction between the set of ligatures and linguistic information.
> 
> What the font needs to export is enough information to allow the
> rendering system to pick the right ligatures and alternate glyphs.
> 
> The simple, and rather unsatisfactory, way of doing this is to simply
> have predefined glyph encodings - this is how Pango deals with X
> fonts.  For X, if Pango wants the form of an Alef glyph at the
> beginning of the word, it knows that it is at position foo in a font
> encoded with the mulearabic encoding.
> 
> The more sophisticated way of doing this is to include tables of information
> that allow the rendering system to pick the ligatures. OpenType is
> a well-developed example of doing this.
> 
> Robert Brady <rwb197@zepler.org> (the author of Pango's Devanagari shaper,
> and gote), is working on a way specifying ligatures to use with X fonts
> intermediate in complexity between these two extremes.
> 
> > API Draft
> > 
> > Problem 1. How to present available fonts in user-manageable way.
> 
> Have you read the Pango API's for this? Note that the general plan
> has been that Pango will play a central role in the future of
> GnomePrint / GnomeText. Raph hasn't had much time to give me feedback
> but that is the way things are supposed to me moving.
> 
> The current Pango font API's can be modified (though for Pango 1.0,
> that needs to be sooner rather than later), but it would be bad
> if the API's of GnomePrint and Pango were subtly different and
> incompatible.

No-no :)
Gnome-font should be rasterizer, and if all compositing is handled via
pango, there should not be duplicating.

>  
> > Proposal:
> > 
> > GnomeFontFamily
> > Opaque
> > 
> > GList * gnome_font_get_family_list (const gchar * encoding...)
> > 
> > Arguments: NULL-terminated list of accepted encodings. NULL or "*" if don't
> > care.
> > Returns: list of available font families, referenced
> > 
> > All further subclassing is done with static strings
> > 
> > GList * gnome_font_family_get_weights (GnomeFontFamily * family, ...)
> > GList * gnome_font_family_get_slants (GnomeFontFamily * family, ...)
> > GList * gnome_font_family_get_stretches (GnomeFontFamily * family, ...)
> > GList * gnome_font_family_get_variants (GnomeFontFamily * family, ...)
> > GList * gnome_font_family_get_encodings (GnomeFontFamily * family, ...)
> 
> This looks like a rather inconvenient way of doing things - I have
> to pick some axis to be the primary axis, and specify all the rest?
> It doesn't seem to map very well to what people generally want to
> do, which is either:
> 
>  - Find the closest match to some given specification
>  - List all variants for a particular font.

The idea came, when I fiddled with sodipodi font selector.
If font family does not handle extensive searching, font selection
dialogs should implement it itself - i.e. if user selects "Black" as
weight, there can be fewer alternatives, than for "Normal" weight.
Also - font library should be as agnostic, as possible about font naming
conventions. If there is "Semibold" font, it cannot call it "Medium",
although these can actually mean the same.
So - if I select "Times", then I would like to be able to get list of
available weights "Normal", "Bold", "Black", (NOT "Book", "Bold",
"Black"), without loading actual fonts.
Yes - there should be a way to request all font descriptions of family
too.
Also I'd like to have a way to request a family list, given language, or
encoding or similar.

> Pango's API is much simpler.
> 
> void       pango_font_map_list_fonts    (PangoFontMap           *fontmap,
> 					 const gchar            *family,
> 					 PangoFontDescription ***descs,
> 					 int                    *n_descs);
> void       pango_font_map_list_families (PangoFontMap           *fontmap,
> 					 gchar                ***families,
> 					 int                    *n_families);
> 
> Where, for pango_font_map_list_fonts(), if family is non-NULL, it lists
> the available fonts for that particular family, and if family is NULL
> it lists all fonts.

I would use GLists, instead of arrays - these make API cleaner IMHO - but
this, of course, depend on user preferences.

> > Arguments: GnomeFontFamily
> > NULL-terminated list of additional constraints, all expressed as string
> > key-value pairs
> > "weight", "slant", "stretch", "variant", "encoding"...
> > Multiple pairs with same key are ANDed, except encodings, which are ORed
> > Scalar arguments can include extra symbols:
> > "+bold" - bold or thicker == ">=bold"
> > ">book" - thicker than book
> > Synonyms are resolved according to current family rules - i.e. usually
> > "book" == "normal"
> > Returns: New GList of static strings
> 
> Why would you want this complexity? The set of variants for a particular
> font, is small. Why not just return them and let the client choose between
> them if they want. 

The said problem - every font chooser has to implement multi-dimensional
font array somehow. 

> > Convenience translations:
> > 
> > GnomeFontWeight gnome_font_string_to_weight (const gchar * weight)
> > GnomeFontSlant gnome_font_string_to_weight (const gchar * slant)
> > GnomeFontStretch gnome_font_string_to_weight (const gchar * stretch)
> > GnomeFontVariant gnome_font_string_to_weight (const gchar * variant)
> > GnomeFontEncoding gnome_font_string_to_encoding (const gchar * variant)
> > 
> > Opposite are family-dependent to allow correct value for synonyms
> > 
> > const gchar * gnome_font_weight_to_string (GnomeFontFamily * family,
> > 	GnomeFontWeight weight)
> > etc...
> > 
> > GnomeFontMap - unsized font
> > Opaque
> 
> I took a simpler approach to this for Pango:
> 
> PangoFontDescription *pango_font_description_from_string (const char                  *str);
> char *                pango_font_description_to_string   (const PangoFontDescription  *desc);
> 
> (look at the API docs on pango.org if you want a full description of the way
> this works.)
> 
> This makes for a very nice user api.
> 
>  font_desc = pango_font_description_from_string ("Times Bold 24");

Same reason - fonts have original names, which should be preserved,
wherever possible. I.e. you cannot resolve attributes to textual
description, without referring to font.

> 
> > GnomeFontMap * gnome_font_find (GnomeFontFamily * family,
> > 	GnomeFontWeight weight,
> > 	GnomeFontSlant slant,
> > 	GnomeFontVariant variant,
> > 	GnomeFontStretch stretch,
> > 	GnomeFontEncoding encoding);
> 
> The name GnomeFontMap for this is unfortunate. A PangoFontmap is an object
> that does lookups from PangoFontDescription to PangoFont.

OK.

> > Arguments: font data. Anything (including family) can be NULL, in which case
> > sensible default is loaded. Default values for all arguments are:
> > "Helvetica", "Book", "Normal", "Normal", "Normal", "iso-8859-15"
> > Returns: Referenced GnomeFontMap object
> 
> How can FontWeight, for instance, be NULL - it is a enumeration, right?

No. All family attributes are meant as static strings. I am also
considering variable argument list here, as there can be fonts with
different set of attributes than standard weight/slant/stretch/variant

> > Accessing members:
> > GnomeFontFamily * gnome_font_map_get_family (GnomeFontMap * map)
> > Returns: Referenced font family
> > const gchar * gnome_font_map_get_family_as_string (GnomeFontMap * map)
> > Return: Family name
> > etc... (weight, slant, variant, stretch, encoding)
> > 
> > const gchar * gnome_font_map_get_ps_name (GnomeFontMap * map)
> > Returns: PostScript name for font
> >
> > gdouble gnome_font_map_get_ascender (GnomeFontMap * map)
> > gdouble gnome_font_map_get_descender (GnomeFontMap * map)
> > gdouble gnome_font_map_get_underline_position (GnomeFontMap * map)
> > gdouble gnome_font_map_get_underline_thickness (GnomeFontMap * map)
> 
> The metrics can be very different for different scripts. (Arabic has
> much larger descenders than English). Pango has:
> 
> void                  pango_font_get_metrics       (PangoFont        *font,
> 						    const gchar      *lang,
> 						    PangoFontMetrics *metrics);
> 
> Where lang is the standard "en_US"-style string. If you really want
> to handle fine typography, you need to handle baseline adjustment as
> well. (See the OpenType spec, or Lunde's book for information about this)

No, I do not want to handle fine typography :)
But why specifying language here? Shouldn't particular font already
constrained to specific encoding/language?

> > Accessing glyphs
> > 
> > gint gnome_font_map_glyph_from_unicode (GnomeFontMap * map, gint unicode)
> 
> This is nowhere near sufficient. In the big picture, one-to-one char
> to glyph mappings are only a small part of what is necessary. 
>  
> > gint gnome_font_map_glyph_from_char (GnomeFontMap * map, gint ch)
> 
> Char? in what encoding?

That was meant to be defined by encoding attribute in font selecting.
Rationale is to have EASY way for application programmers to access fonts.
The other way is to force them using pango - maybe this is the right way -
ensuring, for example, that you simply cannot use neither gnome-print nor
canvas text item, without sending all your character data through pango
layout library.
The current state in GNOME is most unfortunate of all - there is not even
incomplete standard to output international text.

> > Text operations
> > 
> > GnomeGlyphList * gnome_font_map_translate (GnomeFontMap * map,
> > 	const gchar * text)
> > Returns: List (array?) of glyphs, corresponding to given character. This
> > function resolves all ligatures that font support
> 
> This is nowhere near sufficient. Pango is all about doing this. Just 
> create a font system that Pango can use.

OK :)

> > ArtPoint * gnome_font_map_text_advance (GnomeFontMap * map,
> > 	const gchar * text, ArtPoint * advance)
> > ArtDRect * gnome_font_map_text_bbox (GnomeFontMap * map, const gchar * text,
> > 	ArtDRect * bbox)
> 
> > gdouble gnome_font_map_text_position (GnomeFontMap * map,
> > 	const gchar * text, gint position, gboolean inside_ligature)
> 
> Again, not enough. Don't try to do this yourself. Take advantage
> of Pango.

OK :)

> > Misc
> > 
> > gchar * gnome_font_map_get_ps_font (GnomeFontMap * map, gint * length)
> > Returns: PostScript (type?) font, suitable for sending to printer
>  
> Hmmm, but, what do you do with the result? What's the encoding?
> What if the font map maps to more than one font? Wouldn't it be
> better to have a function to render to postscript.

Rationale:
User sets gnome print font, using gnome_print_setfont (pc, font)
Now - depending on printing context, it can be more efficent to send font
to postscript printer. Printing context does usually not know actual
printing resolution, so sending curves/bitmaps does not count. It has
somehow extract font or fontset information from font library and send it
to printer.
Current implementation simply gives back a buffer, which can contain
anything. gnome_print_show could send it to printer, if required.

The actual implementation can be different, but something similar is
needed.

>  
> > GnomeFont - sized font variant, suitable for rendering
> > Opaque
> 
> I'm quite confused by the presence a bunch of functions duplicated
> between GnomeFont and GnomeFontmap; I don't think that is an
> intuitive API, and I don't quite undersand what the implications
> are of the duplication - what is the relation between the  metrics
> of the unsized font and the metrics of the sized font?
> 
> (Pango has no way of getting metrics for an unsized font - for X
> using bitmap fonts, there are huge deviations from linear scaling,
> and it wouldn't really make any sense at all.)

For any real layout, you usually need integer character/word metrics, to
align nicely with screen pixels or printer points. All font types have a
way, to get these. To align text correctly, whitespaces are then adjusted.
On the other hand - if you are interested in text outlines, you want
exact metrics.

> > gnome_font_render_glyph_pixmap_and_mask (GnomeFont * font, gint glyph,
> > 	GdkWindow * window, GdkPixmap ** pixmap, GdkBitmap ** bitmap)
> 
> You probably need to think about sub-pixel positionging here.

Probably. But there should always be aligned variant available to output
easily readable text. Have you looked at libart rendered tiny text -
although it is nice at first glance, working with it in
text-processor is nightmare.

> > gnome_font_render_text_graymap (GnomeFont * font, const gchar * text,
> > 	guchar * pixels, gint width, gint height, gint rowstride)
> > gnome_font_render_glyph_rgb (GnomeFont * font, const gchar * text,
> > 	guchar * pixels, gint width, gint height, gint rowstride,
> > 	guint32 color)
> > gnome_font_render_text_rgba (GnomeFont * font, const gchar * text,
> > 	guchar * pixels, gint width, gint height, gint rowstride,
> > 	guint32 color)
> > gnome_font_render_text_pixmap_and_mask (GnomeFont * font, const gchar * text,
> > 	GdkWindow * window, GdkPixmap ** pixmap, GdkBitmap ** bitmap)
> 
> These should all be done in conjunction with Pango, not separately.
> 
> > GdkFont * gnome_font_get_gdk_font (GnomeFont * font)
> > NB! this function should invoke X font lookup, to which (hopefully)
> > server-side XFS responds, rendering to X exact representation of given
> > font.
> 
> Pretty irrelevant in a few months. GdkFont is deprecated in the next
> release of GTK+. With Pango, a "font" does not map to a single X font
> in any particularly straightforward way.

Problem, I like to solve:
If office uses together GNOME apps (with pango etc.) and standard X apps.
Half of reasoning behind gnome-font should be the easy font management -
i.e. to ensure that I can access same fonts from every application.
As pango will be integrated with Gtk, there probably is no need for
requesting Gdk font separately (Gtk uses pango fonts, which ==
gnome-fonts), but still there is need for X font server.

> > const gchar * gnome_font_get_uri (GnomeFont * font)
> > Returns URI, if present, from where client can fetch that font
> 
> Is there a point in including this function at this point? What does the
> client get from the URI?

Imagine an office environment, where html documents are composed. Simplest
way, to ensure that people get right fonts, is to have these available in
http server, and reference to URI in html. And it would be nice, if
gnome-font would know the URI-s, so composer can insert these without
effort. Of course - this is more candy, than anything else :)

> Hope these comments are useful.
>                                         Owen

Yes very much :)

Further ideas:
There is 3 logically different packages needed:
1. Universal font server
2. Pango - multilanguage text resolver
3. High-quality font renderer
All these should be integrated.
I'll take some days to study Pango code. At moment I can only highlight
things, that are needed for rendering:
- A way to get bezier outlines and exact metrics of glyphs
- A way to get integer-aligned shapes and integer metrics of glyphs
- Bunch of methods to render to actual destinations
- A way, to get as good as possible X font from existing font
AFAIK, the basic datatype for all rendering should be PangoGlyphString -
but this should take into consideration proper pixel alignment.
Now - the font system probably wants to implement several glyph caches.
Some of these (outline cache) should be per-font (i.e. unsized), some per
sized font (shape cache). Maybe the differentiating between sized/unsized
font is not strictly necessary, if loading font does not load
unnecessary information (integer hinting rules), but for me it makes
things cleaner.
Now - how you think, would be best to implement abstract font description,
shared between 2 slightly different subsystems? Should pango know about
different font formats? If so, then it should implement outline fetching
and rendering itself - and gnome-font should be only server
implementation.
It is early morning already, so I'll continue thinking about it tomorrow
:)

Regards,
Lauris






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]