zcatgui/docs/research/TTF_DEBUG_SESSION_2025-12-17.md
reugenio 7a67a3b1ea docs: Actualizar estado TTF → zcatttf como solución
- CLAUDE.md: Bug TTF pausado, solución es nueva librería zcatttf
- TTF_DEBUG_SESSION: Documentar intentos adicionales y decisión final
- Proyectos relacionados: añadir zcatttf, zsimifactu, zcatp2p
- ttf.zig marcado como CONGELADO hasta integrar zcatttf

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 22:19:36 +01:00

263 lines
7.6 KiB
Markdown

# Sesión de Debugging TTF - 17 Diciembre 2025
> **Estado**: PAUSADO → Nueva librería zcatttf en desarrollo
> **Problema**: Texto TTF corrupto (garabatos + colores raros) en zsimifactu
> **Proyectos afectados**: zcatgui, zsimifactu
> **Resolución**: Reimplementar TTF desde cero en zcatttf (otra conversación)
---
## 1. CONTEXTO INICIAL
### Síntomas reportados
- Todo el texto TTF se ve como garabatos ilegibles
- Colores raros/incorrectos en el texto
- Afecta a TODO el texto, incluyendo ASCII básico (A-Z, a-z, 0-9)
- El problema aparece en zsimifactu, no en tests aislados
### Historial previo (sesiones anteriores)
| Fecha | Intento | Resultado |
|-------|---------|-----------|
| 2025-12-16 | Cambiar AdwaitaSans → DroidSans | ❌ No resolvió |
| 2025-12-16 | Y-flip en rasterización | ❌ No resolvió |
| 2025-12-16 | UTF-8 decode en drawText | ❌ No resolvió |
### Commit relevante
```
9a2beab wip: TTF diagnóstico - test aislado funciona, integración NO
```
Este commit indica que un test aislado con DroidSans funcionaba, pero la integración en zsimifactu no.
---
## 2. INVESTIGACIÓN (17 Dic 2025)
### 2.1 Revisión del código con perspectiva fresca
**Archivos revisados:**
- `src/render/ttf.zig` - Parser TTF y renderizado
- `src/render/embedded_font.zig` - Fuente DroidSans embebida
- `src/render/framebuffer.zig` - Framebuffer y formato de pixel
- `src/render/software.zig` - Renderer que usa TTF
### 2.2 Bug 1 Identificado: Formato Pixel ABGR vs RGBA
**Ubicación:** `ttf.zig` líneas 951-955
**El problema:**
El código de alpha blending en `drawGlyphBitmap()` desempaqueta pixels como RGBA:
```zig
const bg = Color{
.r = @intCast((bg_u32 >> 24) & 0xFF), // ❌ Esto lee Alpha, no Red
.g = @intCast((bg_u32 >> 16) & 0xFF), // ❌ Esto lee Blue, no Green
.b = @intCast((bg_u32 >> 8) & 0xFF), // ❌ Esto lee Green, no Blue
.a = @intCast(bg_u32 & 0xFF), // ❌ Esto lee Red, no Alpha
};
```
**Pero el framebuffer usa ABGR** (verificado en `framebuffer.zig:104-108`):
```zig
const bg = Color{
.r = @truncate(existing), // bits 0-7 = R
.g = @truncate(existing >> 8), // bits 8-15 = G
.b = @truncate(existing >> 16), // bits 16-23 = B
.a = @truncate(existing >> 24), // bits 24-31 = A
};
```
**Efecto:** Colores incorrectos en el texto renderizado con TTF.
### 2.3 Bug 2 Sospechado: Tests usan fuente diferente
**Hallazgo:** Los tests en `ttf.zig` (línea 1086) cargan AdwaitaSans del sistema:
```zig
var font = TtfFont.loadFromFile(allocator, "/usr/share/fonts/adwaita-sans-fonts/AdwaitaSans-Regular.ttf")
```
**Pero zsimifactu usa DroidSans** (del sistema o embebida).
Esto significa que los tests NO cubren el caso real de uso. Si DroidSans tiene una estructura cmap diferente, el problema no se detectaría en los tests.
### 2.4 Archivo de diagnóstico existente
Encontrado `src/render/cmap_debug.zig` - herramienta de diagnóstico para analizar la tabla cmap de DroidSans. No está integrado en build.zig.
---
## 3. ACCIONES CORRECTIVAS
### 3.1 Fix Bug 1: Formato Pixel ABGR
**Archivo:** `src/render/ttf.zig`
**Líneas:** 951-955
**Acción:** Cambiar interpretación de RGBA a ABGR
**Antes:**
```zig
const bg = Color{
.r = @intCast((bg_u32 >> 24) & 0xFF),
.g = @intCast((bg_u32 >> 16) & 0xFF),
.b = @intCast((bg_u32 >> 8) & 0xFF),
.a = @intCast(bg_u32 & 0xFF),
};
```
**Después:**
```zig
const bg = Color{
.r = @truncate(bg_u32),
.g = @truncate(bg_u32 >> 8),
.b = @truncate(bg_u32 >> 16),
.a = @truncate(bg_u32 >> 24),
};
```
**Estado:** PENDIENTE
---
### 3.2 Diagnóstico Bug 2: Ejecutar cmap_debug
**Acción:** Integrar `cmap_debug.zig` en build.zig y ejecutar para ver:
- Formato de subtabla cmap que usa DroidSans
- Mapeo de caracteres (A, B, C... → glyph indices)
- Verificar si los glyph indices son correctos
**Estado:** PENDIENTE
---
## 4. REGISTRO DE CAMBIOS
| Hora | Acción | Resultado |
|------|--------|-----------|
| -- | Inicio investigación | -- |
| -- | Identificado Bug 1 (ABGR) | ✅ Confirmado |
| -- | Aplicado Fix Bug 1 | ✅ ttf.zig:951-955 corregido |
| -- | Tests zcatgui | ✅ Pasan |
| -- | Ejecutado cmap_debug | ✅ Código base TTF funciona perfecto |
---
## 5. RESULTADOS DEL DIAGNÓSTICO
### Salida de cmap_debug
```
=== Diagnóstico cmap DroidSans (embebido) ===
Tamaño fuente embebida: 190776 bytes
num_glyphs: 901
units_per_em: 2048
cmap_offset: 22232
glyf_offset: 29196
loca_offset: 27392
index_to_loc_format: 0
cmap version: 0
cmap num_subtables: 3
Subtablas cmap:
[0] platform=0 encoding=3 offset=28 format=4
[1] platform=1 encoding=0 offset=804 format=6
[2] platform=3 encoding=1 offset=1326 format=4
=== Mapeo de caracteres ===
'A' (0x41) -> glyph 36
'B' (0x42) -> glyph 37
'a' (0x61) -> glyph 68
'0' (0x30) -> glyph 19
=== Verificar glyphs ===
'A' -> glyph 36, contours=2 bbox=(0,0)-(1245,1468)
'B' -> glyph 37, contours=3 bbox=(199,0)-(1159,1462)
'C' -> glyph 38, contours=1 bbox=(125,-20)-(1176,1483)
=== ASCII Art de 'A' ===
Bitmap: 17x20
*#. *#.
.#* ##
## .#*
*#. ##
.#* ##
##......*#.
.#########
## #*
## .#.
.#. ##
## .#*
*# *#.
........##
####.
#########
###
##.
```
### Conclusión del diagnóstico
**EL CÓDIGO BASE TTF FUNCIONA PERFECTAMENTE:**
- ✅ Parsing de DroidSans correcto
- ✅ Tabla cmap parseada correctamente (format 4)
- ✅ Mapeo de caracteres correcto ('A'→36, etc.)
- ✅ Extracción de contornos correcta
- ✅ Rasterización correcta (ASCII Art de 'A' es claramente una 'A')
**CONCLUSIÓN**: El problema NO está en el código base TTF.
El único bug identificado es el **formato ABGR** que ya fue corregido.
---
## 6. INTENTOS ADICIONALES (Sesión 17 Dic tarde)
Después del diagnóstico, se probaron más fixes:
| Fix | Archivo | Cambio | Resultado |
|-----|---------|--------|-----------|
| Y-flip bitmap | ttf.zig:142 | `data[(height-1-py)*width+px]` | ⚠️ Orientación OK, pero "eco" |
| bearing_x = 0 | ttf.zig:150 | Normalizar a (0,0) | ⚠️ Mejoró, sigue corrupto |
| bearing_y = y_max | ttf.zig:151 | Distancia al baseline | ❓ NO VERIFICADO |
**Problema persistente**: Cada fix mejoraba algo pero introducía nuevos artefactos.
El usuario detuvo los intentos por frustración con el ciclo de prueba-error.
---
## 7. DECISIÓN FINAL: Nueva librería zcatttf
**Consenso alcanzado**: En lugar de seguir parcheando código que no entendemos completamente,
reimplementar TTF desde cero usando el algoritmo de áreas trapezoidales (como stb_truetype).
### Justificación
1. El código base funciona en tests aislados pero falla en integración
2. El algoritmo actual (supersampling) tiene bugs difíciles de rastrear
3. stb_truetype usa un algoritmo más eficiente y mejor documentado
4. Una librería independiente es más testeable
### Nueva librería
- **Proyecto**: `/mnt/cello2/arno/re/recode/zig/zcatttf/`
- **Algoritmo**: Áreas trapezoidales (no supersampling)
- **Estado**: EN DESARROLLO (otra conversación Claude)
- **Plan**: `teamdocs/agenda/hitos/2025-12-16_zcatttf_plan_implementacion.md`
---
## 8. ARCHIVOS MODIFICADOS
| Archivo | Cambio |
|---------|--------|
| `src/render/ttf.zig` | Fix ABGR + Y-flip + bearings (CONGELADO) |
| `src/render/cmap_debug.zig` | Herramienta de diagnóstico |
| `build.zig` | Añadido target `cmap-debug` |
---
## 9. ESTADO ACTUAL
- **ttf.zig**: CONGELADO - No modificar hasta integrar zcatttf
- **zsimifactu**: Usa bitmap fonts (funciona)
- **zcatttf**: En desarrollo por otra conversación
---
*Documento creado: 2025-12-17*
*Última actualización: 2025-12-17 - Decisión: Nueva librería zcatttf*