#include "dat.h" #include #include "fn.h" static PangoFontMap *fontmap; static PangoContext *context; static PangoLayout *layout; static void resetlayout(void) { pango_layout_set_width(layout, -1); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); } static void textclear(void) { if(layout != nil) g_object_unref(layout); if(context != nil) g_object_unref(context); if(fontmap != nil) g_object_unref(fontmap); layout = nil; context = nil; fontmap = nil; } static void setfont(void) { PangoFontDescription *font; PangoRectangle r; int size; font = pango_font_description_new(); pango_font_description_set_family(font, "sans"); pango_font_description_set_absolute_size(font, Fontsz * PANGO_SCALE); pango_layout_set_font_description(layout, font); pango_layout_set_text(layout, "Mg", -1); pango_layout_get_pixel_extents(layout, nil, &r); if(r.height > 0){ /* Fontsz is the popup row height, not a point size. */ size = Fontsz * PANGO_SCALE * Fontsz / r.height; pango_font_description_set_absolute_size(font, max(size, PANGO_SCALE)); pango_layout_set_font_description(layout, font); } pango_font_description_free(font); } int textinit(void) { textclear(); fontmap = pango_cairo_font_map_new(); if(fontmap == nil){ fprint(2, "strans: popup: can't initialize PangoCairo\n"); return 0; } pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(fontmap), 96); context = pango_font_map_create_context(fontmap); if(context != nil) layout = pango_layout_new(context); if(context == nil || layout == nil){ fprint(2, "strans: popup: can't create text layout\n"); textclear(); return 0; } pango_layout_set_single_paragraph_mode(layout, TRUE); setfont(); return 1; } static int settext(Str *s) { char utf[Maxutf]; int n; if(layout == nil || s == nil || s->n <= 0) return 0; n = stoutf(s, utf, sizeof utf); pango_layout_set_text(layout, utf, n); return n > 0; } static void textextents(PangoRectangle *r) { PangoRectangle ink, logical; int x0, y0, x1, y1; pango_layout_get_pixel_extents(layout, &ink, &logical); x0 = min(ink.x, logical.x); y0 = min(ink.y, logical.y); x1 = max(ink.x + ink.width, logical.x + logical.width); y1 = max(ink.y + ink.height, logical.y + logical.height); r->x = x0; r->y = y0; r->width = max(x1 - x0, 0); r->height = max(y1 - y0, 0); } int textwidth(Str *s) { PangoRectangle r; if(layout == nil) return 0; resetlayout(); if(!settext(s)) return 0; textextents(&r); return r.width; } static void drawtext(u32int *buf, int w, int h, int x, int y, int fit, u32int color, Str *s) { PangoRectangle r; cairo_surface_t *surface; cairo_t *cr; int b, g, red, stride; if(layout == nil) return; resetlayout(); if(fit != -1 && fit <= 0) return; if(fit > 0){ pango_layout_set_width(layout, fit * PANGO_SCALE); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); } if(buf == nil || w <= 0 || h <= 0 || !settext(s)) return; stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w); if(stride < 0 || (vlong)stride != (vlong)w * sizeof buf[0]) return; surface = cairo_image_surface_create_for_data((uchar*)buf, CAIRO_FORMAT_RGB24, w, h, stride); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS){ cairo_surface_destroy(surface); return; } cairo_surface_mark_dirty(surface); cr = cairo_create(surface); if(cairo_status(cr) == CAIRO_STATUS_SUCCESS){ pango_cairo_update_layout(cr, layout); textextents(&r); /* A fallback face must not paint into another popup row. */ if(fit > 0) cairo_rectangle(cr, x, y, fit, Fontsz); else cairo_rectangle(cr, 0, y, w, Fontsz); cairo_clip(cr); cairo_move_to(cr, x - r.x, y + (Fontsz - r.height) / 2 - r.y); red = color >> 16 & 0xff; g = color >> 8 & 0xff; b = color & 0xff; cairo_set_source_rgb(cr, red / 255.0, g / 255.0, b / 255.0); pango_cairo_show_layout(cr, layout); } cairo_destroy(cr); cairo_surface_flush(surface); cairo_surface_destroy(surface); } void textdraw(u32int *buf, int w, int h, int x, int y, Str *s) { drawtext(buf, w, h, x, y, -1, Colfg, s); } void textdrawfit(u32int *buf, int w, int h, int x, int y, int fit, Str *s) { drawtext(buf, w, h, x, y, fit, Colfg, s); } void textdrawfitcolor(u32int *buf, int w, int h, int x, int y, int fit, u32int color, Str *s) { drawtext(buf, w, h, x, y, fit, color, s); }