// 11 march 2018 #include "uipriv_unix.h" #include "draw.h" #include "attrstr.h" struct uiDrawTextLayout { PangoLayout *layout; }; // we need a context for a few things // the documentation suggests creating cairo_t-specific, GdkScreen-specific, or even GtkWidget-specific contexts, but we can't really do that because we want our uiDrawTextFonts and uiDrawTextLayouts to be context-independent // we could use pango_font_map_create_context(pango_cairo_font_map_get_default()) but that will ignore GDK-specific settings // so let's use gdk_pango_context_get() instead; even though it's for the default screen only, it's good enough for us #define mkGenericPangoCairoContext() (gdk_pango_context_get()) static const PangoAlignment pangoAligns[] = { [uiDrawTextAlignLeft] = PANGO_ALIGN_LEFT, [uiDrawTextAlignCenter] = PANGO_ALIGN_CENTER, [uiDrawTextAlignRight] = PANGO_ALIGN_RIGHT, }; uiDrawTextLayout *uiDrawNewTextLayout(uiDrawTextLayoutParams *p) { uiDrawTextLayout *tl; PangoContext *context; PangoFontDescription *desc; PangoAttrList *attrs; int pangoWidth; tl = uiprivNew(uiDrawTextLayout); // in this case, the context is necessary to create the layout // the layout takes a ref on the context so we can unref it afterward context = mkGenericPangoCairoContext(); tl->layout = pango_layout_new(context); g_object_unref(context); // this is safe; pango_layout_set_text() copies the string pango_layout_set_text(tl->layout, uiAttributedStringString(p->String), -1); desc = uiprivFontDescriptorToPangoFontDescription(p->DefaultFont); pango_layout_set_font_description(tl->layout, desc); // this is safe; the description is copied pango_font_description_free(desc); pangoWidth = cairoToPango(p->Width); if (p->Width < 0) pangoWidth = -1; pango_layout_set_width(tl->layout, pangoWidth); pango_layout_set_alignment(tl->layout, pangoAligns[p->Align]); attrs = uiprivAttributedStringToPangoAttrList(p); pango_layout_set_attributes(tl->layout, attrs); pango_attr_list_unref(attrs); return tl; } void uiDrawFreeTextLayout(uiDrawTextLayout *tl) { g_object_unref(tl->layout); uiprivFree(tl); } void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y) { // TODO have an implicit save/restore on each drawing functions instead? and is this correct? cairo_set_source_rgb(c->cr, 0.0, 0.0, 0.0); cairo_move_to(c->cr, x, y); pango_cairo_show_layout(c->cr, tl->layout); } void uiDrawTextLayoutExtents(uiDrawTextLayout *tl, double *width, double *height) { PangoRectangle logical; pango_layout_get_extents(tl->layout, NULL, &logical); *width = pangoToCairo(logical.width); *height = pangoToCairo(logical.height); } void uiLoadControlFont(uiFontDescriptor *f) { GtkWidget *widget; GtkStyleContext *style; PangoFontDescription *fontdesc; widget = g_object_ref_sink(gtk_label_new("")); style = gtk_widget_get_style_context(widget); gtk_style_context_get(style, GTK_STATE_FLAG_NORMAL, "font", &fontdesc, NULL); uiprivFontDescriptorFromPangoFontDescription(fontdesc, f); // pdesc is transfer-full and thus is a copy pango_font_description_free(fontdesc); g_object_unref(widget); } void uiFreeFontDescriptor(uiFontDescriptor *desc) { // TODO ensure this is synchronized with fontmatch.c uiFreeText((char *) (desc->Family)); }