Text metrics API #88

Merged
MartinFouilleul merged 1 commits from text_metrics into main 2023-09-10 17:29:32 +00:00
6 changed files with 191 additions and 141 deletions
Showing only changes of commit 5cdded57b3 - Show all commits

View File

@ -416,11 +416,11 @@ ORCA_EXPORT void oc_on_frame_refresh(void)
int fontSize = 18;
oc_str8 text = oc_str8_pushf(oc_scratch(), "%d", blockHealth[i]);
oc_rect textRect = oc_text_bounding_box(font, fontSize, text);
oc_rect textRect = oc_font_text_metrics(font, fontSize, text).ink;
oc_vec2 textPos = {
r.x + r.w / 2 - textRect.w / 2,
r.y + 9, // TODO: oc_text_bounding_box is returning extremely wack results for height.
r.x + r.w / 2 - textRect.w / 2 - textRect.x,
r.y + r.h / 2 - textRect.h / 2 - textRect.y - textRect.h, //NOTE: we render with y-up so we need to flip bounding box coordinates.
};
oc_set_color_rgba(0.9, 0.9, 0.9, 1);
@ -449,10 +449,9 @@ ORCA_EXPORT void oc_on_frame_refresh(void)
// draw score text
{
oc_move_to(10, 10);
oc_move_to(20, 20);
oc_str8 text = oc_str8_pushf(oc_scratch(), "Destroy all %d blocks to win! Current score: %d", NUM_BLOCKS_TO_WIN, score);
oc_rect textRect = oc_text_bounding_box(font, 20, text);
oc_vec2 textPos = { 10, 10 };
oc_vec2 textPos = { 20, 20 };
oc_matrix_push(flip_y_at(textPos));
{
oc_set_color_rgba(0.9, 0.9, 0.9, 1);

View File

@ -94,11 +94,13 @@ ORCA_EXPORT void oc_on_frame_refresh(void)
// clock face
for(int i = 0; i < oc_array_size(clockNumberStrings); ++i)
{
oc_rect textRect = oc_text_bounding_box(font, fontSize, clockNumberStrings[i]);
textRect.h -= 10 * uiScale; // oc_text_bounding_box height doesn't seem to be a tight fit around the glyph
oc_rect textRect = oc_font_text_metrics(font, fontSize, clockNumberStrings[i]).ink;
const f32 angle = i * ((M_PI * 2) / 12.0f) - (M_PI / 2);
oc_mat2x3 transform = mat_transform(centerX - (textRect.w / 2), centerY + (textRect.h / 2), angle);
oc_mat2x3 transform = mat_transform(centerX - (textRect.w / 2) - textRect.x,
centerY - (textRect.h / 2) - textRect.y,
angle);
oc_vec2 pos = oc_mat2x3_mul(transform, (oc_vec2){ clockRadius * 0.8f, 0 });
oc_set_color_rgba(0.2, 0.2, 0.2, 1);

View File

@ -118,15 +118,15 @@ int main()
create_font("../../resources/CMUSerif-Roman.ttf"),
create_font("../../resources/Courier.ttf") };
oc_font_extents extents[FONT_COUNT];
oc_font_metrics extents[FONT_COUNT];
f32 fontScales[FONT_COUNT];
f32 lineHeights[FONT_COUNT];
for(int i = 0; i < FONT_COUNT; i++)
{
extents[i] = oc_font_get_extents(fonts[i]);
extents[i] = oc_font_get_metrics_unscaled(fonts[i]);
fontScales[i] = oc_font_get_scale_for_em_pixels(fonts[i], 14);
lineHeights[i] = fontScales[i] * (extents[i].ascent + extents[i].descent + extents[i].leading);
lineHeights[i] = fontScales[i] * (extents[i].ascent + extents[i].descent + extents[i].lineGap);
}
int codePointCount = oc_utf8_codepoint_count_for_string(OC_STR8((char*)TEST_STRING));

View File

@ -185,27 +185,30 @@ typedef enum
OC_CAP_SQUARE
} oc_cap_type;
typedef struct oc_font_extents
typedef struct oc_font_metrics
{
f32 ascent; // the extent above the baseline (by convention a positive value extends above the baseline)
f32 descent; // the extent below the baseline (by convention, positive value extends below the baseline)
f32 leading; // spacing between one row's descent and the next row's ascent
f32 lineGap; // spacing between one row's descent and the next row's ascent
f32 xHeight; // height of the lower case letter 'x'
f32 capHeight; // height of the upper case letter 'M'
f32 width; // maximum width of the font
} oc_font_extents;
} oc_font_metrics;
typedef struct oc_text_extents
typedef struct oc_glyph_metrics
{
f32 xBearing;
f32 yBearing;
f32 width;
f32 height;
f32 xAdvance;
f32 yAdvance;
oc_rect ink;
oc_vec2 advance;
} oc_glyph_metrics;
} oc_text_extents;
typedef struct oc_text_metrics
{
oc_rect ink;
oc_rect logical;
oc_vec2 advance;
} oc_text_metrics;
//------------------------------------------------------------------------------------------
//SECTION: graphics canvas
@ -222,32 +225,25 @@ ORCA_API void oc_render(oc_canvas canvas); //DOC: renders all canvas
//SECTION: fonts
//------------------------------------------------------------------------------------------
ORCA_API oc_font oc_font_nil(void);
ORCA_API bool oc_font_is_nil(oc_font font);
ORCA_API oc_font oc_font_create_from_memory(oc_str8 mem, u32 rangeCount, oc_unicode_range* ranges);
ORCA_API oc_font oc_font_create_from_file(oc_file file, u32 rangeCount, oc_unicode_range* ranges);
ORCA_API oc_font oc_font_create_from_path(oc_str8 path, u32 rangeCount, oc_unicode_range* ranges);
ORCA_API void oc_font_destroy(oc_font font);
//NOTE(martin): the following int valued functions return -1 if font is invalid or codepoint is not present in font//
//TODO(martin): add enum error codes
ORCA_API oc_font_extents oc_font_get_extents(oc_font font);
ORCA_API oc_font_extents oc_font_get_scaled_extents(oc_font font, f32 emSize);
ORCA_API f32 oc_font_get_scale_for_em_pixels(oc_font font, f32 emSize);
//NOTE(martin): if you need to process more than one codepoint, first convert your codepoints to glyph indices, then use the
// glyph index versions of the functions, which can take an array of glyph indices.
ORCA_API oc_str32 oc_font_get_glyph_indices(oc_font font, oc_str32 codePoints, oc_str32 backing);
ORCA_API oc_str32 oc_font_push_glyph_indices(oc_font font, oc_arena* arena, oc_str32 codePoints);
ORCA_API u32 oc_font_get_glyph_index(oc_font font, oc_utf32 codePoint);
ORCA_API int oc_font_get_codepoint_extents(oc_font font, oc_utf32 codePoint, oc_text_extents* outExtents);
// metrics
ORCA_API oc_font_metrics oc_font_get_metrics(oc_font font, f32 emSize);
ORCA_API oc_font_metrics oc_font_get_metrics_unscaled(oc_font font);
ORCA_API f32 oc_font_get_scale_for_em_pixels(oc_font font, f32 emSize);
ORCA_API int oc_font_get_glyph_extents(oc_font font, oc_str32 glyphIndices, oc_text_extents* outExtents);
ORCA_API oc_rect oc_text_bounding_box_utf32(oc_font font, f32 fontSize, oc_str32 text);
ORCA_API oc_rect oc_text_bounding_box(oc_font font, f32 fontSize, oc_str8 text);
ORCA_API oc_text_metrics oc_font_text_metrics_utf32(oc_font font, f32 fontSize, oc_str32 codepoints);
ORCA_API oc_text_metrics oc_font_text_metrics(oc_font font, f32 fontSize, oc_str8 text);
//------------------------------------------------------------------------------------------
//SECTION: images

