| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
| |
Two more shapers on the syllabic groundwork, from HarfBuzz 10.2's
source. Khmer reorders before any lookup: a coeng and Ro go before the
base, masked for pref, what follows them for cfar, a left matra goes
first; split matras decompose with U+17C1. Myanmar finds the base after
a kinzi, gives each glyph its place around it and sorts by place, and
zeroes mark advances before GPOS rather than after.
Noto Sans Khmer and Noto Sans Myanmar shape as HarfBuzz does at 20,000
runs a plan, and so do Unifont's Khmer and Myanmar (no GSUB).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Indic shaper, from HarfBuzz 10.2's source: syllables found by the
Indic machine; each syllable's base consonant, its pre-base matras and
reph moved around it and masked for the basic features, applied one at
a time within the syllable; then matras, reph and pre-base-reordering
consonants placed again by what the features made. Vowel constraints,
Indic decompositions and compositions, dotted circles for broken
syllables, and per-syllable matching come with it.
Plans carry GSUB pauses (steps where the shaper does its part) and the
stages of the features the shaper asks whether they would substitute;
the runtime answers with each subtable's would_apply, as HarfBuzz does.
Masks are now the common ones and each shaper's own.
text/syllabic.py reads HarfBuzz's Ragel grammars (Indic, Khmer,
Myanmar) and compiles each to a minimal DFA with Ragel's scanner
semantics; beside the machines Ragel generated from the same grammars,
100,000 random runs each find no syllable that differs. It also reads
HarfBuzz's Indic table (Unicode 16) cell for cell.
Every installed font shapes as HarfBuzz does (213 fonts, 1,688 plans);
the Indic ones at 20,000 runs a plan (FreeSerif's eight scripts,
FreeSans, Unifont's nine without GSUB), and nine new-spec Noto Sans
fonts at 5,000.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
HarfBuzz does
The planner now picks who positions as HarfBuzz 10.2 does: GPOS, the old
kern table when GPOS has no kern feature, and marks placed by combining
class and ink boxes when there is no GPOS; the Hangul shaper composes
syllables the font has whole, takes apart those it lacks into jamo for
ljmo, vjmo and tjmo, and moves tone marks before their syllable.
The section grows to an 80-byte header (the kern table, and each glyph's
ink box when a plan places marks without GPOS) and 88-byte plans (the
kern mask, the jamo masks). Kern tables are applied pair subtable by
pair subtable with HarfBuzz's own binary search; state machines, class
subtables and cross-stream kerning, which no installed font has, are
refused. The check spells Hangul syllables every way text does.
Every installed font Vega accepts shapes as HarfBuzz does (209 fonts,
1,520 plans, a thousand runs each), and the fonts refused before at
20,000 runs a plan: Noto Sans CJK KR and Baekmuk for Hangul, IPA Gothic
and Noto Mono for marks without GPOS, FreeSans, FreeSerif, Liberation
and DejaVu Sans ExtraLight for kern tables, Unifont's Latin, Greek,
Cyrillic, Hebrew and Hangul.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
vega display --access joins the accessibility bus as AT-SPI2 objects for
screen readers such as Orca, with no toolkit, ATK or libdbus: dbus.c
speaks the D-Bus wire format (EXTERNAL authentication, headers, aligned
bodies, calls, replies, signals). The tree follows what the say surface
says: a heading, a label per field, a list box per list whose items know
their place and which is selected and focused, tables, the entry, the
keys as buttons; answers come from the app when asked, one object has the
focus, and focus moves are said as events. Assistive technology can act
too: Selection focuses a row, Action presses a key. The live loop now
draws only when something changed, so a screen reader's questions no
longer cost frames. The check walks the tree with gdbus on a private
session bus with at-spi-bus-launcher, and follows the focus through keys,
Selection, Action and the events.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Chromium's accessibility tree
Lists are listboxes that keep the keyboard focus, the focused row their
active descendant, each option with its place in the whole list though
only the visible rows are drawn; tables are grids with row indices;
tones other than normal and muted are said, not only coloured; keys are
named buttons. The page now updates in place instead of rebuilding each
list, so the focus a screen reader follows survives every redraw. The
browser test reads Chromium's accessibility tree: roles, names, focus,
selection and the active descendant moving within the same list.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
order
text/layout.c puts the checked parts together: a paragraph's levels,
scripts resolved for Common and Inherited characters, break
opportunities, one shaping to measure, lines broken at the last
opportunity that fits (trailing spaces hang, and a line that shapes
wider than measured backs off), then per line L1, runs of one level and
one script shaped again, the runs in L2's order and their glyphs placed.
test-layout checks 30,000 random mixed-script paragraphs: lines cover
the text, mandatory breaks end lines, lines fit when they can, and
glyphs come in the order UAX #9 gives the characters. vega-symbols
paragraph draws a layout through the symbol file's glyphs.
|
| |
|
|
|
|
|
|
|
| |
UAX #14 line breaking (LB1-LB31, numbers tailored as Unicode's tests
are) and UAX #29's grapheme cluster, word and sentence boundaries, each
from generated property tables, the rules taken in order, in linear time.
They pass all of Unicode 15.1's LineBreakTest (10,274 cases),
GraphemeBreakTest (1,187), WordBreakTest (1,826) and SentenceBreakTest
(512).
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
The build tool compiles a font's shaping plans the way HarfBuzz's planner
does (features, stages, masks, lookups per script and direction) and
carries them with the font's character map, advances and GDEF, GSUB and
GPOS tables in a section of the symbol file (VEGASYM4); glyphs shaping
reaches become symbols of their own. A small engine ports HarfBuzz 10's
default, Arabic and Hebrew shaping step for step and reads the tables in
place, every read bounds-checked. The build refuses a file whose shaping
differs from HarfBuzz's on random runs: DejaVu Sans agrees on 600,000
runs in six scripts both ways, and every installed font the tool accepts
agrees too, at 1.05-1.18 times HarfBuzz's time.
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
vega display --live reads the kernel's input events with no library:
keys become Pure's key names and the text they type on a US layout, going
through the TUI's own handling (the input line takes text, else the app
takes keys); a mouse moves an outlined pointer and clicks, a touch screen
presses where it is touched, scaled from the device's range; the line
pressed is the row. --input FILE reads recorded events to their end and
prints the last frame, which is how this screenless Pi checks it: after
typing two items with Shift, Enter, Tab, Space and a touch on a row, the
display's last frame is the TUI's after the same keys and click, and came
back from the display controller as drawn.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
vega display draws the same frames on a display with the kernel's mode
setting and no library between: a connected connector's mode on a CRTC, its
primary plane flipped between two dumb buffers by atomic commits, the grid
as many cells as fit. Frames are drawn in cached memory and copied over,
since blending over write-combined buffers read them back slowly (a 1080p
frame took 370 ms; now 20.6 ms with a vertical sync and the check below).
This Pi has no screen but its display controller has writeback connectors:
--writeback sets a mode on one and takes every frame back as the controller
put it out. Each came back exactly as drawn, and the new check finds it the
pixel surface's frame for the same grid, pixel for pixel.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
vega pixels runs the same scripts as tui --dump and writes each frame as
an image: the view's cells (only those on screen are evaluated) become
glyphs, each drawn once per size with the exact area of its curves, in its
tone's colour on its row's background. No page, no scene in between. A
1920x1350 grid takes 12 ms a frame here, writing the image included.
Symbol files carry the font's line now (format 3: ascent and descent where
format 2 kept zeros), the cell height and baseline; and the build tool takes
fonts in order, later ones filling the codes earlier ones lack: a CJK font
alone drew ambiguous-width arrows two cells wide in a one-cell grid, which
the new check caught, so a monospace Latin font comes first and Hangul after.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Each size's symbols are drawn on the CPU into one 8-bit atlas, every pixel
the exact area its curves cover, and text is a quad per glyph reading it.
A 1080p page of 11,382 glyphs composes in 1.07 ms at 16 px (it took 525 ms
computing coverage per fragment), and the composed pixels are the CPU
raster's exactly (worst difference 0 for DejaVu's ASCII, 1 for Noto's
11,172 Hangul syllables).
Computing coverage on the GPU lost on both counts: a compute pass filling
the atlas took 5-13x longer than one Cortex-A76 core (35 against 2.7 ms at
16 px), and its faster sorting-network form computed whole rows wrongly
under this Mesa V3D. Coverage now has one implementation, in C, and the
shaders only compose. vega_symbol_raster takes a row stride to draw into
the atlas in place.
|
| |
|
|
|
|
|
| |
src/ held two parts, the surfaces that show modules to people and the
symbol format with its CPU and GPU drawing. As in Pure (design 009), top
level directories are now the parts, and the README says what each builds.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
OpenGL ES 3.1: the file's points go up as one storage buffer, each symbol
gets 16 row bands listing the curves they reach (cut by integer division of
doubled coordinates, so CPU and shader agree), and every pixel of a symbol's
box sums the exact area of its bands' curves, as vega_coverage does.
vega-symbols gpu draws every symbol against the CPU reference and times
1080p pages.
On the Pi 5's V3D it matches the reference (mean 0.001-0.1 levels, worst
4) but takes 142-757 ms a page, 83% of it in the area function. A sorting
network in registers made it 2.3x faster yet computes wrong rows in the
fragment stage with this driver, while the same code is exact in a compute
shader; so drawing each glyph size once into an atlas by compute comes next.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Format 2 (VEGASYM2) writes each contour as a chain of 4-byte points, on or
off the curve as in TrueType: endpoints are shared, lines have no control
point, and two off points imply the on point between them. A curve is still
had from one point and its two neighbours, so a GPU can point at curves by
point index and upload the table as it is. Cubics (CFF, SVG curves and arcs)
become quadratic splines the cu2qu way, joins left implied, within a unit.
Files are about half of format 1: 1.3-1.4x a TrueType font's glyf (the
whole subset font's size), 2.0-2.9x CFF, 2.6x smaller than the SVG icons.
Opening checks each symbol's first and last point instead of every curve:
0.34 ms rather than 19 ms for 11,172 Hangul syllables. Points decode
without branching on their flags (9.7 ns a point), still 1.2-10x cheaper
than FreeType's outline.
Glyph advances were half their width since outlines are doubled for
FreeType's implied points; they now match hmtx, and the check says so.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Symbol files (VEGASYM1) hold glyphs and icons as quadratic curves, verified
once per symbol and then read in place. vega-symbols builds them from fonts
(through FreeType, losslessly: twice the font's units keeps TrueType's
implied points whole) and from solid SVG paths (arcs included), refusing by
name what an icon asks for that symbols cannot hold.
The reference rasterizer computes each pixel's covered area exactly: every
curve's integral of clamp(1 - x) dy inside the pixel, split where it crosses
the pixel's sides. The Slug-style two-ray average first tried missed FreeType
by 15.4 levels on average at 12 px; exact area is within 1.2-3.5 at 8-16 px,
and where it differs most it matches 64x64 supersampling, not FreeType.
Reaching an outline costs 4.6-29x less than through FreeType, but the files
are 2.1-6.6x larger than glyf or CFF: design 002 has the numbers and the next
question (points shared along contours, lines without control points).
|
| |
|
|
|
|
|
|
|
|
| |
examples/board.aup is a kanban board: people add and move cards on
Vega's surfaces, programs post JSON to the same module served by
pure-serve, with no routes written. The checks write cards with the CLI
into a store, serve that store over HTTP where a program moves one and
adds another, and read it again with the CLI, the focus still on the
card it was on.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
The terminal and the web page set the time events see to the wall clock
and tick an app's timers on time: each round ticks what is due, draws,
then waits for input, a frame or the next tick, and a tick is news to
every open page at once. Scripts have no clock: time MS sets the time
the next events see and tick TIMER ticks, so an app that uses time
replays exactly. A module swap reschedules the timers.
examples/stopwatch.aup runs on every surface; the checks drive it by
script, on a pseudo-terminal by the clock, and on the web page.
|
| |
|
|
|
|
|
|
| |
examples/tally.aup counts typed words in a list keyed by the word: the
screen stays sorted with each word once, typing a word again counts it
and moves the focus to it. It runs on the three surfaces with the other
examples, and vega check finds nothing in it.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
vega tui|web MODULE --watch replaces the running app's module when its
file is written again (aup watch writes it); states keep their values by
name through pure_app_replace and every web page hears of it. The file is
compared by the digest of its bytes, at most five times a second, so a
module of the same size written within the same second is not missed; a
module that does not load leaves the app as it was and is not tried
again. Modules alternate between two slots so a failed load never touches
the running one. Scripts get swap MODULE; whether a module runs frames is
now a property of the screen.
|
| |
|
|
|
|
| |
The todo example now counts its open tasks, so the field line changes
with more events; a changed frame sends 143 B on average, not 139 B.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A list may now be filtered (each t in tasks where !t.done), and several
filtered lists over one list share one focus: the focus view names an
item, so Vega asks Pure which row shows it and highlights it only in the
list that holds it; the other lists have no focus (null in the web
surface's JSON, and the spoken surface names the item where it is). A
click or point on a row points at the item that row shows, and the wheel
on a list without the focus focuses the row under it. Pure's rows now
take a mutable app.
examples/today.aup shows what is open and what is done; its CLI output
matches a model over random adds, moves, toggles and points into either
list, and the web surface leaves the other list without a focus.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
vega web MODULE serves the screen to a browser (127.0.0.1 unless given
--listen): one dependency-free page draws the title, fields, lists as
listboxes and tables, with tones as colors and the focus highlighted. It
asks for the screen as JSON with the rows it can show per list or table,
so only those cells are evaluated, scrolled like the TUI around the
focus. Keys go as KeyboardEvent.code, which is Pure's key naming already;
typed text commits with Enter; a click or the wheel moves the focus
through pure_app_point; an event stream tells every open page of each
change. Scrolling, key presses and text commits are now shared helpers.
The checks drive it against the model (1,200 random steps: title, field,
rows, focus, the window of items with badges and tones), check a table's
columns and cells, post at random to every example, and in headless
Chromium over the DevTools protocol press keys, click a row and type
Korean text into the page itself.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Only the app's key handlers could move a list's focus. When the focus
view is a plain index position (`view tasks_list_focus = at.position`),
Vega now asks Pure for that index and moves it as a user pointing at a
row (pure_app_point), with no code in the app. The grid remembers which
item each line shows; in the TUI a click on a row focuses it and the
wheel moves the focus one row (SGR mouse reports, turned off on exit).
Scripts say point VIEW ROW or click LINE COLUMN on the last shown frame.
The focus is stored like any event, so the next run of any surface
starts from it.
The model now points too: random scripts with points (some past the
end) and TUI clicks still match it on every surface, a mouse click on a
real pseudo-terminal moves the focus, and the stored session keeps it.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The TUI rebuilt its grid from the app on every change and then sent all
of it. It now keeps what the terminal shows and sends each run of changed
cells after a cursor move (short unchanged gaps stay in a run, being
cheaper than another move; a run that starts in the second half of a wide
character starts at its first). A resize sends everything again.
vega tui --paint WxH writes the bytes of each frame; the checks replay
them with a small terminal emulator and compare with the dumped frame:
4,800 random frames at three sizes agree, and a change costs 139 bytes on
average against 1,220 for a whole frame. The interactive check now reads
the final screen from the replayed bytes.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Surfaces read a view that misses a convention as something else without
a word: a number label makes a list a table, a text tone disappears, a
list never shows its other columns, X_focus without a table becomes a
field, a second text input has nowhere to type. vega check MODULE names
each such place (the view or input and what the surface does instead)
and exits 1; the rules sit next to the code that reads the screen.
The checks build a spec that misses eight conventions and expect exactly
its nine findings, and none in the examples.
|
| |
|
|
|
|
|
|
|
|
|
| |
Every surface takes --store PATH and runs the app on Pure's tree store,
so a list typed in the terminal is there the next time, on any surface.
Vega and the app carry no saving code; Vega saves the last frame changes
when it ends.
Checks let the CLI and the sentence surface take turns on one store and
match the model each time, and reopen an interactive session's store.
|
|
|
Vega reads a verified Pure module by convention: a table view with a
label column is a list (with optional badge, detail and tone), any other
table is a table, <table>_focus is its focused row, a title view is the
title and other views are fields. lib/vega.aup gives aup apps the tones,
which say what a row means; each surface decides how it looks or sounds.
vega tui draws the screen in a terminal, keeps the focused row in view
and evaluates only the cells on screen; vega cli prints plain lines for
pipes; vega say speaks the screen and each focus change as sentences.
Display width handles Hangul, CJK, emoji, combining marks and controls.
tests/check.py compares the CLI and NUI output with a reference model of
examples/todo.aup line for line, checks 9,600 TUI frames for scrolling,
focus, badge alignment and the number of cells evaluated, drives the
interactive TUI on a pseudo-terminal, and runs every aup example on every
surface.
|