Skip to main content

Crate llimphi_compositor

Crate llimphi_compositor 

Source
Expand description

llimphi-compositor — el núcleo declarativo de Llimphi, sin winit.

Aquí vive el árbol de vista View<Msg> (DSL declarativo), su instalación sobre taffy (mount), el pintado a vello::Scene (paint/paint_gpu) y el hit-test. Nada de esto necesita una ventana ni llimphi-hal: la composición view → layout → scene es pura y reutilizable.

El runtime que la maneja vive aparte:

  • llimphi-ui la corre sobre winit (run<A: App>()).
  • a futuro, un runtime sobre el framebuffer del kernel wawa puede reusar exactamente este compositor sin arrastrar winit.

wgpu entra sólo por la firma de GpuPaintFn (tipos de Device/Queue/ Encoder/TextureView); wgpu no depende de winit, así que el compositor sigue libre de windowing.

Structs§

Anim
Declara que las props visuales de paint de este nodo se animan de forma implícita. key debe ser estable entre rebuilds del View (índice de item, hash de id, etc.) — es lo que enlaza “el mismo nodo” entre frames.
AnimRegistry
Registro de animaciones implícitas, vivo entre frames. El runtime mantiene una instancia y llama Self::reconcile en cada redraw.
BackdropBlur
Datos de un backdrop blur listos para que el runtime lo aplique sobre la intermediate vía llimphi_hal::BlurCompositor::blur.
Border
Borde (stroke) pintado sobre el contorno redondeado del nodo, inset hacia adentro media línea para que el grosor quede dentro del rect (convención CSS box-sizing: border-box). Se pinta después del relleno.
Constraints
Restricciones de tamaño que un LayoutBuilderFn recibe: las dimensiones del slot que el layout le asignó al nodo (en px físicos). Análogo a las BoxConstraints de Flutter LayoutBuilder / al MediaQuery pero local al nodo (no a la ventana). El builder construye su subárbol en función de esto — p. ej. una columna si max_width < 600, dos si es ancho.
FilterPass
Una operación de filter lista para que el runtime la aplique sobre la intermediate, restringida a rect. Espeja BackdropBlur pero lleva una FilterOp genérica (el runtime hace match por variante). Fase 7.1232.
Hero
Declara un nodo como hero: la key enlaza la identidad entre frames; si el rect cambia, el runtime anima la transición.
HeroRegistry
Registro de heroes, vivo entre frames. Guarda el último rect por key para detectar el delta y un tween activo si está animando.
MaskPlacement
Encaje y modo de una máscara (CSS mask-size + mask-position + mask-repeat + mask-mode), resuelto contra el rect del nodo en el paint, con la misma aritmética que background-image. En el MountedNode viaja como Option: None = estirar la máscara al border-box en modo luminancia (comportamiento de la Fase 7.1226). Fase 7.1227 (encaje), 7.1228 (modo).
Mounted
Versión “instalada” del árbol: cada nodo tiene su NodeId de taffy, color y handler. Se mantiene en orden de inserción (recorrido pre-orden), así el hit-test puede iterar al revés para honrar el orden de pintado.
MountedNode
PaintRect
Rect absoluto del nodo (en coordenadas físicas del frame). Lo recibe el callback de View::paint_with para que pueda posicionar sus primitivas custom dentro del nodo.
Ripple
Declara que este nodo emite un ripple (salpicadura Material) al recibir un press. key debe ser estable entre rebuilds del View (igual que la key de crate::Anim) — es lo que enlaza la salpicadura retenida con el nodo entre frames. color es el tinte de la onda (típicamente semitransparente, p. ej. blanco a alpha ~0.25 sobre superficies oscuras o negro a alpha ~0.12 sobre claras); su alpha se multiplica por el fade.
RippleRegistry
Registro de ripples vivos, retenido por el runtime entre frames. Una instancia por ventana; el runtime llama Self::trigger en el press y Self::paint tras el paint del contenido.
SemanticsFlags
Banderas booleanas del nodo accesible. Todas opcionales (None = no aplica, que es distinto de “aplica pero es false”). Mantienelas en None salvo que el widget realmente las exponga — los lectores diferencian “no es checkable” de “es checkable y no checked”.
SemanticsSpec
Especificación semántica completa de un nodo. Lo que el runtime traduce a un accesskit::Node cada frame.
Shadow
Sombra proyectada detrás del rect del nodo (drop shadow), rasterizada con el draw_blurred_rounded_rect nativo de vello. Se pinta antes del relleno, así el fill (si es opaco) tapa la parte solapada y la sombra sólo asoma por el desenfoque + el offset. El radio sigue al del nodo (más spread).
SizeAnim
Declara que el tamaño de este nodo (CSS width/height / Flutter AnimatedSize/Compose animateContentSize()) se anima de forma implícita cuando cambia entre frames. Bloque 15 de PARIDAD-FLUTTER (extensión faltante del Bloque 4).
SizeAnimRegistry
Registro de animaciones implícitas de tamaño, vivo entre frames. El runtime mantiene una instancia y llama reconcile_size_anim en cada redraw antes del mount/layout.
TextMeasure
Datos de un nodo-hoja de texto necesarios para medirlo (shaping + line-break) sin volver a tocar el View. Lo consume el runtime en la función de medición que le pasa a LayoutTree::compute_with_measure.
TextSpec
Texto a pintar dentro de un nodo. Alineación por defecto Center (horizontal y vertical), apta para labels de botón. Para layouts tipo editor o párrafo, usar .text_aligned(...) con Alignment::Start.
TransformPivot
Punto de pivote de transform (CSS transform-origin). Cada eje se resuelve contra el rect del nodo como px + frac · tamaño: px (ya escalado por zoom por el caller) cubre offsets absolutos y frac los porcentuales (0.5 = 50% del ancho/alto). El default CSS 50% 50% (centro) es { px: (0.0, 0.0), frac: (0.5, 0.5) }; un nodo con transform_origin: None usa ese centro. Modela px + % por eje igual que transform_rel modela el translate(<%>) — necesario porque el % depende del layout, desconocido hasta paint.
View
Nodo de la vista declarativa. Estilo de layout (taffy) + relleno opcional (vello) + texto opcional (skrifa+vello) + Msg al click opcional + hijos.

