Merge pull request #6000 from odin-lang/bill/kb_text_shape_2

Update kb_text_shape to v2.03
This commit is contained in:
gingerBill
2025-12-08 13:28:36 +00:00
committed by GitHub
5 changed files with 15885 additions and 9881 deletions

57
vendor/kb_text_shape/doc.odin vendored Normal file
View File

@@ -0,0 +1,57 @@
/*
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)
*/
package vendor_kb_text_shape

View File

@@ -1,4 +1,3 @@
// Bindings for [[ Jimmy Lefevre's Text Shape ; https://github.com/JimmyLefevre/kb ]] Unicode text segmentation and OpenType shaping.
package vendor_kb_text_shape
when ODIN_OS == .Windows {
@@ -11,175 +10,391 @@ when ODIN_OS == .Windows {
}
}
import "core:mem"
import "base:runtime"
import "core:c"
//
// Context API
// The context can do everything for you. It is pretty convenient!
//
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
SizeOfShapeContext :: proc() -> c.int ---
PlaceShapeContext :: proc(Allocator: allocator_function, AllocatorData: rawptr, Memory: rawptr) -> ^shape_context ---
CreateShapeContext :: proc(Allocator: allocator_function, AllocatorData: rawptr) -> ^shape_context ---
DestroyShapeContext :: proc(Context: ^shape_context) ---
ShapePushFont :: proc(Context: ^shape_context, Font: ^font) -> ^font ---
ShapePopFont :: proc(Context: ^shape_context) -> ^font ---
ShapeBegin :: proc(Context: ^shape_context, ParagraphDirection: direction, Language: language) ---
ShapeEnd :: proc(Context: ^shape_context) ---
ShapePushFeature :: proc(Context: ^shape_context, FeatureTag: feature_tag, Value: c.int) ---
ShapePopFeature :: proc(Context: ^shape_context, FeatureTag: feature_tag) -> b32 ---
ShapeCodepoint :: proc(Context: ^shape_context, Codepoint: rune) ---
ShapeCodepointWithUserId :: proc(Context: ^shape_context, Codepoint: rune, UserId: c.int) ---
ShapeError :: proc(Context: ^shape_context) -> shape_error ---
ShapeBeginManualRuns :: proc(Context: ^shape_context) ---
ShapeNextManualRun :: proc(Context: ^shape_context, Direction: direction, Script: script) ---
ShapeEndManualRuns :: proc(Context: ^shape_context) ---
ShapeManualBreak :: proc(Context: ^shape_context) ---
}
@(require_results)
PlaceShapeContextFixedMemory :: proc "c" (Memory: []byte) -> ^shape_context {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_PlaceShapeContextFixedMemory :: proc(Memory: rawptr, Size: c.int) -> ^shape_context ---
}
return kbts_PlaceShapeContextFixedMemory(raw_data(Memory), c.int(len(Memory)))
}
ShapePushFontFromMemory :: proc "c" (Context: ^shape_context, Memory: []byte, FontIndex: c.int) -> ^font {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ShapePushFontFromMemory :: proc(Context: ^shape_context, Memory: rawptr, Size: c.int, FontIndex: c.int) -> ^font ---
}
return kbts_ShapePushFontFromMemory(Context, raw_data(Memory), c.int(len(Memory)), FontIndex)
}
@(require_results)
ShapeRun :: proc "contextless" (Context: ^shape_context) -> (Run: run, Ok: b32) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ShapeRun :: proc(Context: ^shape_context, Run: ^run) -> b32 ---
}
Ok = kbts_ShapeRun(Context, &Run)
return
}
ShapeUtf32 :: proc "c" (Context: ^shape_context, Utf32: []rune) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ShapeUtf32 :: proc(Context: ^shape_context, Utf32: [^]rune, Length: c.int) ---
}
kbts_ShapeUtf32(Context, raw_data(Utf32), c.int(len(Utf32)))
}
ShapeUtf32WithUserId :: proc "c" (Context: ^shape_context, Utf32: []rune, UserId: c.int, UserIdIncrement: c.int) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ShapeUtf32WithUserId :: proc(Context: ^shape_context, Utf32: [^]rune, Length: c.int, UserId: c.int, UserIdIncrement: c.int) ---
}
kbts_ShapeUtf32WithUserId(Context, raw_data(Utf32), c.int(len(Utf32)), UserId, UserIdIncrement)
}
ShapeUtf8 :: proc(Context: ^shape_context, Utf8: string, UserIdGenerationMode: user_id_generation_mode) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ShapeUtf8 :: proc(Context: ^shape_context, Utf8: [^]byte, Length: c.int, UserIdGenerationMode: user_id_generation_mode) ---
}
kbts_ShapeUtf8(Context, raw_data(Utf8), c.int(len(Utf8)), UserIdGenerationMode)
}
ShapeUtf8WithUserId :: proc(Context: ^shape_context, Utf8: string, UserId: c.int, UserIdGenerationMode: user_id_generation_mode) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ShapeUtf8WithUserId :: proc(Context: ^shape_context, Utf8: [^]byte, Length: c.int, UserId: c.int, UserIdGenerationMode: user_id_generation_mode) ---
}
kbts_ShapeUtf8WithUserId(Context, raw_data(Utf8), c.int(len(Utf8)), UserId, UserIdGenerationMode)
}
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
FeatureTagToId :: proc(Tag: feature_tag) -> feature_id ---
FeatureOverride :: proc(Id: feature_id, Alternate: b32, Value: u32) -> feature_override ---
FeatureOverrideFromTag :: proc(Tag: feature_tag, Alternate: b32, Value: u32) -> feature_override ---
GlyphConfigOverrideFeature :: proc(Config: ^glyph_config, Id: feature_id, Alternate: b32, Value: u32) -> b32 ---
GlyphConfigOverrideFeatureFromTag :: proc(Config: ^glyph_config, Tag: feature_tag, Alternate: b32, Value: u32) -> b32 ---
ShapeCurrentCodepointsIterator :: proc(Context: ^shape_context) -> shape_codepoint_iterator ---
ShapeCodepointIteratorIsValid :: proc(It: ^shape_codepoint_iterator) -> b32 ---
ShapeGetShapeCodepoint :: proc(Context: ^shape_context, CodepointIndex: c.int, Codepoint: ^shape_codepoint) -> b32 ---
}
FontIsValid :: proc(Font: ^font) -> b32 ---
SizeOfShapeState :: proc(Font: ^font) -> un ---
@(require_results)
ShapeCodepointIteratorNext :: proc "contextless" (It: ^shape_codepoint_iterator) -> (Codepoint: shape_codepoint, CodepointIndex: c.int, Ok: b32) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ShapeCodepointIteratorNext :: proc(It: ^shape_codepoint_iterator, Codepoint: ^shape_codepoint, CodepointIndex: ^c.int) -> b32 ---
}
Ok = kbts_ShapeCodepointIteratorNext(It, &Codepoint, &CodepointIndex)
return
}
ResetShapeState :: proc(State: ^shape_state) ---
ShapeConfig :: proc(Font: ^font, Script: script, Language: language) -> shape_config ---
ShaperIsComplex :: proc(Shaper: shaper) -> b32 ---
//
// Direct API
//
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
FreeFont :: proc(Font: ^font) ---
FontIsValid :: proc(Font: ^font) -> b32 ---
PlaceBlob :: proc(Font: ^font, State: ^load_font_state, ScratchMemory: rawptr, OutputMemory: rawptr) -> load_font_error ---
GetFontInfo :: proc(Font: ^font, Info: ^font_info) ---
// A shape_config is a bag of pre-computed data for a specific shaping setup.
SizeOfShapeConfig :: proc(Font: ^font, Script: script, Language: language) -> b32 ---
PlaceShapeConfig :: proc(Font: ^font, Script: script, Language: language, Memory: rawptr) -> ^shape_config ---
CreateShapeConfig :: proc(Font: ^font, Script: script, Language: language, Allocator: allocator_function, AllocatorData: rawptr) -> ^shape_config ---
DestroyShapeConfig :: proc(Config: ^shape_config) ---
// A glyph_storage holds and recycles glyph data.
InitializeGlyphStorage :: proc(Storage: ^glyph_storage, Allocator: allocator_function, AllocatorData: rawptr) -> b32 ---
InitializeGlyphStorageFixedMemory :: proc(Storage: ^glyph_storage, Memory: rawptr, MemorySize: c.int) -> b32 ---
PushGlyph :: proc(Storage: ^glyph_storage, Font: ^font, Codepoint: rune, Config: ^glyph_config, UserId: c.int) -> ^glyph ---
ClearActiveGlyphs :: proc(Storage: ^glyph_storage) ---
FreeAllGlyphs :: proc(Storage: ^glyph_storage) ---
CodepointToGlyph :: proc(Font: ^font, Codepoint: rune, Config: ^glyph_config, UserId: c.int) -> glyph ---
CodepointToGlyphId :: proc(Font: ^font, Codepoint: rune) -> c.int ---
ActiveGlyphIterator :: proc(Storage: ^glyph_storage) -> glyph_iterator ---
// A glyph_config specifies glyph-specific shaping parameters.
// A single glyph_config can be shared by multiple glyphs.
DestroyGlyphConfig :: proc(Config: ^glyph_config) ---
}
@(require_results)
LoadFont :: proc "contextless" (Font: ^font, State: ^load_font_state, FontData: []byte, FontIndex: c.int) -> (ScratchSize, OutputSize: c.int, Err: load_font_error) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_LoadFont :: proc(Font: ^font, State: ^load_font_state, FontData: rawptr, FontDataSize: c.int, FontIndex: c.int, ScratchSize_: ^c.int, OutputSize_: ^c.int) -> load_font_error ---
}
Err = kbts_LoadFont(Font, State, raw_data(FontData), c.int(len(FontData)), FontIndex, &ScratchSize, &OutputSize)
return
}
@(require_results)
FontCount :: proc "c" (FileData: []byte) -> c.int {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_FontCount :: proc(FileData: rawptr, FileSize: c.int) -> c.int ---
}
return kbts_FontCount(raw_data(FileData), c.int(len(FileData)))
}
@(require_results)
FontFromMemory :: proc "c" (FileData: []byte, FontIndex: c.int, Allocator: allocator_function, AllocatorData: rawptr) -> font {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_FontFromMemory :: proc(FileData: rawptr, FileSize: c.int, FontIndex: c.int, Allocator: allocator_function, AllocatorData: rawptr) -> font ---
}
return kbts_FontFromMemory(raw_data(FileData), c.int(len(FileData)), FontIndex, Allocator, AllocatorData)
}
@(require_results)
ShapeDirect :: proc "contextless" (Config: ^shape_config, Storage: ^glyph_storage, RunDirection: direction, Allocator: allocator_function, AllocatorData: rawptr) -> (Output: glyph_iterator, Err: shape_error) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ShapeDirect :: proc(Config: ^shape_config, Storage: ^glyph_storage, RunDirection: direction, Allocator: allocator_function, AllocatorData: rawptr, Output: ^glyph_iterator) -> shape_error ---
}
Err = kbts_ShapeDirect(Config, Storage, RunDirection, Allocator, AllocatorData, &Output)
return
}
@(require_results)
ShapeDirectFixedMemory :: proc "contextless" (Config: ^shape_config, Storage: ^glyph_storage, RunDirection: direction, Memory: rawptr, MemorySize: c.int) -> (Output: glyph_iterator, Err: shape_error) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ShapeDirectFixedMemory :: proc(Config: ^shape_config, Storage: ^glyph_storage, RunDirection: direction, Memory: rawptr, MemorySize: c.int, Output: ^glyph_iterator) -> shape_error ---
}
Err = kbts_ShapeDirectFixedMemory(Config, Storage, RunDirection, Memory, MemorySize, &Output)
return
}
@(require_results)
SizeOfGlyphConfig :: proc "c" (Overrides: []feature_override) -> c.int {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_SizeOfGlyphConfig :: proc(Overrides: [^]feature_override, OverrideCount: c.int) -> c.int ---
}
return kbts_SizeOfGlyphConfig(raw_data(Overrides), c.int(len(Overrides)))
}
@(require_results)
PlaceGlyphConfig :: proc "c" (Overrides: []feature_override, Memory: rawptr) -> ^glyph_config {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_PlaceGlyphConfig :: proc(Overrides: [^]feature_override, OverrideCount: c.int, Memory: rawptr) -> ^glyph_config ---
}
return kbts_PlaceGlyphConfig(raw_data(Overrides), c.int(len(Overrides)), Memory)
}
@(require_results)
CreateGlyphConfig :: proc(Overrides: []feature_override, Allocator: allocator_function, AllocatorData: rawptr) -> ^glyph_config {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_CreateGlyphConfig :: proc(Overrides: [^]feature_override, OverrideCount: c.int, Allocator: allocator_function, AllocatorData: rawptr) -> ^glyph_config ---
}
return kbts_CreateGlyphConfig(raw_data(Overrides), c.int(len(Overrides)), Allocator, AllocatorData)
}
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
GlyphIteratorIsValid :: proc(It: ^glyph_iterator) -> b32 ---
}
@(require_results)
GlyphIteratorNext :: proc "contextless" (It: ^glyph_iterator) -> (Glyph: ^glyph, Ok: b32) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_GlyphIteratorNext :: proc(It: ^glyph_iterator, Glyph: ^^glyph) -> b32 ---
}
Ok = kbts_GlyphIteratorNext(It, &Glyph)
return
}
//
// Segmentation
//
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
BreakBegin :: proc(State: ^break_state, ParagraphDirection: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags) ---
BreakAddCodepoint :: proc(State: ^break_state, Codepoint: rune, PositionIncrement: c.int, EndOfText: c.int) ---
BreakEnd :: proc(State: ^break_state) ---
}
@(require_results)
Break :: proc "contextless" (State: ^break_state) -> (Break: break_type, Ok: b32) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_Break :: proc(State: ^break_state, Break: ^break_type) -> b32 ---
}
Ok = kbts_Break(State, &Break)
return
}
BreakEntireString :: proc "c" (Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags,
Input: []byte, InputFormat: text_format,
Breaks: []break_type, BreakCount: ^c.int,
BreakFlags: []break_flags, BreakFlagCount: ^c.int) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_BreakEntireString :: proc(Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags,
Input: rawptr, InputSizeInBytes: c.int, InputFormat: text_format,
Breaks: [^]break_type, BreakCapacity: c.int, BreakCount: ^c.int,
BreakFlags: [^]break_flags, BreakFlagCapacity: c.int, BreakFlagCount: ^c.int) ---
}
kbts_BreakEntireString(Direction, JapaneseLineBreakStyle, ConfigFlags, raw_data(Input), c.int(len(Input)), InputFormat, raw_data(Breaks), c.int(len(Breaks)), BreakCount, raw_data(BreakFlags), c.int(len(BreakFlags)), BreakFlagCount)
}
BreakEntireStringUtf32 :: proc "c" (Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags,
Utf32: []rune,
Breaks: []break_type, BreakCount: ^c.int,
BreakFlags: []break_flags, BreakFlagCount: ^c.int) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_BreakEntireStringUtf32 :: proc(Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags,
Utf32: [^]rune, Utf32Count: c.int,
Breaks: [^]break_type, BreakCapacity: c.int, BreakCount: ^c.int,
BreakFlags: [^]break_flags, BreakFlagCapacity: c.int, BreakFlagCount: ^c.int) ---
}
kbts_BreakEntireStringUtf32(Direction, JapaneseLineBreakStyle, ConfigFlags, raw_data(Utf32), c.int(len(Utf32)), raw_data(Breaks), c.int(len(Breaks)), BreakCount, raw_data(BreakFlags), c.int(len(BreakFlags)), BreakFlagCount)
}
BreakEntireStringUtf8 :: proc "c" (Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags,
Utf8: string,
Breaks: []break_type, BreakCount: ^c.int,
BreakFlags: []break_flags, BreakFlagCount: ^c.int) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_BreakEntireStringUtf8 :: proc(Direction: direction, JapaneseLineBreakStyle: japanese_line_break_style, ConfigFlags: break_config_flags,
Utf8: [^]byte, Utf8Length: c.int,
Breaks: [^]break_type, BreakCapacity: c.int, BreakCount: ^c.int,
BreakFlags: [^]break_flags, BreakFlagCapacity: c.int, BreakFlagCount: ^c.int) ---
}
kbts_BreakEntireStringUtf8(Direction, JapaneseLineBreakStyle, ConfigFlags, raw_data(Utf8), c.int(len(Utf8)), raw_data(Breaks), c.int(len(Breaks)), BreakCount, raw_data(BreakFlags), c.int(len(BreakFlags)), BreakFlagCount)
}
@(default_calling_convention="c", link_prefix="kbts_", require_results)
foreign lib {
// Quick test for font support of a sequence of codepoints.
FontCoverageTestBegin :: proc(Test: ^font_coverage_test, Font: ^font) ---
FontCoverageTestCodepoint :: proc(Test: ^font_coverage_test, Codepoint: rune) ---
FontCoverageTestEnd :: proc(Test: ^font_coverage_test) -> b32 ---
ScriptDirection :: proc(Script: script) -> direction ---
ScriptIsComplex :: proc(Script: script) -> b32 ---
ScriptTagToScript :: proc(Tag: script_tag) -> script ---
Shape :: proc(State: ^shape_state, Config: ^shape_config,
MainDirection, RunDirection: direction,
Glyphs: [^]glyph, GlyphCount: ^u32, GlyphCapacity: u32) -> b32 ---
Cursor :: proc(Direction: direction) -> cursor ---
BeginBreak :: proc(State: ^break_state, MainDirection: direction, JapaneseLineBreakStyle: japanese_line_break_style) ---
BreakStateIsValid :: proc(State: ^break_state) -> b32 ---
BreakAddCodepoint :: proc(State: ^break_state, Codepoint: rune, PositionIncrement: u32, EndOfText: b32) ---
BreakFlush :: proc(State: ^break_state) ---
Break :: proc(State: ^break_state, Break: ^break_type) -> b32 ---
CodepointToGlyph :: proc(Font: ^font, Codepoint: rune) -> glyph ---
InferScript :: proc(Direction: ^direction, Script: ^script, GlyphScript: script) ---
}
@(require_results)
GlyphConfig :: proc "c" (FeatureOverrides: []feature_override) -> glyph_config {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_GlyphConfig :: proc(FeatureOverrides: [^]feature_override, FeatureOverrideCount: u32) -> glyph_config ---
}
return kbts_GlyphConfig(raw_data(FeatureOverrides), u32(len(FeatureOverrides)))
}
@(require_results)
EmptyGlyphConfig :: proc(FeatureOverrides: []feature_override) -> glyph_config {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_EmptyGlyphConfig :: proc(FeatureOverrides: [^]feature_override, FeatureOverrideCapacity: u32) -> glyph_config ---
}
return kbts_EmptyGlyphConfig(raw_data(FeatureOverrides), u32(len(FeatureOverrides)))
EncodeUtf8 :: proc "c" (Codepoint: rune) -> (Encoded: [4]u8, EncodedLength: c.int, Valid: b32) {
return expand_values(kbts_EncodeUtf8(Codepoint))
}
@(default_calling_convention="c", require_results)
foreign lib {
kbts_EncodeUtf8 :: proc(Codepoint: rune) -> encode_utf8 ---
}
@(require_results)
PlaceShapeState :: proc "c" (Memory: []byte) -> ^shape_state {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_PlaceShapeState :: proc(Address: rawptr, Size: un) -> ^shape_state ---
}
return kbts_PlaceShapeState(raw_data(Memory), un(len(Memory)))
}
@(require_results)
DecodeUtf8 :: proc "contextless" (String: string) -> (Codepoint: rune, SourceCharactersConsumed: u32, Valid: bool) {
decode :: struct {
Codepoint: rune,
SourceCharactersConsumed: u32,
Valid: b32,
}
DecodeUtf8 :: proc "c" (Utf8: string) -> decode {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_DecodeUtf8 :: proc(Utf8: [^]byte, Length: un) -> decode ---
}
Decode := kbts_DecodeUtf8(raw_data(String), un(len(String)))
return Decode.Codepoint, Decode.SourceCharactersConsumed, bool(Decode.Valid)
return kbts_DecodeUtf8(raw_data(Utf8), un(len(Utf8)))
}
// 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.
@(require_results)
ReadFontHeader :: proc "c" (Font: ^font, Data: []byte) -> un {
GuessTextProperties :: proc "contextless" (Text: []byte, Format: text_format) -> (Direction: direction, Script: script) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ReadFontHeader :: proc(Font: ^font, Data: rawptr, Size: un) -> un ---
kbts_GuessTextProperties :: proc(Text: rawptr, TextSizeInBytes: c.int, Format: text_format, Direction: ^direction, Script: ^script) ---
}
return kbts_ReadFontHeader(Font, raw_data(Data), un(len(Data)))
}
@(require_results)
ReadFontData :: proc "c" (Font: ^font, Scratch: []byte) -> un {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_ReadFontData :: proc(Font: ^font, Scratch: rawptr, ScratchSize: un) -> un ---
}
return kbts_ReadFontData(Font, raw_data(Scratch), un(len(Scratch)))
}
@(require_results)
PostReadFontInitialize :: proc "c" (Font: ^font, Memory: []byte) -> b32 {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_PostReadFontInitialize :: proc(Font: ^font, Memory: rawptr, MemorySize: un) -> b32 ---
}
return kbts_PostReadFontInitialize(Font, raw_data(Memory), un(len(Memory)))
}
@(require_results)
FontFromMemory :: proc(Data: []byte, allocator: mem.Allocator) -> (Result: font, Err: mem.Allocator_Error) {
ClonedData := mem.make_aligned([]byte, len(Data), 16, allocator) or_return
defer if Err != nil {
delete(ClonedData, allocator)
}
copy(ClonedData, Data)
ScratchSize := ReadFontHeader(&Result, ClonedData)
Scratch := mem.make_aligned([]byte, ScratchSize, 16, allocator) or_return
MemorySize := ReadFontData(&Result, Scratch)
Memory := Scratch
if MemorySize > ScratchSize {
delete(Scratch, allocator)
Memory = mem.make_aligned([]byte, MemorySize, 16, allocator) or_return
}
defer if Err != nil {
delete(Memory, allocator)
}
_ = PostReadFontInitialize(&Result, Memory)
return
}
FreeFont :: proc(Font: ^font, allocator: mem.Allocator) {
free(Font.FileBase, allocator)
free(Font.GlyphLookupMatrix, allocator)
Font^ = {}
}
@(require_results)
CreateShapeState :: proc(Font: ^font, allocator: mem.Allocator) -> (Result: ^shape_state, Err: mem.Allocator_Error) {
Size := SizeOfShapeState(Font)
Memory := mem.make_aligned([]byte, Size, 16, allocator) or_return
Result = PlaceShapeState(Memory)
return
}
FreeShapeState :: proc(State: ^shape_state, allocator: mem.Allocator) {
free(State, allocator)
}
@(require_results)
PositionGlyph :: proc(Cursor: ^cursor, Glyph: ^glyph) -> (X, Y: i32) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_PositionGlyph :: proc(Cursor: ^cursor, Glyph: ^glyph, X, Y: ^i32) ---
}
kbts_PositionGlyph(Cursor, Glyph, &X, &Y)
kbts_GuessTextProperties(raw_data(Text), c.int(len(Text)), Format, &Direction, &Script)
return
}
// 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.
@(require_results)
ShapeDynamic :: proc(State: ^shape_state, Config: ^shape_config,
MainDirection, RunDirection: direction,
Glyphs: ^[dynamic]glyph) -> b32 {
GlyphCount := u32(len(Glyphs^))
GlyphCapacity := u32(cap(Glyphs^))
Res := Shape(State, Config, MainDirection, RunDirection, raw_data(Glyphs^), &GlyphCount, GlyphCapacity)
resize(Glyphs, int(GlyphCount))
return Res
}
GuessTextPropertiesUtf32 :: proc "contextless" (Utf32: []rune) -> (Direction: direction, Script: script) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_GuessTextPropertiesUtf32 :: proc(Utf32: [^]rune, Utf32Count: c.int, Direction: ^direction, Script: ^script) ---
}
kbts_GuessTextPropertiesUtf32(raw_data(Utf32), c.int(len(Utf32)), &Direction, &Script)
return
}
// 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)
@(require_results)
GuessTextPropertiesUtf8 :: proc "contextless" (Utf8: string) -> (Direction: direction, Script: script) {
@(default_calling_convention="c", require_results)
foreign lib {
kbts_GuessTextPropertiesUtf8 :: proc(Utf8: cstring, Utf8Length: c.int, Direction: ^direction, Script: ^script) ---
}
kbts_GuessTextPropertiesUtf8(cstring(raw_data(Utf8)), c.int(len(Utf8)), &Direction, &Script)
return
}
@(require_results)
AllocatorFromOdinAllocator :: proc "contextless" (allocator: ^runtime.Allocator) -> (Allocator: allocator_function, AllocatorData: rawptr) {
allocator_function :: proc "c" (Data: rawptr, Op: ^allocator_op) {
if Data == nil {
return
}
context = runtime.default_context()
context.allocator = (^runtime.Allocator)(Data)^
switch Op.Kind {
case .NONE:
return
case .ALLOCATE:
res, _ := runtime.mem_alloc(int(Op.Allocate.Size), runtime.DEFAULT_ALIGNMENT)
Op.Allocate.Pointer = raw_data(res)
Op.Allocate.Size = u32(len(res))
case .FREE:
_ = runtime.mem_free(Op.Free.Pointer)
}
}
return allocator_function, rawptr(allocator)
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff