windowmaker-wl/WINGs/wfont_wl.c

236 lines
7.6 KiB
C

#define WRASTER_NO_XLIB /* Wayland-only file: no libX11 deps */
/*
* wfont_wl.c — Wayland/PangoFT2 + pixman font backend for WINGs.
*
* No X11 dependency. Fonts are loaded via PangoFT2 (fontconfig+FreeType).
* Text is measured with pango_layout_get_pixel_size().
* Text is drawn by rendering to a temporary FT_Bitmap then alpha-compositing
* onto a pixman_image_t surface (passed as WMDrawable = uintptr_t).
*
* Semantic note: in Wayland compositor mode the WM owns the rendering pipeline.
* A "drawable" is a pixman_image_t* allocated by the surface backend; this file
* treats the WMDrawable handle as exactly that pointer.
*/
#include "wconfig.h"
#include "WINGsP.h"
#include <pango/pangoft2.h>
#include <pango/pangofc-fontmap.h>
#include <fontconfig/fontconfig.h>
#include <pixman.h>
#include <string.h>
extern void *W_GetViewBacking(unsigned long id);
static inline pixman_image_t *wl_font_resolve_drawable(WMDrawable d)
{
/* Synthetic IDs: 0x10000000-0x1FFFFFFF = WM frame_buf windows,
* 0x20000000-0x2FFFFFFF = WINGs view windows.
* Both are registered via W_RegisterBacking so W_GetViewBacking
* handles both ranges uniformly. */
if ((unsigned long)d >= 0x10000000 && (unsigned long)d < 0x30000000)
return (pixman_image_t *)W_GetViewBacking((unsigned long)d);
return (pixman_image_t *)(uintptr_t)d;
}
/* ------------------------------------------------------------------ */
typedef struct {
PangoFontMap *fontmap; /* PangoFT2FontMap — one per screen */
PangoContext *ctx;
} ScreenCtxWL;
typedef struct {
PangoLayout *layout;
int ascent; /* baseline offset within cell */
} FontHandleWL;
/* ------------------------------------------------------------------ */
static void *
wl_screen_init(W_Screen *scr)
{
(void)scr;
ScreenCtxWL *ctx = wmalloc(sizeof(*ctx));
ctx->fontmap = pango_ft2_font_map_new();
ctx->ctx = pango_font_map_create_context(ctx->fontmap);
return ctx;
}
static void
wl_screen_fini(void *sctx)
{
ScreenCtxWL *ctx = sctx;
g_object_unref(ctx->ctx);
g_object_unref(ctx->fontmap);
wfree(ctx);
}
static void *
wl_font_open(void *sctx, const char *fc_name, int *height_out, int *y_out)
{
ScreenCtxWL *ctx = sctx;
FontHandleWL *h = wmalloc(sizeof(*h));
FcPattern *pat = FcNameParse((FcChar8 *)fc_name);
PangoFontDescription *desc = pango_fc_font_description_from_pattern(pat, FALSE);
double sz = 0;
if (FcPatternGetDouble(pat, FC_PIXEL_SIZE, 0, &sz) == FcResultMatch)
pango_font_description_set_absolute_size(desc, sz * PANGO_SCALE);
h->layout = pango_layout_new(ctx->ctx);
pango_layout_set_font_description(h->layout, desc);
/* Measure ascent via font metrics from Pango. */
PangoFontMetrics *metrics =
pango_context_get_metrics(ctx->ctx, desc, NULL);
int asc = pango_font_metrics_get_ascent(metrics);
int dsc = pango_font_metrics_get_descent(metrics);
pango_font_metrics_unref(metrics);
h->ascent = PANGO_PIXELS(asc);
*height_out = PANGO_PIXELS(asc + dsc);
*y_out = h->ascent;
pango_font_description_free(desc);
FcPatternDestroy(pat);
return h;
}
static void
wl_font_close(void *sctx, void *handle)
{
FontHandleWL *h = handle;
(void)sctx;
if (!h) return;
g_object_unref(h->layout);
wfree(h);
}
static int
wl_text_width(void *handle, const char *text, int len)
{
FontHandleWL *h = handle;
pango_layout_set_text(h->layout, text, len);
int w = 0;
pango_layout_get_pixel_size(h->layout, &w, NULL);
return w;
}
/* Composite an 8-bit alpha mask onto a pixman_image_t with a solid colour. */
static void
blit_alpha_to_pixman(pixman_image_t *dst,
unsigned char *alpha, int stride,
int src_w, int src_h,
int dst_x, int dst_y,
unsigned short r, unsigned short g,
unsigned short b, unsigned short a)
{
pixman_color_t pc = { .red=r, .green=g, .blue=b, .alpha=a };
pixman_image_t *solid = pixman_image_create_solid_fill(&pc);
pixman_image_t *mask = pixman_image_create_bits(PIXMAN_a8,
src_w, src_h,
(uint32_t *)(void *)alpha,
stride);
pixman_image_composite32(PIXMAN_OP_OVER,
solid, mask, dst,
0, 0, 0, 0,
dst_x, dst_y,
src_w, src_h);
pixman_image_unref(mask);
pixman_image_unref(solid);
}
static void
wl_draw_string(void *sctx, void *handle, WMDrawable d,
int x, int y,
unsigned short r, unsigned short g,
unsigned short b, unsigned short a,
unsigned long pixel,
const char *text, int len)
{
FontHandleWL *h = handle;
pixman_image_t *dst = wl_font_resolve_drawable(d); if (!dst) return;
(void)sctx; (void)pixel;
const char *prev = pango_layout_get_text(h->layout);
if (!prev || strcmp(text, prev) != 0)
pango_layout_set_text(h->layout, text, len);
int pw = 0, ph = 0;
pango_layout_get_pixel_size(h->layout, &pw, &ph);
if (pw <= 0 || ph <= 0) return;
int stride = (pw + 3) & ~3;
unsigned char *buf = wmalloc((size_t)(stride * ph));
memset(buf, 0, (size_t)(stride * ph));
FT_Bitmap bm = {
.rows = (unsigned)ph,
.width = (unsigned)pw,
.pitch = stride,
.buffer = buf,
.pixel_mode = FT_PIXEL_MODE_GRAY,
.num_grays = 256,
};
pango_ft2_render_layout(&bm, h->layout, 0, 0);
blit_alpha_to_pixman(dst, buf, stride, pw, ph, x, y, r, g, b, a);
wfree(buf);
}
static void
wl_draw_image_string(void *sctx, void *handle, WMDrawable d,
int x, int y,
unsigned short tr, unsigned short tg,
unsigned short tb, unsigned short ta, unsigned long tpix,
unsigned short br, unsigned short bg,
unsigned short bb, unsigned short ba, unsigned long bpix,
int bg_w, int bg_h,
const char *text, int len)
{
pixman_image_t *dst = wl_font_resolve_drawable(d); if (!dst) return;
(void)tpix; (void)bpix;
/* Fill background. */
pixman_color_t bpc = { .red=br, .green=bg, .blue=bb, .alpha=ba };
pixman_image_t *bsolid = pixman_image_create_solid_fill(&bpc);
pixman_image_composite32(PIXMAN_OP_OVER,
bsolid, NULL, dst,
0, 0, 0, 0,
x, y, bg_w, bg_h);
pixman_image_unref(bsolid);
/* Draw text on top. */
wl_draw_string(sctx, handle, d, x, y,
tr, tg, tb, ta, tpix, text, len);
}
static int
wl_lookup_string(void *sctx, W_View *view, WMEvent *event,
char *buffer, int buflen, unsigned long *keysym_out)
{
(void)sctx; (void)view;
*keysym_out = event->u.key.keysym;
int len = event->u.key.utf8_len;
if (len > 0 && len < buflen) {
memcpy(buffer, event->u.key.utf8, len);
buffer[len] = '\0';
} else {
len = 0;
}
return len;
}
const W_FontBackend W_FontBackendWL = {
.screen_init = wl_screen_init,
.screen_fini = wl_screen_fini,
.font_open = wl_font_open,
.font_close = wl_font_close,
.text_width = wl_text_width,
.draw_string = wl_draw_string,
.draw_image_string = wl_draw_image_string,
.lookup_string = wl_lookup_string,
};