Bindings for [[ Jimmy Lefevre's Text Shape ; https://github.com/JimmyLefevre/kb ]] Unicode text segmentation and OpenType shaping. Example: // Basic OdinAllocator := context.allocator FontData, _ := os.read_entire_file("myfonts.ttf", OdinAllocator) Context := kbts.CreateShapeContext(kbts.AllocatorFromOdinAllocator(&OdinAllocator)) kbts.ShapePushFontFromMemory(Context, FontData, 0) kbts.ShapeBegin(Context, .DONT_KNOW, .DONT_KNOW) kbts.ShapeUtf8(Context, "Let's shape something!", .CODEPOINT_INDEX) kbts.ShapeEnd(Context) CursorX, CursorY: c.int = 0, 0 for Run in kbts.ShapeRun(Context) { Run := Run for Glyph in kbts.GlyphIteratorNext(&Run.Glyphs) { GlyphX := CursorX + Glyph.OffsetX GlyphY := CursorY + Glyph.OffsetY DisplayGlyph(Glyph.Id, GlyphX, GlyphY) CursorX += Glyph.AdvanceX CursorY += Glyph.AdvanceY } } Example: // Font collections OdinAllocator := context.allocator FontData, _ := os.read_entire_file("myfonts.ttf", OdinAllocator) Font := kbts.FontFromMemory(FontData, 0, kbts.AllocatorFromOdinAllocator(&OdinAllocator)) _ = kbts.ShapePushFont(Context, &Font) FontCount := kbts.FontCount(FontData) for FontIndex in 1..<FontCount { kbts.ShapePushFontFromMemory(Context, FontData, FontIndex) } Example: kbts.ShapeBegin(Context, .DONT_KNOW, .DONT_KNOW) kbts.ShapePushFeature(Context, .kern, 0) kbts.ShapeUtf8(Context, "Without kerning", .CODEPOINT_INDEX) _ = kbts.ShapePopFeature(Context, .kern) kbts.ShapeUtf8(Context, "With kerning", .CODEPOINT_INDEX) kbts.ShapeEnd(Context)

Collection Info

View Source
Collection
vendor
Path
kb_text_shape
Entries
164

Source Files

Constants

20

BREAK_FLAG_ANY #

Source
BREAK_FLAG_ANY :: break_flags{.DIRECTION, .SCRIPT, .GRAPHEME, .WORD, .LINE_SOFT, .LINE_HARD}

BREAK_FLAG_DIRECTION #

Source
BREAK_FLAG_DIRECTION :: break_flags{.DIRECTION}

BREAK_FLAG_GRAPHEME #

Source
BREAK_FLAG_GRAPHEME :: break_flags{.GRAPHEME}

BREAK_FLAG_LINE #

Source
BREAK_FLAG_LINE :: break_flags{.LINE_SOFT, .LINE_HARD}

BREAK_FLAG_LINE_HARD #

Source
BREAK_FLAG_LINE_HARD :: break_flags{.LINE_HARD}

BREAK_FLAG_LINE_SOFT #

Source
BREAK_FLAG_LINE_SOFT :: break_flags{.LINE_SOFT}

BREAK_FLAG_PARAGRAPH_DIRECTION #

Source
BREAK_FLAG_PARAGRAPH_DIRECTION :: break_flags{.PARAGRAPH_DIRECTION}

MAXIMUM_RECOMPOSITION_PARENTS #

Source
MAXIMUM_RECOMPOSITION_PARENTS :: 19

UNICODE_FLAG_CLOSE_BRACKET #

Source
UNICODE_FLAG_CLOSE_BRACKET :: unicode_flags{.CLOSE_BRACKET}

UNICODE_FLAG_DECIMAL_DIGIT #

Source
UNICODE_FLAG_DECIMAL_DIGIT :: unicode_flags{.DECIMAL_DIGIT}

UNICODE_FLAG_DEFAULT_IGNORABLE #

Source
UNICODE_FLAG_DEFAULT_IGNORABLE :: unicode_flags{.DEFAULT_IGNORABLE}

UNICODE_FLAG_MIRRORED #

Source
UNICODE_FLAG_MIRRORED :: unicode_flags{.OPEN_BRACKET, .CLOSE_BRACKET}

UNICODE_FLAG_MODIFIER_COMBINING_MARK #

Source
UNICODE_FLAG_MODIFIER_COMBINING_MARK :: unicode_flags{.MODIFIER_COMBINING_MARK}

UNICODE_FLAG_NON_SPACING_MARK #

Source
UNICODE_FLAG_NON_SPACING_MARK :: unicode_flags{.NON_SPACING_MARK}

UNICODE_FLAG_OPEN_BRACKET #

Source
UNICODE_FLAG_OPEN_BRACKET :: unicode_flags{.OPEN_BRACKET}

UNICODE_FLAG_PART_OF_WORD #

Source
UNICODE_FLAG_PART_OF_WORD :: unicode_flags{.PART_OF_WORD}

Types

69

break_state #

Source
break_state :: break_state

In the worst case, a single call to BreakAddCodepoint would generate 4 breaks. We buffer breaks to reorder them before returning them to the user. This potentially requires infinite memory, which we don't have, so you may want to tweak this constant, although, really, if the defaults don't work, then you have likely found very strange/adversarial text.

japanese_line_break_style #

Source
japanese_line_break_style :: japanese_line_break_style

Japanese text contains "kinsoku" characters, around which breaking a line is forbidden. Exactly which characters are "kinsoku" or not depends on the context: - Strict style has the largest amount of kinsoku characters, which leads to longer lines. - Loose style has the smallest amount of kinsoku characters, which leads to smaller lines. - Normal style is somewhere in the middle. Note that, while the Unicode standard mentions all three of these styles, it does not mention any differences between the normal and loose styles. As such, normal and loose styles currently behave the same.

shaper #

Source
shaper :: shaper

Unicode defines scripts and languages. A language belongs to a single script, and a script belongs to a single writing system. On top of these, OpenType defines shapers, which are basically just designations for specific code paths that are taken depending on which script is being shapen. Some scripts, like Latin and Cyrillic, need relatively few operations, while complex scripts like Arabic and Indic scripts have specific processing steps that need to happen in order to obtain a correct result. These sequences of operations are _not_ described in the font file itself. The shaping code needs to know which script it is shaping, and implement all of those passes itself. That is why you, as a user, have to care about this. When creating shape_config, you can either pass in a known script, or you can specify SCRIPT_DONT_KNOW and let the library figure it out. While SCRIPT_DONT_KNOW may look appealing, it is worth noting that we can only infer the _script_, and not the language, of the text you pass in. This means that you might miss out on language-specific features when you use it.

Procedures

75

EncodeUtf8 #

Source
@(require_results)
EncodeUtf8 :: proc "c" (Codepoint: rune) -> (Encoded: [4]u8, EncodedLength: i32, Valid: b32) {…}

GuessTextProperties #

Source
@(require_results)
GuessTextProperties :: proc "contextless" (Text: []u8, Format: text_format) -> (Direction: direction, Script: script) {…}

This is a quick guess that stops at the first glyph that has a strong script/direction associated to it. It is convenient, but only works if you are sure your input text is mono-script and mono-direction.

GuessTextPropertiesUtf32 #

Source
@(require_results)
GuessTextPropertiesUtf32 :: proc "contextless" (Utf32: []rune) -> (Direction: direction, Script: script) {…}

This is a quick guess that stops at the first glyph that has a strong script/direction associated to it. It is convenient, but only works if you are sure your input text is mono-script and mono-direction.

GuessTextPropertiesUtf8 #

Source
@(require_results)
GuessTextPropertiesUtf8 :: proc "contextless" (Utf8: string) -> (Direction: direction, Script: script) {…}

This is a quick guess that stops at the first glyph that has a strong script/direction associated to it. It is convenient, but only works if you are sure your input text is mono-script and mono-direction._results)

SizeOfShapeConfig #

Source
SizeOfShapeConfig :: proc "c" (Font: ^font, Script: script, Language: language) -> b32 ---

A shape_config is a bag of pre-computed data for a specific shaping setup.