Enums§

Cursor
Forma del puntero del mouse. Subconjunto práctico, llimphi-native (el compositor no depende de winit). El runtime (llimphi-ui) mapea 1:1 a winit::window::CursorIcon. Nombres alineados con CSS/winit.
DragPhase
Fase de un drag activo. Move se emite por cada CursorMoved con el delta desde el evento anterior; End se emite al soltar el botón.
FilterOp
Una operación de filtro CSS (filter: blur()/brightness()/…) aplicada al propio subárbol del nodo. A diferencia de backdrop_blur (que afecta lo pintado debajo), un FilterOp modifica el contenido del nodo. El runtime los aplica como post-pasada GPU sobre la intermediate, restringidos al rect del nodo, en el orden de la lista. La lista crece por fase (CSS Filter Effects 1): Blur (7.1232) + ColorMatrix (7.1233). Fase 7.1232.
GesturePhase
Fase de un gesto continuo (pinch-to-zoom de momento; rotación a futuro). El runtime emite Begin al iniciar el gesto, Update por cada cambio incremental y End al terminar. El camino de Ctrl+rueda (universal, sin trackpad) emite un único Update por click de rueda — no hay un “inicio” ni “fin” naturales, así que el handler debe tolerar Updates sueltos sin Begin previo (es lo común en desktop). El camino de trackpad (PinchGesture, sólo macOS/iOS) sí entrega Begin/Update*/End.
ImageFit
Cómo encajar una imagen en el rect del nodo (CSS object-fit / Flutter BoxFit). El runtime calcula la escala y el origen correspondientes a esta política y siempre recorta al node_rrect del nodo, así el clip respeta radius / corner_radii.
MaskCompose
Operador de combinación entre capas de máscara (CSS mask-composite). Mapea a un Compose Porter-Duff de vello cuando una capa extra se compone sobre las de abajo. Fase 7.1231.
MaskLen
Longitud de un eje de MaskSize/posición de máscara, sin resolver — el paint la resuelve contra el rect del nodo. Neutral respecto de CSS: el frontend (p. ej. puriy) traduce mask-size/mask-position a esto. Fase 7.1227.
MaskMode
Modo de una máscara (CSS mask-mode). Decide qué canal del píxel-máscara modula el alpha del contenido. Fase 7.1228.
MaskSize
mask-size neutral (espejo de BackgroundSize). Ver MaskPlacement. Fase 7.1227.
Role
Rol semántico del nodo. Los nombres y la granularidad siguen los roles de AccessKit / ARIA. Subset acotado: agregamos lo que falte cuando aparezca un caller real (regla del repo — no diseñamos para lo hipotético).

Functions§