View File

@ -37,7 +37,7 @@ typedef struct oc_glyph_data
bool exists;
oc_utf32 codePoint;
oc_path_descriptor pathDescriptor;
oc_text_extents extents;
oc_glyph_metrics metrics;
//...
} oc_glyph_data;
@ -62,7 +62,7 @@ typedef struct oc_font_data
oc_path_elt* outlines;
f32 unitsPerEm;
oc_font_extents extents;
oc_font_metrics metrics;
} oc_font_data;
@ -398,16 +398,16 @@ oc_font oc_font_create_from_memory(oc_str8 mem, u32 rangeCount, oc_unicode_range
stbtt_GetFontVMetrics(&stbttFontInfo, &ascent, &descent, &lineGap);
stbtt_GetFontBoundingBox(&stbttFontInfo, &x0, &y0, &x1, &y1);
font->extents.ascent = ascent;
font->extents.descent = -descent;
font->extents.leading = lineGap;
font->extents.width = x1 - x0;
font->metrics.ascent = ascent;
font->metrics.descent = -descent;
font->metrics.lineGap = lineGap;
font->metrics.width = x1 - x0;
stbtt_GetCodepointBox(&stbttFontInfo, 'x', &x0, &y0, &x1, &y1);
font->extents.xHeight = y1 - y0;
font->metrics.xHeight = y1 - y0;
stbtt_GetCodepointBox(&stbttFontInfo, 'M', &x0, &y0, &x1, &y1);
font->extents.capHeight = y1 - y0;
font->metrics.capHeight = y1 - y0;
//NOTE(martin): load codepoint ranges
font->rangeCount = rangeCount;
@ -483,13 +483,16 @@ oc_font oc_font_create_from_memory(oc_str8 mem, u32 rangeCount, oc_unicode_range
stbtt_GetGlyphHMetrics(&stbttFontInfo, stbttGlyphIndex, &xAdvance, &xBearing);
stbtt_GetGlyphBox(&stbttFontInfo, stbttGlyphIndex, &x0, &y0, &x1, &y1);
glyph->extents.xAdvance = (f32)xAdvance;
glyph->extents.yAdvance = 0;
glyph->extents.xBearing = (f32)xBearing;
glyph->extents.yBearing = y0;
//NOTE(martin): stb stbtt_GetGlyphBox returns bottom left and top right corners, with y up,
// so we have to set .y = -y1
glyph->metrics.ink = (oc_rect){
.x = x0,
.y = -y1,
.w = x1 - x0,
.h = y1 - y0
};
glyph->extents.width = x1 - x0;
glyph->extents.height = y1 - y0;
glyph->metrics.advance = (oc_vec2){ xAdvance, 0 };
//NOTE(martin): load glyph outlines
@ -673,34 +676,34 @@ oc_glyph_data* oc_font_get_glyph_data(oc_font_data* fontData, u32 glyphIndex)
return (&(fontData->glyphs[glyphIndex - 1]));
}
oc_font_extents oc_font_get_extents(oc_font font)
oc_font_metrics oc_font_get_metrics_unscaled(oc_font font)
{
oc_font_data* fontData = oc_font_data_from_handle(font);
if(!fontData)
{
return ((oc_font_extents){ 0 });
return ((oc_font_metrics){ 0 });
}
return (fontData->extents);
return (fontData->metrics);
}
oc_font_extents oc_font_get_scaled_extents(oc_font font, f32 emSize)
oc_font_metrics oc_font_get_metrics(oc_font font, f32 emSize)
{
oc_font_data* fontData = oc_font_data_from_handle(font);
if(!fontData)
{
return ((oc_font_extents){ 0 });
return ((oc_font_metrics){ 0 });
}
f32 scale = emSize / fontData->unitsPerEm;
oc_font_extents extents = fontData->extents;
oc_font_metrics metrics = fontData->metrics;
extents.ascent *= scale;
extents.descent *= scale;
extents.leading *= scale;
extents.xHeight *= scale;
extents.capHeight *= scale;
extents.width *= scale;
metrics.ascent *= scale;
metrics.descent *= scale;
metrics.lineGap *= scale;
metrics.xHeight *= scale;
metrics.capHeight *= scale;
metrics.width *= scale;
return (extents);
return (metrics);
}
f32 oc_font_get_scale_for_em_pixels(oc_font font, f32 emSize)
@ -713,9 +716,10 @@ f32 oc_font_get_scale_for_em_pixels(oc_font font, f32 emSize)
return (emSize / fontData->unitsPerEm);
}
void oc_font_get_glyph_extents_from_font_data(oc_font_data* fontData,
////////////////////////////////////////////////////////////////////////////////////////////::
void oc_font_get_glyph_metrics_from_font_data(oc_font_data* fontData,
oc_str32 glyphIndices,
oc_text_extents* outExtents)
oc_glyph_metrics* outMetrics)
{
for(int i = 0; i < glyphIndices.len; i++)
{
@ -724,22 +728,23 @@ void oc_font_get_glyph_extents_from_font_data(oc_font_data* fontData,
continue;
}
oc_glyph_data* glyph = oc_font_get_glyph_data(fontData, glyphIndices.ptr[i]);
outExtents[i] = glyph->extents;
outMetrics[i] = glyph->metrics;
}
}
int oc_font_get_glyph_extents(oc_font font, oc_str32 glyphIndices, oc_text_extents* outExtents)
/*
int oc_font_get_glyph_metrics(oc_font font, oc_str32 glyphIndices, oc_text_metrics* outMetrics)
{
oc_font_data* fontData = oc_font_data_from_handle(font);
if(!fontData)
{
return (-1);
}
oc_font_get_glyph_extents_from_font_data(fontData, glyphIndices, outExtents);
oc_font_get_glyph_metrics_from_font_data(fontData, glyphIndices, outMetrics);
return (0);
}
int oc_font_get_codepoint_extents(oc_font font, oc_utf32 codePoint, oc_text_extents* outExtents)
int oc_font_get_codepoint_metrics(oc_font font, oc_utf32 codePoint, oc_text_metrics* outMetrics)
{
oc_font_data* fontData = oc_font_data_from_handle(font);
if(!fontData)
@ -750,21 +755,23 @@ int oc_font_get_codepoint_extents(oc_font font, oc_utf32 codePoint, oc_text_exte
oc_str32 codePoints = { 1, &codePoint };
oc_str32 backing = { 1, &glyphIndex };
oc_str32 glyphs = oc_font_get_glyph_indices_from_font_data(fontData, codePoints, backing);
oc_font_get_glyph_extents_from_font_data(fontData, glyphs, outExtents);
oc_font_get_glyph_metrics_from_font_data(fontData, glyphs, outMetrics);
return (0);
}
*/
/////////////////////////////////////////////////
oc_rect oc_text_bounding_box_utf32(oc_font font, f32 fontSize, oc_str32 codePoints)
oc_text_metrics oc_font_text_metrics_utf32(oc_font font, f32 fontSize, oc_str32 codePoints)
{
if(!codePoints.len || !codePoints.ptr)
{
return ((oc_rect){ 0 });
return ((oc_text_metrics){ 0 });
}
oc_font_data* fontData = oc_font_data_from_handle(font);
if(!fontData)
{
return ((oc_rect){ 0 });
return ((oc_text_metrics){ 0 });
}
oc_arena_scope scratch = oc_scratch_begin();
@ -772,86 +779,123 @@ oc_rect oc_text_bounding_box_utf32(oc_font font, f32 fontSize, oc_str32 codePoin
//NOTE(martin): find width of missing character
//TODO(martin): should cache that at font creation...
oc_text_extents missingGlyphExtents;
oc_glyph_metrics missingGlyphMetrics = { 0 };
u32 missingGlyphIndex = oc_font_get_glyph_index_from_font_data(fontData, 0xfffd);
if(missingGlyphIndex)
{
oc_font_get_glyph_extents_from_font_data(fontData, (oc_str32){ 1, &missingGlyphIndex }, &missingGlyphExtents);
oc_font_get_glyph_metrics_from_font_data(fontData, (oc_str32){ 1, &missingGlyphIndex }, &missingGlyphMetrics);
}
else
{
//NOTE(martin): could not find replacement glyph, try to get an 'x' to get a somewhat correct width
//NOTE(martin): could not find replacement glyph, try to get an 'X' to get a somewhat correct dimensions
// to render an empty rectangle. Otherwise just render with the max font width
f32 boxWidth = fontData->extents.width * 0.8;
f32 xBearing = fontData->extents.width * 0.1;
f32 xAdvance = fontData->extents.width;
missingGlyphIndex = oc_font_get_glyph_index_from_font_data(fontData, 'x');
missingGlyphIndex = oc_font_get_glyph_index_from_font_data(fontData, 'X');
if(missingGlyphIndex)
{
oc_font_get_glyph_extents_from_font_data(fontData, (oc_str32){ 1, &missingGlyphIndex }, &missingGlyphExtents);
oc_font_get_glyph_metrics_from_font_data(fontData, (oc_str32){ 1, &missingGlyphIndex }, &missingGlyphMetrics);
}
else
{
missingGlyphExtents.xBearing = fontData->extents.width * 0.1;
missingGlyphExtents.yBearing = 0;
missingGlyphExtents.width = fontData->extents.width * 0.8;
missingGlyphExtents.xAdvance = fontData->extents.width;
missingGlyphExtents.yAdvance = 0;
missingGlyphMetrics = (oc_glyph_metrics){
.ink = {
.x = fontData->metrics.width * 0.1,
.y = -fontData->metrics.ascent,
.w = fontData->metrics.width * 0.8,
.h = fontData->metrics.ascent,
},
.advance = { .x = fontData->metrics.width, .y = 0 },
};
}
}
//NOTE(martin): accumulate text extents
f32 width = 0;
f32 x = 0;
f32 y = 0;
f32 lineHeight = fontData->extents.descent + fontData->extents.ascent;
oc_text_metrics metrics = { 0 };
f32 lineHeight = fontData->metrics.descent + fontData->metrics.ascent + fontData->metrics.lineGap;
if(glyphIndices.len)
{
metrics.logical.y = -(fontData->metrics.ascent + fontData->metrics.lineGap);
metrics.logical.h += lineHeight + fontData->metrics.lineGap;
}
f32 inkX0 = 0, inkX1 = 0, inkY0 = 0, inkY1 = 0;
for(int i = 0; i < glyphIndices.len; i++)
{
//TODO(martin): make it failsafe for fonts that don't have a glyph for the line-feed codepoint ?
oc_glyph_data* glyph = 0;
oc_text_extents extents;
oc_glyph_metrics glyphMetrics;
if(!glyphIndices.ptr[i] || glyphIndices.ptr[i] >= fontData->glyphCount)
{
extents = missingGlyphExtents;
glyphMetrics = missingGlyphMetrics;
}
else
{
glyph = oc_font_get_glyph_data(fontData, glyphIndices.ptr[i]);
extents = glyph->extents;
glyphMetrics = glyph->metrics;
}
x += extents.xAdvance;
y += extents.yAdvance;
inkX0 = oc_min(inkX0, metrics.advance.x + glyphMetrics.ink.x);
inkX1 = oc_max(inkX1, metrics.advance.x + glyphMetrics.ink.x + glyphMetrics.ink.w);
inkY0 = oc_min(inkY0, metrics.advance.y + glyphMetrics.ink.y);
inkY1 = oc_max(inkY1, metrics.advance.y + glyphMetrics.ink.y + glyphMetrics.ink.h);
metrics.advance.x += glyphMetrics.advance.x;
metrics.advance.y += glyphMetrics.advance.y;
metrics.logical.w = oc_max(metrics.logical.w, metrics.advance.x);
if(glyph && glyph->codePoint == '\n')
{
width = oc_max(width, x);
x = 0;
y += lineHeight + fontData->extents.leading;
metrics.advance.y += lineHeight;
metrics.advance.x = 0;
if(i < glyphIndices.len - 1)
{
metrics.logical.h += lineHeight;
}
}
width = oc_max(width, x);
}
metrics.ink = (oc_rect){
inkX0,
inkY0,
inkX1 - inkX0,
inkY1 - inkY0
};
OC_ASSERT(metrics.ink.y <= 0);
f32 fontScale = oc_font_get_scale_for_em_pixels(font, fontSize);
oc_rect rect = { 0, -fontData->extents.ascent * fontScale, width * fontScale, (y + lineHeight) * fontScale };
metrics.ink.x *= fontScale;
metrics.ink.y *= fontScale;
metrics.ink.w *= fontScale;
metrics.ink.h *= fontScale;
metrics.logical.x *= fontScale;
metrics.logical.y *= fontScale;
metrics.logical.w *= fontScale;
metrics.logical.h *= fontScale;
metrics.advance.x *= fontScale;
metrics.advance.y *= fontScale;
oc_scratch_end(scratch);
return (rect);
return (metrics);
}
oc_rect oc_text_bounding_box(oc_font font, f32 fontSize, oc_str8 text)
oc_text_metrics oc_font_text_metrics(oc_font font, f32 fontSize, oc_str8 text)
{
if(!text.len || !text.ptr)
{
return ((oc_rect){ 0 });
return ((oc_text_metrics){ 0 });
}
oc_arena_scope scratch = oc_scratch_begin();
oc_str32 codePoints = oc_utf8_push_to_codepoints(scratch.arena, text);
oc_rect result = oc_text_bounding_box_utf32(font, fontSize, codePoints);
oc_text_metrics result = oc_font_text_metrics_utf32(font, fontSize, codePoints);
oc_scratch_end(scratch);
return (result);
}
@ -1377,31 +1421,40 @@ oc_rect oc_glyph_outlines_from_font_data(oc_font_data* fontData, oc_str32 glyphI
glyphIndex = oc_font_get_glyph_index_from_font_data(fontData, 0xfffd);
if(!glyphIndex)
{
//NOTE(martin): could not find replacement glyph, try to get an 'x' to get a somewhat correct width
//NOTE(martin): could not find replacement glyph, try to get an 'X' to get a somewhat correct dimensions
// to render an empty rectangle. Otherwise just render with the max font width
f32 boxWidth = fontData->extents.width * 0.8;
f32 xBearing = fontData->extents.width * 0.1;
f32 xAdvance = fontData->extents.width;
glyphIndex = oc_font_get_glyph_index_from_font_data(fontData, 'x');
if(glyphIndex)
oc_glyph_metrics missingGlyphMetrics = { 0 };
u32 missingGlyphIndex = oc_font_get_glyph_index_from_font_data(fontData, 'X');
if(missingGlyphIndex)
{
oc_glyph_data* glyph = &(fontData->glyphs[glyphIndex]);
boxWidth = glyph->extents.width;
xBearing = glyph->extents.xBearing;
xAdvance = glyph->extents.xAdvance;
oc_font_get_glyph_metrics_from_font_data(fontData, (oc_str32){ .len = 1, .ptr = &missingGlyphIndex }, &missingGlyphMetrics);
}
else
{
missingGlyphMetrics = (oc_glyph_metrics){
.ink = {
.x = fontData->metrics.width * 0.1,
.y = -fontData->metrics.ascent,
.w = fontData->metrics.width * 0.8,
.h = fontData->metrics.ascent,
},
.advance = { .x = fontData->metrics.width, .y = 0 },
};
}
f32 oldStrokeWidth = canvas->attributes.width;
oc_set_width(boxWidth * 0.005);
oc_rectangle_stroke(xOffset + xBearing * scale,
yOffset,
boxWidth * scale * flip,
fontData->extents.capHeight * scale);
oc_set_width(missingGlyphMetrics.ink.w * 0.005);
oc_rectangle_stroke(xOffset + missingGlyphMetrics.ink.x * scale,
yOffset + missingGlyphMetrics.ink.y * scale,
missingGlyphMetrics.ink.w * scale * flip,
missingGlyphMetrics.ink.h * scale);
oc_set_width(oldStrokeWidth);
oc_move_to(xOffset + xAdvance * scale, yOffset);
maxWidth = oc_max(maxWidth, xOffset + xAdvance * scale - startX);
oc_move_to(xOffset + missingGlyphMetrics.advance.x * scale, yOffset);
maxWidth = oc_max(maxWidth, xOffset + missingGlyphMetrics.advance.x * scale - startX);
continue;
}
}
@ -1419,11 +1472,11 @@ oc_rect oc_glyph_outlines_from_font_data(oc_font_data* fontData, oc_str32 glyphI
elements[eltIndex].p[pIndex].y = elements[eltIndex].p[pIndex].y * scale * flip + yOffset;
}
}
oc_move_to(xOffset + scale * glyph->extents.xAdvance, yOffset);
oc_move_to(xOffset + scale * glyph->metrics.advance.x, yOffset);
maxWidth = oc_max(maxWidth, xOffset + scale * glyph->extents.xAdvance - startX);
maxWidth = oc_max(maxWidth, xOffset + scale * glyph->metrics.advance.x - startX);
}
f32 lineHeight = (fontData->extents.ascent + fontData->extents.descent) * scale;
f32 lineHeight = (fontData->metrics.ascent + fontData->metrics.descent) * scale;
oc_rect box = { startX, startY, maxWidth, canvas->subPathLastPoint.y - startY + lineHeight };
return (box);
}

