SlopTube

Text rendering#

YouTube titles, channel names and comments arrive in every script, often mixed in one string (an Arabic title with Latin words and digits, a Korean title with emoji). Dear ImGui draws one glyph per code point, left to right, so SlopTube adds font fallback, Arabic shaping and bidirectional reordering on top of it. Glyphs are rasterised by FreeType (imgui_freetype). The code is in src/app/ui/Fonts.* and src/app/ui/text/.

Fonts (ui/Fonts.cpp)#

loadFonts() builds one face per Weight (Regular, Medium, SemiBold, Bold: Roboto's 400, 500, 600 and 700, the weights the official app uses), each with the same chain of fallbacks merged in:

  1. Roboto (the system UI font), then colour emoji (below), then the NotoSansSymbols files;
  2. Arabic (NotoNaskhArabicUI), Hebrew, CJK, Korean;
  3. one font for every other script found in /system/fonts (Devanagari, Thai, …).

Colour emoji#

ImGui's rasteriser cannot read colour fonts (CBDT/sbix), so emoji come from Android itself. A custom ImFontLoader (emojiLoader in Fonts.cpp), merged right after Roboto, claims the emoji blocks (U+2300–23FF, U+2600–27BF, U+2B00–2BFF, U+1F000–1FAFF) when the system can draw them (Paint.hasGlyph). Each glyph is drawn on demand by Platform::drawGlyph (JNI: Paint, Canvas, Bitmap) at the text's size, as everywhere else on the phone, then copied into ImGui's RGBA atlas as a coloured glyph (ImFontGlyph::Colored, so text colour does not tint it). Glyphs are baked once per size, like any other.

Coming before the symbol fonts, it also draws in colour the pictographs they carry (hearts, stars), as everywhere else on the phone. Sequence controls (zero-width joiner, variation selectors, skin-tone modifiers, tags) take no space.

Cost on the Galaxy A14:

Item Measured
Font loading 4–14 ms
Mapped font files about 1.5 MB
APK size +0.3 MB

Typography#

Sizes and weights were measured on screenshots of the official app on the same phone: the ink box and the inked area of each text were compared with Roboto rendered at every candidate size and weight. They live in Theme.hpp:

Role Size Weight
Channel name (search card, channel page, You) 24 sp Bold
Sheet title (comments, description, accounts, save, download) 20 sp Bold
Section header (Shorts shelf, You, channel shelves), watch title 18 sp Bold
Card title 16 sp SemiBold
Shelf and Shorts tile title, post video title 14 sp SemiBold
Buttons, chips, names, "N replies" 14 sp Medium
Comment text, post text 14 sp Regular
Metadata under a card title, duration badge 12 sp Medium
Other metadata (handles, views, dates) 12 sp Regular
Navigation labels 10 sp Regular

The same measurements on SlopTube's screens give the same sizes and weights.

Pipeline (ui/text/)#

File Role
Utf8.hpp Decoding and encoding helpers
UnicodeTables.* Compact generated tables (≈5 KB): bidi classes, Arabic joining types, mirrored brackets. Regenerate with generate_tables.py (Python's unicodedata, no downloads)
Shaping.* Arabic contextual forms (isolated, initial, medial, final) through the presentation-form blocks; lam-alef ligatures; transparent marks (harakat) are skipped when joining
Bidi.* A pragmatic subset of the Unicode Bidirectional Algorithm: paragraph direction from the first strong character, RTL runs, European and Arabic numbers kept left to right, neutrals resolved from their neighbours, mirrored brackets
TextLayout.* Line breaking on the logical text, then shaping and reordering per line, with a 128-entry cache

Strings without right-to-left characters take a fast path that skips everything above. Once cached, a string costs nothing; its first appearance costs tens to a few hundred microseconds, mostly ImGui rasterising new glyphs.

Canvas API#

Known limitations#

Edit this page on GitHub