summaryrefslogtreecommitdiff
path: root/vendor/stb/font.c
blob: 6c5106f60a878517b50f7f7e2279d1f773ecc052 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// stb_truetype wrapper for ui_sdl.zig. See font.h. Compiled into the SDL UI
// backend module alongside stb_truetype_impl.c (which defines the impl).
#include "font.h"
#include "stb_truetype.h"

#include <stdlib.h>
#include <string.h>

struct UIFont {
    stbtt_fontinfo info;
    const uint8_t *data;
};

UIFont *ui_font_new(const uint8_t *data, int32_t len) {
    if (!data || len <= 0) return NULL;
    UIFont *f = (UIFont *)calloc(1, sizeof(UIFont));
    if (!f) return NULL;
    f->data = data;
    int offset = stbtt_GetFontOffsetForIndex(data, 0);
    if (offset < 0 || !stbtt_InitFont(&f->info, (const unsigned char *)data, offset)) {
        free(f);
        return NULL;
    }
    return f;
}

void ui_font_free(UIFont *f) {
    free(f);
}

float ui_font_scale_for_height(UIFont *f, float px) {
    return stbtt_ScaleForPixelHeight(&f->info, px);
}

void ui_font_cell_metrics(UIFont *f, float scale, int32_t *cell_w, int32_t *cell_h, int32_t *ascent) {
    int asc = 0, desc = 0, gap = 0;
    stbtt_GetFontVMetrics(&f->info, &asc, &desc, &gap);
    int a = (int)(asc * scale + 0.5f);
    int d = (int)(-desc * scale + 0.5f);
    int g = (int)(gap * scale + 0.5f);
    *ascent = a;
    *cell_h = a + d + g;
    if (*cell_h < 1) *cell_h = 1;
    // monospace advance of 'M'
    int adv = 0, lsb = 0;
    stbtt_GetCodepointHMetrics(&f->info, 'M', &adv, &lsb);
    int w = (int)(adv * scale + 0.5f);
    if (w < 1) w = 1;
    *cell_w = w;
}

int ui_font_raster(UIFont *f, float scale, int32_t cp,
                   uint8_t *out, int32_t stride, int32_t cell_w, int32_t cell_h,
                   int32_t ascent) {
    if (!out || cell_w <= 0 || cell_h <= 0) return 0;
    // zero the cell
    for (int y = 0; y < cell_h; y++)
        memset(out + (size_t)y * stride, 0, (size_t)cell_w);

    int w = 0, h = 0, xoff = 0, yoff = 0;
    unsigned char *bm = stbtt_GetCodepointBitmap(&f->info, scale, scale, cp, &w, &h, &xoff, &yoff);
    if (!bm || w <= 0 || h <= 0) {
        if (bm) stbtt_FreeBitmap(bm, NULL);
        return 0;
    }
    // origin = (0, baseline=ascent); glyph top-left = (xoff, ascent + yoff).
    int gx = xoff;
    int gy = ascent + yoff;
    for (int y = 0; y < h; y++) {
        int dy = gy + y;
        if (dy < 0 || dy >= cell_h) continue;
        for (int x = 0; x < w; x++) {
            int dx = gx + x;
            if (dx < 0 || dx >= cell_w) continue;
            uint8_t v = bm[y * w + x];
            if (v) out[(size_t)dy * stride + dx] = v;
        }
    }
    stbtt_FreeBitmap(bm, NULL);
    return 1;
}