collect_backdrop_blurs
Recolecta los nodos con MountedNode::backdrop_blur activo del árbol montado, junto con el sigma y el rect absoluto al cual restringir el blur. El runtime (llimphi-ui::eventloop) los aplica como post-pasada después de la rasterización vello, sobre la intermediate.
collect_builder_constraints
Lee las Constraints (tamaño del slot) de cada nodo is_layout_builder del árbol montado, en pre-orden. El runtime las pasa a expand_layout_builders. Un nodo sin rect computado (fuera del layout) cae a 0×0.
collect_filters
Recolecta los nodos con MountedNode::filter no vacío y los aplana en una lista de FilterPass en orden de árbol y en orden de la lista de cada nodo — así el runtime aplica la cadena filter: a b c en secuencia sobre el rect (a, luego b, luego c). El runtime las consume tras la rasterización vello, igual que collect_backdrop_blurs.
ease_out_cubic
Ease-out cúbico, el default razonable para transiciones implícitas (arranca rápido, frena suave). Copia local para no acoplar el compositor a llimphi-theme; el caller puede pasar cualquier fn(f32)->f32.
expand_layout_builders
Expande los layout_builder de view (pre-orden) usando cons — una Constraints por builder, en el orden que produjo collect_builder_constraints. Cada builder se reemplaza por un nodo contenedor (su mismo Style) cuyo único hijo es lo que devolvió la closure invocada con sus constraints. Builders sin constraint correspondiente (más builders que cons, p. ej. uno anidado recién producido) caen a 0×0 y se resuelven igual, pero su tamaño será nulo (límite v1: sin anidamiento). Consume view.
focus_order
Ids enfocables en orden de Tab (pre-orden del árbol = orden de inserción de Mounted::nodes). Sólo nodos con rect computado (presentes en el layout). Es el orden DOM-like de tabulación.
has_gpu_painter
Pasada GPU directo: recorre el Mounted en pre-orden DFS (mismo orden que paint) e invoca cada gpu_painter con el encoder y la TextureView del frame. Se ejecuta DESPUÉS de la pasada vello — la intermediate ya tiene fill/image/painter/text encima cuando los callbacks corren, así que su LoadOp debe ser Load. Devuelve si se invocó al menos un painter (para que el caller decida si vale la pena finalizar y submitir el encoder). true si algún nodo del árbol registró un gpu_painter (p. ej. el video de media vía gpu_paint_with). El eventloop lo usa para decidir si la capa de overlay necesita componerse aparte (sobre el contenido gpu) en vez de pintarse en la escena principal.
has_layout_builder
true si view o algún descendiente declara un crate::View::layout_builder. El runtime lo usa para decidir si vale la pena la resolución en dos pasadas; cuando es false (lo normal) el camino diferido se evita por completo.
has_over_painter
true si algún nodo del árbol registró un over_painter (vello “over” vía View::paint_over). El eventloop lo usa para decidir si vale la pena montar la pasada vello final + el composite sobre la intermedia. Coste cero (loop barato) cuando nadie usa el over-layer.
hit_test_click
Hit-test específico para clicks (incluye nodos draggables).
hit_test_cursor
Hit-test específico para la forma del cursor: devuelve el Cursor del nodo más al frente bajo el punto que declare uno. Como un hijo sin cursor no matchea el predicado, el cursor “cae” al ancestro más cercano que lo declare — herencia estilo CSS sin recorrer el árbol a mano. None = ningún nodo bajo el punto declara cursor (el runtime usa el default de la ventana). Lo invoca llimphi-ui en la transición de hover.
hit_test_double_tap
Hit-test para doble-tap: el nodo más al frente bajo el punto que declaró on_double_tap/on_double_tap_at. El runtime lo usa al detectar dos presses rápidos y cercanos.
hit_test_drop
Hit-test específico para drop targets (nodos con on_drop). Usado durante un drag activo para resaltar el destino y para invocar el handler al soltar.
hit_test_focusable
Hit-test para foco: el id focusable del nodo más al frente bajo el cursor (click-to-focus). None si no se clickeó nada enfocable.
hit_test_hover
Hit-test específico para hover (nodos con hover_fill).
hit_test_long_press
Hit-test para long-press: el nodo más al frente bajo el punto que declaró on_long_press/on_long_press_at. El runtime lo usa al armar el gesto en el press (que vence por tiempo si no hay movimiento ni release).
hit_test_middle_click
Hit-test específico para middle-click. Mismo modelo que right-click: sólo nodos que declararon on_middle_click reaccionan.
hit_test_pointer_move
Hit-test para movimiento posicional del cursor (nodos con on_pointer_move_at). El runtime lo invoca en cada CursorMoved para reportar la posición local al nodo más al frente que lo declare.
hit_test_pred
Hit-test parametrizado por elegibilidad. Devuelve el índice del nodo más al frente (último en pre-orden) cuyo rect contiene (x, y) y para el cual pred devuelve true, respetando clip: si el punto cae afuera de un nodo con clip, el subárbol entero es invisible.
hit_test_right_click
Hit-test específico para right-click. Sólo considera nodos que declararon on_right_click o on_right_click_at — un right-click sobre un nodo sin handler no hace nada (no se “filtra” al click izquierdo).
hit_test_ripple
Hit-test para ripple: el nodo más al frente bajo el punto que declaró un Ripple (vía View::ripple). El runtime lo usa en el press para disparar la salpicadura. Aditivo — no compite con click/drag.
hit_test_rotate
Hit-test específico para gestos de rotación (trackpad): el nodo más al frente bajo el punto que declaró un on_rotate. Análogo a hit_test_scale; el runtime lo invoca al recibir un RotationGesture. None = ningún nodo rotable bajo el cursor.
hit_test_scale
Hit-test específico para gestos de escala (pinch-to-zoom): el nodo más al frente bajo el punto que declaró un on_scale. Como un hijo sin handler no matchea el predicado, el gesto “cae” al ancestro más cercano que lo declare (un canvas grande zoomeable con widgets encima que no zoomean). El runtime lo invoca al recibir Ctrl+rueda o un pinch de trackpad. None = ningún nodo zoomeable bajo el cursor (el evento cae al scroll/on_wheel).
hit_test_scroll
Hit-test específico para áreas de scroll (nodos con on_scroll). El runtime lo usa al recibir la rueda: el nodo más al frente bajo el cursor con handler de scroll consume el evento antes del on_wheel global.
hit_test_scroll_chain
Cadena de scroll anidado: devuelve todos los nodos con on_scroll que contienen el punto, ordenados front→back (el primero es el más al frente, igual que hit_test_scroll; los siguientes son sus ancestros scrollables). El runtime itera la cadena al recibir la rueda y se queda con el primer handler que devuelva Some: si un scroll interno está en el extremo del eje y devuelve None, el evento “pasa” al ancestro scrollable más cercano (lista dentro de panel, etc.). Recorrido idéntico al de hit_test_pred pero acumulando todos los hits en vez de pisar.
hit_test_selectable
Hit-test para selección de texto: el índice del nodo de texto seleccionable (text_select_key) más al frente bajo el cursor. El runtime lo usa para arrancar/extender una selección; devuelve el índice (no la key) para que el caller acceda al text + rect del nodo. None si no hay texto seleccionable bajo el punto.
measure_text_node
Mide una hoja de texto para taffy: shaping + line-break con parley contra el ancho disponible, devolviendo el bounding box. Si el ancho ya está resuelto (known.width) se usa ese; si no, se deriva del available (Definite → ese ancho; MaxContent → sin límite = una línea; MinContent → 0 = envuelve a la palabra más ancha). El line_height sale del propio TextMeasure, el mismo que usa paint, así medida y pintado coinciden.
mount
mount_recursive
Mount en pre-orden directo sobre out: pusheamos el padre como placeholder (id real desconocido hasta crear el taffy node), recursamos hijos sobre el mismo out, y al volver completamos id + subtree_end.
next_focus
Próximo id de foco al pulsar Tab (o Shift+Tab si reverse), dado el order (de focus_order) y el current. Envuelve en los extremos. Si no hay enfocables devuelve None; si current ya no existe en el orden, arranca por el primero (Tab) o el último (Shift+Tab).
paint
paint_gpu
paint_over
Pinta la pasada vello “over” en scene: recorre el árbol en orden DFS pre-orden e invoca cada over_painter con el Typesetter compartido y el rect absoluto del nodo. Espejo de paint_gpu pero del lado vello — la diferencia de timing la pone el caller, que rasteriza esta scene DESPUÉS del pase GPU y la compone sobre la intermedia. No resetea scene (el caller decide); sólo agrega primitivas. Como paint_gpu, usa rects absolutos (no compone los transform de ancestros — el over-layer es contenido posicionado en coordenadas de pantalla, igual que el pintor GPU).
paint_range
reconcile_size_anim
Recorre el View tree y, para cada nodo con SizeAnim, reconcila su style.size con el registry: si cambió el objetivo, arranca un tween; si está animando, parcha style.size con el valor interpolado. Devuelve true si alguna animación de tamaño sigue viva → el runtime debe pedir otro redraw.

