236 lines
7.6 KiB
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,
|
|
};
|