mirror of
https://github.com/tomolt/libschrift
synced 2025-07-26 04:24:38 -04:00
132 lines
3.7 KiB
C
132 lines
3.7 KiB
C
/*
|
|
* A simple command line application that shows how to
|
|
* use libschrift with X11 via XRender.
|
|
* See LICENSE file for copyright and license details.
|
|
* Contributed by Andor Badi.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <X11/Xlib.h>
|
|
#include <X11/extensions/Xrender.h>
|
|
|
|
#include <stdint.h>
|
|
#include "util/utf8_to_utf32.h"
|
|
#include "schrift.h"
|
|
|
|
static int add_glyph(Display *dpy, GlyphSet glyphset, SFT *sft, unsigned long cp)
|
|
{
|
|
#define ABORT(cp, m) do { fprintf(stderr, "codepoint 0x%04lX %s\n", cp, m); return -1; } while (0)
|
|
|
|
SFT_Glyph gid; // unsigned long gid;
|
|
if (sft_lookup(sft, cp, &gid) < 0)
|
|
ABORT(cp, "missing");
|
|
|
|
SFT_GMetrics mtx;
|
|
if (sft_gmetrics(sft, gid, &mtx) < 0)
|
|
ABORT(cp, "bad glyph metrics");
|
|
|
|
SFT_Image img = {
|
|
.width = (mtx.minWidth + 3) & ~3,
|
|
.height = mtx.minHeight,
|
|
};
|
|
char pixels[img.width * img.height];
|
|
img.pixels = pixels;
|
|
if (sft_render(sft, gid, img) < 0)
|
|
ABORT(cp, "not rendered");
|
|
|
|
XGlyphInfo info = {
|
|
.x = (short) -mtx.leftSideBearing,
|
|
.y = (short) -mtx.yOffset,
|
|
.width = (unsigned short) img.width,
|
|
.height = (unsigned short) img.height,
|
|
.xOff = (short) mtx.advanceWidth,
|
|
.yOff = 0
|
|
};
|
|
Glyph g = cp;
|
|
XRenderAddGlyphs(dpy, glyphset, &g, &info, 1,
|
|
img.pixels, (int) (img.width * img.height));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
#define END(m) do { fprintf(stderr, "%s\n", m); return 1; } while (0)
|
|
|
|
Display *dpy = XOpenDisplay(NULL);
|
|
if (dpy == NULL)
|
|
END("Can't open X display");
|
|
int s = 2, screen = DefaultScreen(dpy);
|
|
|
|
Window win = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 600*s, 440*s, 0,
|
|
DefaultDepth(dpy, screen), InputOutput, CopyFromParent, 0, NULL);
|
|
XSelectInput(dpy, win, ExposureMask);
|
|
Atom wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
|
XSetWMProtocols(dpy, win, &wmDeleteWindow, 1);
|
|
XMapRaised(dpy, win);
|
|
|
|
XRenderPictFormat *fmt = XRenderFindVisualFormat(dpy, DefaultVisual(dpy, screen));
|
|
Picture pic = XRenderCreatePicture(dpy, win, fmt, 0, NULL);
|
|
XRenderColor fg = { 0, 0, 0, 0xFFFF }, bg = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF };
|
|
|
|
Pixmap fgpix = XCreatePixmap(dpy, win, 1, 1, 24);
|
|
XRenderPictureAttributes attr = { .repeat = True };
|
|
fmt = XRenderFindStandardFormat(dpy, PictStandardRGB24);
|
|
Picture fgpic = XRenderCreatePicture(dpy, fgpix, fmt, CPRepeat, &attr);
|
|
XRenderFillRectangle(dpy, PictOpSrc, fgpic, &fg, 0, 0, 1, 1);
|
|
|
|
fmt = XRenderFindStandardFormat(dpy, PictStandardA8);
|
|
GlyphSet glyphset = XRenderCreateGlyphSet(dpy, fmt);
|
|
|
|
SFT sft = {
|
|
.xScale = 16*s,
|
|
.yScale = 16*s,
|
|
.flags = SFT_DOWNWARD_Y,
|
|
};
|
|
sft.font = sft_loadfile("resources/FiraGO-Regular.ttf");
|
|
if (sft.font == NULL)
|
|
END("TTF load failed");
|
|
|
|
XEvent event;
|
|
while (!XNextEvent(dpy, &event)) {
|
|
if (event.type == Expose) {
|
|
XRenderFillRectangle(dpy, PictOpOver, pic, &bg, 0, 0, event.xexpose.width, event.xexpose.height);
|
|
|
|
FILE *file = fopen("resources/glass.utf8", "r");
|
|
if (file == NULL)
|
|
END("Cannot open input text");
|
|
|
|
SFT_LMetrics lmtx;
|
|
sft_lmetrics(&sft, &lmtx);
|
|
int y = 20 + lmtx.ascender + lmtx.lineGap;
|
|
|
|
char text[256];
|
|
while (fgets(text, sizeof(text), file)) {
|
|
int n = strlen(text) - 1;
|
|
text[n] = 0; // '\n' => len>0
|
|
|
|
unsigned codepoints[sizeof(text)];
|
|
n = utf8_to_utf32((unsigned char *) text, codepoints, sizeof(text)); // (const uint8_t *)
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
add_glyph(dpy, glyphset, &sft, codepoints[i]);
|
|
}
|
|
XRenderCompositeString32(dpy, PictOpOver, fgpic, pic, NULL, glyphset, 0, 0, 20, y, codepoints, n);
|
|
|
|
y += 2 * (lmtx.ascender + lmtx.descender + lmtx.lineGap);
|
|
}
|
|
|
|
fclose(file);
|
|
} else if (event.type == ClientMessage) {
|
|
if ((Atom) event.xclient.data.l[0] == wmDeleteWindow)
|
|
break;
|
|
}
|
|
}
|
|
|
|
sft_freefont(sft.font);
|
|
XCloseDisplay(dpy);
|
|
return 0;
|
|
}
|
|
|