Type Aliases§

ClickAtFn
Handler de click con posición. Recibe (x_local, y_local, rect_w, rect_h): las dos primeras son la posición del cursor relativa a la esquina superior-izquierda del nodo y las dos últimas son el ancho/alto actual del nodo en pixels — útil cuando el caller necesita centrar o normalizar. Devolver None no dispara update.
DragAtFn
Variante de DragFn que conoce la posición inicial del press relativa al rect del nodo. Útil cuando el caller necesita identificar qué entidad (Concepto, lemming, etc.) bajo el cursor agarró el drag. Recibe (phase, dx, dy, initial_lx, initial_ly).
DragFn
Handler de drag. Recibe la fase + delta (dx, dy) desde el evento anterior (no acumulado desde el press). Devolver None deja el drag activo sin disparar Msg. Arc<dyn Fn> para que el runtime pueda clonarlo barato al iniciar el drag y mantenerlo vivo aunque el cache de la vista se regenere mientras tanto.
DragVelocityFn
Variante de DragFn que recibe la velocidad del drag al soltarlo (vx, vy en px/s). El runtime mide el desplazamiento sobre los últimos ~100 ms de movimiento (ventana móvil de hasta ocho samples) y la pasa en DragPhase::End. Durante DragPhase::Move ambas son 0.0 — la velocidad sólo es significativa al final. Permite fling-desde-drag: el caller arranca un ticker con esa velocidad y la decae con fling_step hasta asentar. Reemplaza la estimación manual que antes tenía que llevar el caller con Instant::now() por su cuenta.
DropFn
Handler de drop. El runtime lo invoca cuando un drag activo se suelta sobre este nodo. Recibe el payload u64 que el origen del drag declaró vía View::drag_payload. Devolver None ignora el drop.
GpuPaintFn
Callback de pintura GPU directo, sin vello intermedio. Recibe el device/queue ya construidos por el runtime más un CommandEncoder y la TextureView del frame (la intermediate Rgba8Unorm de WinitSurface), todo durante el paint del nodo.
LayoutBuilderFn
Constructor diferido de subárbol sensible al tamaño (Flutter LayoutBuilder). El runtime resuelve el tamaño del slot del nodo en una primera pasada de layout y luego invoca esta closure con esas Constraints para producir los hijos — así “construir distinto según el espacio disponible” deja de exigir conocer el tamaño al armar el View. Ver View::layout_builder.
OverPaintFn
Callback de pintura vello “over”: idéntico en firma a PaintFn (&mut Scene, &mut Typesetter, PaintRect), pero el runtime lo invoca en una pasada vello FINAL, después de todos los gpu_painter del frame. Sus primitivas se rasterizan sobre fondo transparente y se componen con alpha encima de la intermedia (que ya tiene vello-base + GPU directo). Resuelve el z-order inverso al de GpuPaintFn: permite pintar texto/sprites AA por vello encima de celdas instanciadas por GPU (dominium grid, futuro motor voxel).
PaintFn
Callback de pintura custom. El runtime lo invoca durante el paint del nodo (entre el fill/image y el text) con el Scene vivo
RotateFn
Handler de gesto de rotación (trackpad, sólo macOS — winit no emite RotationGesture en Wayland/Windows). Análogo a ScaleFn pero el segundo argumento es el delta de ángulo incremental en radianes (positivo = horario) en lugar del factor de escala; (focal_x, focal_y) es el punto bajo el cursor relativo al rect del nodo. El nodo más al frente bajo el cursor que declare un on_rotate consume el gesto. Base para rotar canvases/imágenes con dos dedos. Ver View::on_rotate.
ScaleFn
Handler de gesto de escala (pinch-to-zoom). Recibe (phase, factor, focal_x, focal_y):
ScrollFn
Handler de rueda local a un nodo. Recibe el delta (dx, dy) en líneas lógicas (misma normalización que App::on_wheel: dy positivo = scroll hacia abajo). El runtime lo invoca cuando la rueda gira con el cursor sobre este nodo, ANTES de caer al App::on_wheel global: si el handler devuelve Some(Msg), el evento se consume acá. Permite áreas de scroll autocontenidas (el widget scroll lo usa) sin que cada app rutee la rueda a mano por su Model. Devolver None deja pasar el evento al on_wheel global.