diff options
| author | hachem <im@hachem.wtf> | 2026-10-09 11:08:09 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-10-09 11:08:09 +0200 |
| commit | e0572c37d970d601c17085bdb082cc6ef4356891 (patch) | |
| tree | f0b4d71c92978e74d127d7090d3e11380378a8b3 /kernel/ttf.rv | |
| parent | 8cb66100fe802c38d180ea29a11a902decf0fd8b (diff) | |
chore: fmt some revo code based on lung's example
Diffstat (limited to 'kernel/ttf.rv')
| -rw-r--r-- | kernel/ttf.rv | 459 |
1 files changed, 294 insertions, 165 deletions
diff --git a/kernel/ttf.rv b/kernel/ttf.rv index 17d1a19..fb1bab7 100644 --- a/kernel/ttf.rv +++ b/kernel/ttf.rv @@ -6,84 +6,120 @@ # fuck lung # fuck me # im like 90% confident this works, but im like 10% confident its fucked -fn ttf_mod(a, b) a - math.floor(a / b) * b +fn ttf_mod(value, modulus) -> num do + return value - math.floor(value / modulus) * modulus +end + +fn ttf_u8(data, offset) -> num do + return mem_read(data + offset, 1) +end -fn ttf_u8(d, o) mem_read(d + o, 1) -fn ttf_u16(d, o) mem_read(d + o, 1) * 256 + mem_read(d + o + 1, 1) -fn ttf_i16(d, o) do - const v = ttf_u16(d, o) - if v >= 32768 return v - 65536 - return v +fn ttf_u16(data, offset) -> num do + return mem_read(data + offset, 1) * 256 + mem_read(data + offset + 1, 1) end -fn ttf_u32(d, o) ((mem_read(d + o, 1) * 256 + mem_read(d + o + 1, 1)) * 256 + mem_read(d + o + 2, 1)) * 256 + mem_read(d + o + 3, 1) -fn ttf_tag_eq(d, o, tag) do - for i in 0..4 do if mem_read(d + o + i, 1) != tag[i]:ascii() return :false end +fn ttf_i16(data, offset) -> num do + const value = ttf_u16(data, offset) + if (value >= 32768) + return value - 65536 + return value +end + +fn ttf_u32(data, offset) -> num do + return ((mem_read(data + offset, 1) * 256 + mem_read(data + offset + 1, 1)) * 256 + mem_read(data + offset + 2, 1)) * 256 + mem_read(data + offset + 3, 1) +end + +fn ttf_tag_eq(data, offset, tag) -> bool do + for i in 0..4 do + if (mem_read(data + offset + i, 1) != tag[i]:ascii()) + return :false + end + return :true end -fn ttf_table(d, tag) do - const n = ttf_u16(d, 4) - for i in 0..n do - const rec = 12 + i * 16 - if ttf_tag_eq(d, rec, tag) return ttf_u32(d, rec + 8) +fn ttf_table(data, tag) -> num do + const count = ttf_u16(data, 4) + for i in 0..count do + const record = 12 + i * 16 + if (ttf_tag_eq(data, record, tag)) + return ttf_u32(data, record + 8) end return -1 end -fn ttf_cmap_sub(d, cmap_off) do - const n = ttf_u16(d, cmap_off + 2) +fn ttf_cmap_sub(data, cmap_off) -> num do + const count = ttf_u16(data, cmap_off + 2) let best = -1 - for i in 0..n do - const rec = cmap_off + 4 + i * 8 - const plat = ttf_u16(d, rec) - const enc = ttf_u16(d, rec + 2) - if (plat == 3 and (enc == 1 or enc == 0)) or plat == 0 do best = cmap_off + ttf_u32(d, rec + 4) end + + for i in 0..count do + const record = cmap_off + 4 + i * 8 + const platform = ttf_u16(data, record) + const encoding = ttf_u16(data, record + 2) + if (platform == 3 and (encoding == 1 or encoding == 0)) or platform == 0 do + best = cmap_off + ttf_u32(data, record + 4) + end end + return best end -fn ttf_glyph_of(d, sub, c) do - if ttf_u16(d, sub) != 4 return 0 - const segCount = ttf_u16(d, sub + 6) / 2 - const endBase = sub + 14 - const startBase = endBase + segCount * 2 + 2 - const deltaBase = startBase + segCount * 2 - const rangeBase = deltaBase + segCount * 2 - for i in 0..segCount do - if c <= ttf_u16(d, endBase + i * 2) do - const startC = ttf_u16(d, startBase + i * 2) - if c < startC return 0 - const idro = ttf_u16(d, rangeBase + i * 2) - if idro == 0 return (c + ttf_i16(d, deltaBase + i * 2)) band 0xFFFF - const g = ttf_u16(d, rangeBase + i * 2 + idro + (c - startC) * 2) - if g == 0 return 0 - return (g + ttf_i16(d, deltaBase + i * 2)) band 0xFFFF +fn ttf_glyph_of(data, subtable, code) -> num do + if (ttf_u16(data, subtable) != 4) + return 0 + + const segment_count = ttf_u16(data, subtable + 6) / 2 + const end_base = subtable + 14 + const start_base = end_base + segment_count * 2 + 2 + const delta_base = start_base + segment_count * 2 + const range_base = delta_base + segment_count * 2 + + for i in 0..segment_count do + if code <= ttf_u16(data, end_base + i * 2) do + const start_code = ttf_u16(data, start_base + i * 2) + if (code < start_code) + return 0 + + const idro = ttf_u16(data, range_base + i * 2) + if (idro == 0) + return (code + ttf_i16(data, delta_base + i * 2)) band 0xFFFF + + const glyph_id = ttf_u16(data, range_base + i * 2 + idro + (code - start_code) * 2) + if (glyph_id == 0) + return 0 + + return (glyph_id + ttf_i16(data, delta_base + i * 2)) band 0xFFFF end end + return 0 end -fn ttf_glyph_offset(d, loca, long, g) do - if long return ttf_u32(d, loca + g * 4) - return ttf_u16(d, loca + g * 2) * 2 +fn ttf_glyph_offset(data, loca, long, glyph_id) -> num do + if (long) + return ttf_u32(data, loca + glyph_id * 4) + return ttf_u16(data, loca + glyph_id * 2) * 2 end -fn ttf_advance(d, hmtx, numH, g) do - if g < numH return ttf_u16(d, hmtx + g * 4) - return ttf_u16(d, hmtx + (numH - 1) * 4) +fn ttf_advance(data, hmtx, num_hmetrics, glyph_id) -> num do + if (glyph_id < num_hmetrics) + return ttf_u16(data, hmtx + glyph_id * 4) + return ttf_u16(data, hmtx + (num_hmetrics - 1) * 4) end -fn ttf_add_line(edges, x0, y0, x1, y1) edges:push({ ax = x0, ay = y0, bx = x1, by = y1 }) +fn ttf_add_line(edges, x0, y0, x1, y1) + edges:push({ ax = x0, ay = y0, bx = x1, by = y1 }) -fn ttf_add_quad(edges, x0, y0, cx, cy, x1, y1, n) do +fn ttf_add_quad(edges, x0, y0, cx, cy, x1, y1, steps) do let px = x0 let py = y0 - for i in 1..(n + 1) do - const t = i / n + + for i in 1..(steps + 1) do + const t = i / steps const mt = 1 - t const qx = mt * mt * x0 + 2 * mt * t * cx + t * t * x1 const qy = mt * mt * y0 + 2 * mt * t * cy + t * t * y1 + ttf_add_line(edges, px, py, qx, qy) px = qx py = qy @@ -91,196 +127,289 @@ fn ttf_add_quad(edges, x0, y0, cx, cy, x1, y1, n) do end fn ttf_contour(pts, edges, nsub) do - const m = pts:len() - if m < 2 return :nil - let exp = {} - for i in 0..m do - exp:push(pts[i]) - const j = ttf_mod(i + 1, m) - if (pts[i].on == :false and pts[j].on == :false) do - exp:push({ x = (pts[i].x + pts[j].x) / 2, y = (pts[i].y + pts[j].y) / 2, on = :true }) + const point_count = pts:len() + if (point_count < 2) + return :nil + + let expanded = {} + for i in 0..point_count do + expanded:push(pts[i]) + const j = ttf_mod(i + 1, point_count) + + if pts[i].on == :false and pts[j].on == :false do + expanded:push({ x = (pts[i].x + pts[j].x) / 2, y = (pts[i].y + pts[j].y) / 2, on = :true }) end end - const n = exp:len() - let s = -1 - for i in 0..n do if (s < 0 and exp[i].on) do s = i end end - if s < 0 return :nil - let cx = exp[s].x - let cy = exp[s].y + + const expanded_count = expanded:len() + let start = -1 + for i in 0..expanded_count do + if (start < 0 and expanded[i].on) + start = i + end + + if (start < 0) + return :nil + + let cx = expanded[start].x + let cy = expanded[start].y let k = 1 - while k <= n do - const a = exp[ttf_mod(s + k, n)] - if a.on do - ttf_add_line(edges, cx, cy, a.x, a.y) - cx = a.x - cy = a.y + + while (k <= expanded_count) do + const point = expanded[ttf_mod(start + k, expanded_count)] + + if point.on do + ttf_add_line(edges, cx, cy, point.x, point.y) + cx = point.x + cy = point.y k += 1 - end - else do - const b = exp[ttf_mod(s + k + 1, n)] - ttf_add_quad(edges, cx, cy, a.x, a.y, b.x, b.y, nsub) - cx = b.x - cy = b.y + end else do + const endpoint = expanded[ttf_mod(start + k + 1, expanded_count)] + ttf_add_quad(edges, cx, cy, point.x, point.y, endpoint.x, endpoint.y, nsub) + cx = endpoint.x + cy = endpoint.y k += 2 end end end # how about you contour my fucking asshole -fn ttf_glyph_edges(d, glyf, loca, long, g, scale, ox, baseline, edges, nsub) do - const off = ttf_glyph_offset(d, loca, long, g) - const next = ttf_glyph_offset(d, loca, long, g + 1) - if next <= off return :nil # empty glyph - const base = glyf + off - const nc = ttf_i16(d, base) - if nc < 0 return :nil # skip +fn ttf_glyph_edges(data, glyf, loca, long, glyph_id, scale, ox, baseline, edges, nsub) do + const offset = ttf_glyph_offset(data, loca, long, glyph_id) + const next = ttf_glyph_offset(data, loca, long, glyph_id + 1) + + # empty glyph + if (next <= offset) + return :nil + const base = glyf + offset + const contour_count = ttf_i16(data, base) + + # skip + if (contour_count < 0) + return :nil + let ends = {} - for i in 0..nc do ends:push(ttf_u16(d, base + 10 + i * 2)) end - const npts = ends[nc - 1] + 1 - let p = base + 10 + nc * 2 - p += 2 + ttf_u16(d, p) # skip instructions + for i in 0..contour_count do ends:push(ttf_u16(data, base + 10 + i * 2)) end + + const point_count = ends[contour_count - 1] + 1 + let pos = base + 10 + contour_count * 2 + + pos += 2 + ttf_u16(data, pos) # skip instructions let flags = {} - while flags:len() < npts do - const f = ttf_u8(d, p) - p += 1 - flags:push(f) - if (f band 0x08) != 0 do - let rep = ttf_u8(d, p) - p += 1 - while rep > 0 do flags:push(f) rep -= 1 end + while (flags:len() < point_count) do + const flag = ttf_u8(data, pos) + + pos += 1 + flags:push(flag) + + if (flag band 0x08) != 0 do + let repeat = ttf_u8(data, pos) + pos += 1 + + while (repeat > 0) do + flags:push(flag) + repeat -= 1 + end end end + let xs = {} let x = 0 - for i in 0..npts do - const f = flags[i] - if (f band 0x02) != 0 do - const dx = ttf_u8(d, p) - p += 1 - if (f band 0x10) != 0 do x += dx end else do x -= dx end - end - else do - if (f band 0x10) == 0 do x += ttf_i16(d, p) p += 2 end + + for i in 0..point_count do + const flag = flags[i] + + if (flag band 0x02) != 0 do + const dx = ttf_u8(data, pos) + pos += 1 + + if (flag band 0x10) != 0 do + x += dx + end else do + x -= dx + end + end else do + if (flag band 0x10) == 0 do + x += ttf_i16(data, pos) + pos += 2 + end end + xs:push(x) end + let ys = {} let y = 0 - for i in 0..npts do - const f = flags[i] - if (f band 0x04) != 0 do - const dy = ttf_u8(d, p) - p += 1 - if (f band 0x20) != 0 do y += dy end else do y -= dy end - end - else do - if (f band 0x20) == 0 do y += ttf_i16(d, p) p += 2 end + + for i in 0..point_count do + const flag = flags[i] + + if (flag band 0x04) != 0 do + const dy = ttf_u8(data, pos) + pos += 1 + + if (flag band 0x20) != 0 do + y += dy + end else do + y -= dy + end + end else do + if (flag band 0x20) == 0 do + y += ttf_i16(data, pos) + pos += 2 + end end + ys:push(y) end + # split into contours let start = 0 - for ci in 0..nc do + + for ci in 0..contour_count do const stop = ends[ci] let pts = {} + for i in start..(stop + 1) do pts:push({ x = xs[i] * scale + ox, y = baseline - ys[i] * scale, on = (flags[i] band 0x01) != 0 }) end + ttf_contour(pts, edges, nsub) start = stop + 1 end end -fn ttf_fill(edges, w, h) do +fn ttf_fill(edges, width, height) -> table do let rows = {} - for py in 0..h do + + for py in 0..height do const yc = py + 0.5 let cross = {} - for e in 0..edges:len() do - const ed = edges[e] - const y0 = ed.ay - const y1 = ed.by - if ((y0 <= yc and yc < y1) or (y1 <= yc and yc < y0)) do + + for i in 0..edges:len() do + const edge = edges[i] + const y0 = edge.ay + const y1 = edge.by + + if (y0 <= yc and yc < y1) or (y1 <= yc and yc < y0) do const t = (yc - y0) / (y1 - y0) - let dir = 1 - if y1 < y0 do dir = -1 end - cross:push({ x = ed.ax + t * (ed.bx - ed.ax), dir = dir }) + let direction = 1 + + if y1 < y0 do + direction = -1 + end + + cross:push({ x = edge.ax + t * (edge.bx - edge.ax), dir = direction }) end end + # sort crossings left to right # insertion sort - for a in 1..cross:len() do - const key = cross[a] - let b = a - 1 - while (b >= 0 and cross[b].x > key.x) do - cross[b + 1] = cross[b] - b -= 1 + for i in 1..cross:len() do + const key = cross[i] + let j = i - 1 + while (j >= 0 and cross[j].x > key.x) do + cross[j + 1] = cross[j] + j -= 1 end - cross[b + 1] = key + + cross[j + 1] = key end + let bits = 0 - let wind = 0 + let winding = 0 + for k in 0..cross:len() do - wind += cross[k].dir - if (wind != 0 and k + 1 < cross:len()) do + winding += cross[k].dir + + if (winding != 0 and k + 1 < cross:len()) do const xa = cross[k].x const xb = cross[k + 1].x + if xb > xa do let any = :false - for px in 0..w do - if (px + 0.5 >= xa and px + 0.5 < xb) do bits = bits bor (1 shl px) any = :true end + for px in 0..width do + if (px + 0.5 >= xa and px + 0.5 < xb) do + bits = bits bor (1 shl px) + any = :true + end end + if any == :false do - const mid = math.floor((xa + xb) / 2) - if (mid >= 0 and mid < w) do bits = bits bor (1 shl mid) end + const midpoint = math.floor((xa + xb) / 2) + if (midpoint >= 0 and midpoint < width) + bits = bits bor (1 shl midpoint) end end end end + rows:push(bits) end + return rows end -global ttf_io = { buf = 0, pages = 512 } +global ttf_io = { buffer = 0, pages = 512 } -global load_ttf = fn(path, size) do +global load_ttf = fn(path, size) -> { glyphs: table, width: num, height: num } | :nil do const total = fs:size(path) - if total < 12 return :nil - if ttf_io.buf == 0 do ttf_io.buf = alloc_contig(ttf_io.pages) end - if ttf_io.buf == 0 return :nil - if total > ttf_io.pages * 4096 return :nil - fs:read_into(path, ttf_io.buf) - const d = ttf_io.buf - const head = ttf_table(d, "head") - const maxp = ttf_table(d, "maxp") - const cmap = ttf_table(d, "cmap") - const loca = ttf_table(d, "loca") - const glyf = ttf_table(d, "glyf") - const hhea = ttf_table(d, "hhea") - const hmtx = ttf_table(d, "hmtx") - if (head < 0 or cmap < 0 or loca < 0 or glyf < 0 or hhea < 0) return :nil - const upm = ttf_u16(d, head + 18) - if upm == 0 return :nil - const long = ttf_i16(d, head + 50) == 1 - const ascent = ttf_i16(d, hhea + 4) - const descent = ttf_i16(d, hhea + 6) - const numH = ttf_u16(d, hhea + 34) + if (total < 12) + return :nil + + if ttf_io.buffer == 0 do + ttf_io.buffer = alloc_contig(ttf_io.pages) + end + if (ttf_io.buffer == 0) + return :nil + if (total > ttf_io.pages * 4096) + return :nil + + fs:read_into(path, ttf_io.buffer) + + const data = ttf_io.buffer + const head = ttf_table(data, "head") + const maxp = ttf_table(data, "maxp") + const cmap = ttf_table(data, "cmap") + const loca = ttf_table(data, "loca") + const glyf = ttf_table(data, "glyf") + const hhea = ttf_table(data, "hhea") + const hmtx = ttf_table(data, "hmtx") + + if (head < 0 or cmap < 0 or loca < 0 or glyf < 0 or hhea < 0) + return :nil + + const upm = ttf_u16(data, head + 18) + if (upm == 0) + return :nil + + const long = ttf_i16(data, head + 50) == 1 + const ascent = ttf_i16(data, hhea + 4) + const descent = ttf_i16(data, hhea + 6) + const num_hmetrics = ttf_u16(data, hhea + 34) const scale = size / upm const baseline = math.floor(ascent * scale) let height = math.floor((ascent - descent) * scale) + 1 - const sub = ttf_cmap_sub(d, cmap) - if sub < 0 return :nil - const mgate = ttf_glyph_of(d, sub, 77) # 'M' - let width = math.floor(ttf_advance(d, hmtx, numH, mgate) * scale) + 1 - if width < 2 do width = math.floor(size * 0.6) + 1 end + + const subtable = ttf_cmap_sub(data, cmap) + if (subtable < 0) + return :nil + + const mgate = ttf_glyph_of(data, subtable, 77) # 'M' + let width = math.floor(ttf_advance(data, hmtx, num_hmetrics, mgate) * scale) + 1 + if (width < 2) + width = math.floor(size * 0.6) + 1 + const nsub = 5 let glyphs = {} + for code in 32..128 do - const g = ttf_glyph_of(d, sub, code) + const glyph_id = ttf_glyph_of(data, subtable, code) let edges = {} - ttf_glyph_edges(d, glyf, loca, long, g, scale, 1, baseline, edges, nsub) + + ttf_glyph_edges(data, glyf, loca, long, glyph_id, scale, 1, baseline, edges, nsub) glyphs:push(ttf_fill(edges, width, height)) end + return { glyphs = glyphs, width = width, height = height } end |
