popuplayout had two refit stages for a work area shorter than one padded row — 40 pixels — and popupdraw re-checked the layout it had just been handed, against an Imgh that bounded no buffer any more. Pango and Cairo abort rather than return nil, so textinit is void and the layout is never nil; the stride Cairo computes for RGB24 is w*4 by definition; and textdraw set the layout's width and ellipsis twice.
143 lines
3.4 KiB
C
143 lines
3.4 KiB
C
#include "dat.h"
|
|
#include <fontconfig/fontconfig.h>
|
|
#include <pango/pangocairo.h>
|
|
#include "fn.h"
|
|
|
|
static PangoFontMap *fontmap;
|
|
static PangoContext *context;
|
|
static PangoLayout *layout;
|
|
|
|
void
|
|
textclose(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);
|
|
}
|
|
|
|
void
|
|
textinit(void)
|
|
{
|
|
FcInit();
|
|
fontmap = pango_cairo_font_map_new();
|
|
pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(fontmap), 96);
|
|
context = pango_font_map_create_context(fontmap);
|
|
layout = pango_layout_new(context);
|
|
pango_layout_set_single_paragraph_mode(layout, TRUE);
|
|
setfont();
|
|
}
|
|
|
|
static int
|
|
settext(Str *s)
|
|
{
|
|
char utf[Maxutf];
|
|
int n;
|
|
|
|
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;
|
|
|
|
pango_layout_set_width(layout, -1);
|
|
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
|
if(!settext(s))
|
|
return 0;
|
|
textextents(&r);
|
|
return r.width;
|
|
}
|
|
|
|
/*
|
|
* Draws s at (x, y) into the w-by-h buffer, ellipsized to fit pixels and
|
|
* clipped to its own row so a tall fallback face cannot paint a
|
|
* neighbour.
|
|
*/
|
|
void
|
|
textdraw(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;
|
|
|
|
if(fit <= 0)
|
|
return;
|
|
pango_layout_set_width(layout, fit * PANGO_SCALE);
|
|
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
|
if(w <= 0 || h <= 0 || !settext(s))
|
|
return;
|
|
surface = cairo_image_surface_create_for_data((uchar*)buf,
|
|
CAIRO_FORMAT_RGB24, w, h, w * sizeof buf[0]);
|
|
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);
|
|
cairo_rectangle(cr, x, y, fit, 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);
|
|
}
|