#include "font.h"
#include "font.inl"
#include "draw2d.inl"
#include <core/heap.h>
#include <core/strings.h>
#include <sewer/bmath.h>
#include <sewer/cassert.h>
#include <sewer/ptr.h>
struct _font_t
{
uint32_t num_instances;
uint32_t family;
uint32_t style;
real32_t size;
real32_t xscale;
real32_t cell_size;
real32_t leading;
real32_t ascent;
real32_t descent;
real32_t avg_width;
bool_t monospace;
bool_t metrics;
String *family_name;
OSFont *osfont;
};
#define i_abs(x) (((x) < 0.f) ? -(x) : (x))
static Font *i_create_font(const uint32_t family, const real32_t size, const uint32_t style)
{
Font *font = heap_new(Font);
font->num_instances = 1;
font->family = family;
font->size = size;
font->style = style;
font->xscale = 1;
font->cell_size = -1;
font->leading = -1;
font->ascent = -1;
font->descent = -1;
font->avg_width = -1;
font->monospace = FALSE;
font->metrics = FALSE;
font->family_name = NULL;
font->osfont = NULL;
return font;
}
static ___INLINE void i_osfont(Font *font)
{
cassert_no_null(font);
if (font->osfont == NULL)
{
const char_t *fname = _draw2d_font_family(font->family);
font->osfont = osfont_create(fname, font->size, -1, -1, font->style);
}
}
static ___INLINE void i_metrics(Font *font)
{
cassert_no_null(font);
if (font->metrics == FALSE)
{
i_osfont(font);
osfont_metrics(font->osfont, font->size, font->xscale, &font->ascent, &font->descent, &font->leading, &font->cell_size, &font->avg_width, &font->monospace);
font->metrics = TRUE;
}
}
void font_destroy(Font **font)
{
cassert_no_null(font);
cassert_no_null(*font);
if ((*font)->num_instances == 1)
{
if ((*font)->osfont != NULL)
osfont_destroy(&(*font)->osfont);
str_destopt(&(*font)->family_name);
heap_delete(font, Font);
}
else
{
cassert((*font)->num_instances > 0);
(*font)->num_instances -= 1;
}
}
Font *font_create(const char_t *family, const real32_t size, const uint32_t style)
{
uint32_t ffamily = _draw2d_register_font(family);
return i_create_font(ffamily, size, style);
}
Font *font_system(const real32_t size, const uint32_t style)
{
return i_create_font((uint32_t)ekFONT_FAMILY_SYSTEM, size, style);
}
Font *font_monospace(const real32_t size, const uint32_t style)
{
return i_create_font((uint32_t)ekFONT_FAMILY_MONOSPACE, size, style);
}
Font *font_with_style(const Font *font, const uint32_t style)
{
cassert_no_null(font);
return i_create_font(font->family, font->size, style);
}
Font *font_with_width(const Font *font, const real32_t width)
{
Font *font_nscaled = cast(font, Font);
Font *font_scaled = NULL;
const char_t *fname = NULL;
cassert_no_null(font);
cassert(width > 0);
if (bmath_absf(font_nscaled->xscale - 1.f) > 0.01f)
font_nscaled = i_create_font(font->family, font->size, font->style);
i_metrics(font_nscaled);
cassert(font_nscaled->avg_width > 0);
font_scaled = i_create_font(font_nscaled->family, font_nscaled->size, font_nscaled->style);
font_scaled->xscale = width / font_nscaled->avg_width;
cassert(font_scaled->osfont == NULL);
fname = _draw2d_font_family(font_scaled->family);
font_scaled->osfont = osfont_create(fname, font_scaled->size, width, font_scaled->xscale, font_scaled->style);
if (font_nscaled != font)
font_destroy(&font_nscaled);
return font_scaled;
}
Font *font_with_xscale(const Font *font, const real32_t scale)
{
Font *font_nscaled = cast(font, Font);
Font *font_scaled = NULL;
const char_t *fname = NULL;
real32_t width = 0;
cassert_no_null(font);
cassert(scale > 0);
if (bmath_absf(font_nscaled->xscale - 1.f) > 0.01f)
font_nscaled = i_create_font(font->family, font->size, font->style);
i_metrics(font_nscaled);
cassert(font_nscaled->avg_width > 0);
font_scaled = i_create_font(font_nscaled->family, font_nscaled->size, font_nscaled->style);
font_scaled->xscale = scale;
width = font_nscaled->avg_width * scale;
cassert(font_scaled->osfont == NULL);
fname = _draw2d_font_family(font_scaled->family);
font_scaled->osfont = osfont_create(fname, font_scaled->size, width, font_scaled->xscale, font_scaled->style);
if (font_nscaled != font)
font_destroy(&font_nscaled);
return font_scaled;
}
Font *font_copy(const Font *font)
{
cassert_no_null(font);
cast(font, Font)->num_instances += 1;
return cast(font, Font);
}
bool_t font_equals(const Font *font1, const Font *font2)
{
cassert_no_null(font1);
cassert_no_null(font2);
if (font1->family != font2->family)
return FALSE;
if (i_abs(font1->size - font2->size) > 0.0001f)
return FALSE;
if (i_abs(font1->xscale - font2->xscale) > 0.01f)
return FALSE;
if (font1->style != font2->style)
return FALSE;
return TRUE;
}
const char_t *font_family(const Font *font)
{
cassert_no_null(font);
if (font->family_name == NULL)
{
i_osfont(cast(font, Font));
cast(font, Font)->family_name = osfont_family_name(font->osfont);
}
return tc(font->family_name);
}
real32_t font_size(const Font *font)
{
cassert_no_null(font);
return font->size;
}
real32_t font_height(const Font *font)
{
cassert_no_null(font);
i_metrics(cast(font, Font));
return font->cell_size;
}
real32_t font_width(const Font *font)
{
cassert_no_null(font);
i_metrics(cast(font, Font));
return font->avg_width;
}
real32_t font_xscale(const Font *font)
{
cassert_no_null(font);
return font->xscale;
}
real32_t font_ascent(const Font *font)
{
cassert_no_null(font);
i_metrics(cast(font, Font));
return font->ascent;
}
real32_t font_descent(const Font *font)
{
cassert_no_null(font);
i_metrics(cast(font, Font));
return font->descent;
}
real32_t font_leading(const Font *font)
{
cassert_no_null(font);
i_metrics(cast(font, Font));
return font->leading;
}
bool_t font_is_monospace(const Font *font)
{
cassert_no_null(font);
i_metrics(cast(font, Font));
return font->monospace;
}
uint32_t font_style(const Font *font)
{
cassert_no_null(font);
return font->style;
}
void font_extents(const Font *font, const char_t *text, const real32_t refwidth, real32_t *width, real32_t *height)
{
cassert_no_null(font);
i_osfont(cast(font, Font));
osfont_extents(font->osfont, text, font->xscale, refwidth, width, height);
}
const void *font_native(const Font *font)
{
cassert_no_null(font);
i_osfont(cast(font, Font));
return font->osfont;
}