View File

@ -964,7 +964,7 @@ void oc_ui_styling_prepass(oc_ui_context* ui, oc_ui_box* box, oc_list* before, o
if(desiredSize[OC_UI_AXIS_X].kind == OC_UI_SIZE_TEXT
|| desiredSize[OC_UI_AXIS_Y].kind == OC_UI_SIZE_TEXT)
{
textBox = oc_text_bounding_box(style->font, style->fontSize, box->string);
textBox = oc_font_text_metrics(style->font, style->fontSize, box->string).logical;
}
for(int i = 0; i < OC_UI_AXIS_COUNT; i++)
@ -1362,7 +1362,7 @@ void oc_ui_draw_box(oc_ui_box* box)
if(draw && (box->flags & OC_UI_FLAG_DRAW_TEXT))
{
oc_rect textBox = oc_text_bounding_box(style->font, style->fontSize, box->string);
oc_rect textBox = oc_font_text_metrics(style->font, style->fontSize, box->string).logical;
f32 x = 0;
f32 y = 0;
@ -2508,7 +2508,7 @@ oc_ui_select_popup_info oc_ui_select_popup(const char* name, oc_ui_select_popup_
oc_rect bbox = { 0 };
for(int i = 0; i < info->optionCount; i++)
{
bbox = oc_text_bounding_box(button->style.font, button->style.fontSize, info->options[i]);
bbox = oc_font_text_metrics(button->style.font, button->style.fontSize, info->options[i]).logical;
maxOptionWidth = oc_max(maxOptionWidth, bbox.w);
}
f32 buttonWidth = maxOptionWidth + 2 * button->style.layout.margin.x + button->rect.h;
@ -3305,11 +3305,11 @@ void oc_ui_text_box_render(oc_ui_box* box, void* data)
}
oc_ui_style* style = &box->style;
oc_font_extents extents = oc_font_get_scaled_extents(style->font, style->fontSize);
oc_font_metrics extents = oc_font_get_metrics(style->font, style->fontSize);
f32 lineHeight = extents.ascent + extents.descent;
oc_str32 before = oc_str32_slice(codepoints, 0, firstDisplayedChar);
oc_rect beforeBox = oc_text_bounding_box_utf32(style->font, style->fontSize, before);
oc_rect beforeBox = oc_font_text_metrics_utf32(style->font, style->fontSize, before).logical;
f32 textX = box->rect.x - beforeBox.w;
f32 textTop = box->rect.y + 0.5 * (box->rect.h - lineHeight);
@ -3321,7 +3321,7 @@ void oc_ui_text_box_render(oc_ui_box* box, void* data)
u32 selectEnd = oc_max(ui->editCursor, ui->editMark);
oc_str32 beforeSelect = oc_str32_slice(codepoints, 0, selectStart);
oc_rect beforeSelectBox = oc_text_bounding_box_utf32(style->font, style->fontSize, beforeSelect);
oc_rect beforeSelectBox = oc_font_text_metrics_utf32(style->font, style->fontSize, beforeSelect).logical;
beforeSelectBox.x += textX;
beforeSelectBox.y += textY;
@ -3329,8 +3329,8 @@ void oc_ui_text_box_render(oc_ui_box* box, void* data)
{
oc_str32 select = oc_str32_slice(codepoints, selectStart, selectEnd);
oc_str32 afterSelect = oc_str32_slice(codepoints, selectEnd, codepoints.len);
oc_rect selectBox = oc_text_bounding_box_utf32(style->font, style->fontSize, select);
oc_rect afterSelectBox = oc_text_bounding_box_utf32(style->font, style->fontSize, afterSelect);
oc_rect selectBox = oc_font_text_metrics_utf32(style->font, style->fontSize, select).logical;
oc_rect afterSelectBox = oc_font_text_metrics_utf32(style->font, style->fontSize, afterSelect).logical;
selectBox.x += beforeSelectBox.x + beforeSelectBox.w;
selectBox.y += textY;
@ -3432,7 +3432,7 @@ oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8
oc_ui_box* textBox = oc_ui_box_make("text", OC_UI_FLAG_CLIP | OC_UI_FLAG_DRAW_PROC);
oc_ui_tag_box(textBox, "text");
oc_font_extents extents = oc_font_get_scaled_extents(font, fontSize);
oc_font_metrics extents = oc_font_get_metrics(font, fontSize);
oc_ui_sig sig = oc_ui_box_sig(frame);
@ -3464,7 +3464,7 @@ oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8
f32 x = 0;
for(int i = ui->editFirstDisplayedChar; i < codepoints.len; i++)
{
oc_rect bbox = oc_text_bounding_box_utf32(font, fontSize, oc_str32_slice(codepoints, i, i + 1));
oc_rect bbox = oc_font_text_metrics_utf32(font, fontSize, oc_str32_slice(codepoints, i, i + 1)).logical;
if(x < cursorX)
{
hoveredChar = i;
@ -3520,7 +3520,7 @@ oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8
}
else if(ui->editSelectionMode == OC_UI_EDIT_MOVE_LINE)
{
oc_rect bbox = oc_text_bounding_box_utf32(font, fontSize, codepoints);
oc_rect bbox = oc_font_text_metrics_utf32(font, fontSize, codepoints).logical;
if(fabsf(bbox.w - cursorX) < fabsf(cursorX))
{
ui->editCursor = codepoints.len;
@ -3537,8 +3537,8 @@ oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8
if(oc_min(ui->editCursor, ui->editMark) == oc_min(ui->editWordSelectionInitialCursor, ui->editWordSelectionInitialMark)
&& oc_max(ui->editCursor, ui->editMark) == oc_max(ui->editWordSelectionInitialCursor, ui->editWordSelectionInitialMark))
{
oc_rect editCursorPrefixBbox = oc_text_bounding_box_utf32(font, fontSize, oc_str32_slice(codepoints, 0, ui->editCursor));
oc_rect editMarkPrefixBbox = oc_text_bounding_box_utf32(font, fontSize, oc_str32_slice(codepoints, 0, ui->editMark));
oc_rect editCursorPrefixBbox = oc_font_text_metrics_utf32(font, fontSize, oc_str32_slice(codepoints, 0, ui->editCursor)).logical;
oc_rect editMarkPrefixBbox = oc_font_text_metrics_utf32(font, fontSize, oc_str32_slice(codepoints, 0, ui->editMark)).logical;
f32 editCursorX = editCursorPrefixBbox.w;
f32 editMarkX = editMarkPrefixBbox.w;
if(fabsf(cursorX - editMarkX) < fabsf(cursorX - editCursorX))
@ -3665,13 +3665,13 @@ oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8
{
i32 firstDisplayedChar = ui->editFirstDisplayedChar;
oc_str32 firstToCursor = oc_str32_slice(codepoints, firstDisplayedChar, ui->editCursor);
oc_rect firstToCursorBox = oc_text_bounding_box_utf32(font, fontSize, firstToCursor);
oc_rect firstToCursorBox = oc_font_text_metrics_utf32(font, fontSize, firstToCursor).logical;
while(firstToCursorBox.w > textBox->rect.w)
{
firstDisplayedChar++;
firstToCursor = oc_str32_slice(codepoints, firstDisplayedChar, ui->editCursor);
firstToCursorBox = oc_text_bounding_box_utf32(font, fontSize, firstToCursor);
firstToCursorBox = oc_font_text_metrics_utf32(font, fontSize, firstToCursor).logical;
}
ui->editFirstDisplayedChar = firstDisplayedChar;