Extending standard attributes
Submitted by Behdad Esfahbod
Assigned to Cody Russell
Link to original bug (#511130)
Description
PangoAttribute is not a GType type and I seem to need to reinvent GType here...
Basic way to summarize the missing feature is: pango hardcodes some attribute types in code, basically all the predefined attribute types. A user-define attribute never has a chance to be treated similar to PANGO_ATTR_SHAPE for example. I want to fix that.
Concrete usecase for this is: currently PANGO_ATTR_SHAPE is very hard to use, much harder than it needs to be. I added pango_cairo_context_set_shape_renderer() which greatly simplifies that, so one doesn't have to implement a PangoRenderer to use shape attributes meaningfully anymore (ok, one didn't have to, see GtkTextView for example), but the biggest caveat still remains: It's hard for custom renders in libraries (like gdkpango) to add useful shape renderers (like rendering a GdkPixbuf) without taking full control of ATTR_SHAPE out of user's hand.
Instead of bandaiding that around ATTR_SHAPE I want to fix it properly (to the extent possible by compatibility). Here is my proposal:
-
Currently PangoAttrType's are assigned to predefined attributes from 0 (in the PangoAttrType enum) and allocated from 1000 up for custom attributes, in pango_attr_type_register(). We logically divide that integer "type" value into two parts: lowest byte as base type, three other bytes as instance type.
-
New API for creating new instances of other attribute types. We can only support shallow one-level subtyping here but that's all we care about. Proposed API:
PangoAttrType pango_attr_type_register_similar (const gchar *name, PangoAttrType similar_type);
Not sure about the name... What this does is to set the lower byte of the returned attr type to the lower byte of the base_type.
And a getter:
PangoAttrType pango_attr_type_get_base_type (PangoAttrType attr_type);
Base types are defined as those defined by Pango. An attribute registered using pango_attr_type_register() has base type PANGO_ATTR_INVALID.
- New API for attribute type similarity checking. This checks that the lower byte of attribute types for equality, but this is just the implementation detail and private, publicly just a function:
gboolean pango_attr_type_similar (PangoAttrType first_type, PangoAttrType second_type);
And a convenience one for actual attributes:
gboolean pango_attr_similar_to (PangoAttribute *attr, PangoAttrType other_type);
Note that this test only means that the type of attr and other_type have the same base type. attr is not necessarily of type other_type. As I said, shallow typing only...
-
Change Pango internals to always check for attribute base type instead of exact type. For example, in pango-renderer.c, instead of this:
switch (attr->klass->type) { case PANGO_ATTR_SHAPE: if (shape_attr) *shape_attr = (PangoAttrShape *)attr; break;
... }
We'll have:
switch (pango_attr_type_get_base_type (attr->klass->type))
{
case PANGO_ATTR_SHAPE:
if (shape_attr)
*shape_attr = (PangoAttrShape *)attr;
break;
...
}
- pango_cairo_context_set_shape_renderer() only sets shape renderer for ATTR_SHAPE. Add new API for setting shape renderer for custom shape attributes:
void pango_cairo_context_set_shape_renderer_for_attr_type (PangoContext *context, PangoAttrType attr_type, PangoCairoShapeRendererFunc func, gpointer data, GDestroyNotify dnotify) { g_return_if_fail (pango_attr_type_get_base_type (attr_type) != PANGO_ATTR_SHAPE);
... }
That's all. With all that, we can then add the following gdkpango API:
PangoAttribute * gdk_pango_attribute_pixbuf_new (GdkPixbuf *pixbuf, int width, int height, ...);
Then in gdk_pango_context_get(), register shape renderer for the type GDK_PANGO_ATTR_PIXBUF on the context being returned.
This way they user is free to use ATTR_SHAPE as they wish. The only problem with this being that all shape renderers need to be set on all PangoContext's. That's not totally infeasible, but is a bit of a burden. To fix that, we can provide PangoCairoRenderer API for that too, when we subclass PangoRenderer in gdkpango.
Owen, Matthias, comments?