ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
Font.c File Reference
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Objectively/Hash.h>
#include <Objectively/Array.h>
#include <Objectively/String.h>
#include "Font.h"
#include "Log.h"
#include "View.h"
#include "Window.h"
#include "../Assets/coda.ttf.h"
#include "../Assets/shareTechMono.ttf.h"

Go to the source code of this file.

Macros

#define _Class   _Font
 

Functions

Class * _Font (void)
 
static void cacheFont (Data *data, const char *family)
 
static void clearCache (void)
 
static void dealloc (Object *self)
 
static Font * defaultFont (void)
 
static Font * defaultMonospaceFont (void)
 
static void destroy (Class *clazz)
 
static Font * fontWithAttributes (const FontAttributes *attributes, float pixelDensity)
 
static Font * fontWithName (const char *name, float pixelDensity)
 
static int hash (const Object *self)
 
static void initialize (Class *clazz)
 
static Font * initWithData (Font *self, Data *data, const FontAttributes *attributes, float pixelDensity)
 
static bool isEqual (const Object *self, const Object *other)
 
static String * name (const Font *self)
 
static String * nameWithAttributes (const FontAttributes *attributes)
 
static void normalizeAttributes (FontAttributes *attributes)
 Normalizes Font attributes to their defaults, in one place, so that Font::nameWithAttributes and Font::fontWithAttributes always agree.
 
static SDL_Surface * renderCharacters (const Font *self, const char *chars, SDL_Color color, int wrapWidth)
 
static void sizeCharacters (const Font *self, const char *chars, int *w, int *h)
 

Variables

static Dictionary * _cache
 
static Font * _defaultFont
 
static Font * _defaultMonospaceFont
 
const EnumName FontStyleNames []
 

Macro Definition Documentation

◆ _Class

#define _Class   _Font

Definition at line 50 of file Font.c.

Function Documentation

◆ _Font()

Class * _Font ( void  )

Definition at line 464 of file Font.c.

464 {
465 static Class *clazz;
466 static Once once;
467
468 do_once(&once, {
469 clazz = _initialize(&(const ClassDef) {
470 .name = "Font",
471 .superclass = _Object(),
472 .instanceSize = sizeof(Font),
473 .interfaceSize = sizeof(FontInterface),
474 .initialize = initialize,
475 .destroy = destroy,
476 });
477 });
478
479 return clazz;
480}
static void destroy(Class *clazz)
Definition Font.c:451
static void initialize(Class *clazz)
Definition Font.c:409
TrueType fonts.
Definition Font.h:88

◆ cacheFont()

static void cacheFont ( Data *  data,
const char *  family 
)
static

Definition at line 122 of file Font.c.

122 {
123 $(_cache, setObjectForKeyPath, data, family);
124}
static Dictionary * _cache
Definition Font.c:116

◆ clearCache()

static void clearCache ( void  )
static

Definition at line 149 of file Font.c.

149 {
150 $(_cache, removeAllObjects);
151}

◆ dealloc()

static void dealloc ( Object *  self)
static
See also
Object::dealloc(Object *)

Definition at line 57 of file Font.c.

57 {
58
59 Font *this = (Font *) self;
60
61 deallocBitmap(&this->bitmap);
62
63 TTF_CloseFont(this->font);
64
65 free(this->family);
66 free(this->iconPlaceholder);
67
68 release(this->data);
69
70 super(Object, self, dealloc);
71}
void deallocBitmap(FontBitmap *bitmap)
Releases the resources held by bitmap. Safe to call on a zeroed FontBitmap.
static void dealloc(Object *self)
Definition Font.c:57
static const char * iconPlaceholder(const Font *font)
The placeholder an icon occupies in font's layout: a codepoint that is not a line-break opportunity,...
Definition Text.c:171
static Font * font(Theme *self, const FontAttributes *attributes, float pixelDensity)
Definition Theme.c:108

◆ defaultFont()

static Font * defaultFont ( void  )
static

Definition at line 159 of file Font.c.

159 {
160 static Once once;
161
162 const FontAttributes attrs = {
164 };
165
166 do_once(&once, {
167 _defaultFont = $$(Font, fontWithAttributes, &attrs, 1.f);
168 assert(_defaultFont);
169 });
170
171 return _defaultFont;
172}
static Font * fontWithAttributes(const FontAttributes *attributes, float pixelDensity)
Definition Font.c:199
static Font * _defaultFont
Definition Font.c:153
#define DEFAULT_FONT_STYLE
Definition Font.h:38
#define DEFAULT_FONT_FAMILY
Definition Font.h:36
#define DEFAULT_FONT_SIZE
Definition Font.h:37
The family, size and style attributes that identify a Font, independent of the pixel density at which...
Definition Font.h:64

◆ defaultMonospaceFont()

static Font * defaultMonospaceFont ( void  )
static

Definition at line 180 of file Font.c.

180 {
181 static Once once;
182
183 const FontAttributes attrs = {
185 };
186
187 do_once(&once, {
189 assert(_defaultMonospaceFont);
190 });
191
193}
static Font * _defaultMonospaceFont
Definition Font.c:174
#define DEFAULT_MONOSPACE_FONT_FAMILY
Definition Font.h:40

◆ destroy()

static void destroy ( Class *  clazz)
static
See also
Class::destroy(Class *)

Definition at line 451 of file Font.c.

451 {
452
453 release(_cache);
454 release(_defaultFont);
455 release(_defaultMonospaceFont);
456
457 TTF_Quit();
458}

◆ fontWithAttributes()

static Font * fontWithAttributes ( const FontAttributes *  attributes,
float  pixelDensity 
)
static

Definition at line 199 of file Font.c.

199 {
200
201 FontAttributes normalized = *attributes;
202 normalizeAttributes(&normalized);
203
204 if (pixelDensity < 1.f) {
205 pixelDensity = 1.f;
206 }
207
208 Data *data = $((Dictionary *) _cache, objectForKeyPath, normalized.family);
209 if (data) {
210 Font *font = $(alloc(Font), initWithData, data, &normalized, pixelDensity);
211 assert(font);
212
213 return font;
214 }
215
216 MVC_LogWarn("%s-%d-%d not found\n", normalized.family, normalized.size, normalized.style);
217 return retain($$(Font, defaultFont));
218}
static void normalizeAttributes(FontAttributes *attributes)
Normalizes Font attributes to their defaults, in one place, so that Font::nameWithAttributes and Font...
Definition Font.c:130
static Font * initWithData(Font *self, Data *data, const FontAttributes *attributes, float pixelDensity)
Definition Font.c:263
static Font * defaultFont(void)
Definition Font.c:159
#define MVC_LogWarn(fmt,...)
Definition Log.h:54
const char * family
The family, or NULL for the default.
Definition Font.h:68
int style
The FontStyle, or -1 for the default.
Definition Font.h:78
int size
The point size, or 0 for the default.
Definition Font.h:73

◆ fontWithName()

static Font * fontWithName ( const char *  name,
float  pixelDensity 
)
static

Definition at line 224 of file Font.c.

224 {
225
226 assert(name);
227
228 char *chars = strdup(name);
229 assert(chars);
230
231 Font *font = NULL;
232
233 char *styleToken = strrchr(chars, '-');
234 if (styleToken) {
235 *styleToken++ = '\0';
236
237 char *sizeToken = strrchr(chars, '-');
238 if (sizeToken) {
239 *sizeToken++ = '\0';
240
241 const FontAttributes attributes = {
242 chars, (int) strtol(sizeToken, NULL, 10), valueof(FontStyleNames, styleToken)
243 };
244
245 font = $$(Font, fontWithAttributes, &attributes, pixelDensity);
246 }
247 }
248
249 free(chars);
250
251 if (font == NULL) {
252 MVC_LogWarn("%s is not a valid Font name\n", name);
253 font = retain($$(Font, defaultFont));
254 }
255
256 return font;
257}
const EnumName FontStyleNames[]
Definition Font.c:42
static String * name(const Font *self)
Definition Font.c:303

◆ hash()

static int hash ( const Object *  self)
static
See also
Object::hash(const Object *)

Definition at line 76 of file Font.c.

76 {
77
78 Font *this = (Font *) self;
79
80 int hash = HASH_SEED;
81 hash = HashForCString(hash, this->family);
82 hash = HashForInteger(hash, this->size);
83 hash = HashForInteger(hash, this->style);
84 hash = HashForInteger(hash, this->renderSize);
85
86 return hash;
87}
static int hash(const Object *self)
Definition Font.c:76
static SDL_Size size(const Image *self)
Definition Image.c:416

◆ initialize()

static void initialize ( Class *  clazz)
static
See also
Class::initialize(Class *)

Definition at line 409 of file Font.c.

409 {
410
411 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
412 ((ObjectInterface *) clazz->interface)->hash = hash;
413 ((ObjectInterface *) clazz->interface)->isEqual = isEqual;
414
415 ((FontInterface *) clazz->interface)->cacheFont = cacheFont;
416 ((FontInterface *) clazz->interface)->clearCache = clearCache;
417 ((FontInterface *) clazz->interface)->defaultFont = defaultFont;
418 ((FontInterface *) clazz->interface)->defaultMonospaceFont = defaultMonospaceFont;
419 ((FontInterface *) clazz->interface)->fontWithAttributes = fontWithAttributes;
420 ((FontInterface *) clazz->interface)->fontWithName = fontWithName;
421 ((FontInterface *) clazz->interface)->initWithData = initWithData;
422 ((FontInterface *) clazz->interface)->name = name;
423 ((FontInterface *) clazz->interface)->nameWithAttributes = nameWithAttributes;
424 ((FontInterface *) clazz->interface)->renderBitmapCharacters = renderCharactersBitmap;
425 ((FontInterface *) clazz->interface)->renderCharacters = renderCharacters;
426 ((FontInterface *) clazz->interface)->renderDeviceWillReset = renderDeviceWillResetBitmap;
427 ((FontInterface *) clazz->interface)->sizeBitmapCharacters = sizeCharactersBitmap;
428 ((FontInterface *) clazz->interface)->sizeCharacters = sizeCharacters;
429
430 const bool init = TTF_Init();
431 assert(init);
432 (void) init;
433
434 _cache = $$(Dictionary, dictionary);
435 assert(_cache);
436
437 Data *coda = $(alloc(Data), initWithConstMemory, coda_ttf, coda_ttf_len - 1);
438 assert(coda);
440 release(coda);
441
442 Data *shareTechMono = $(alloc(Data), initWithConstMemory, shareTechMono_ttf, shareTechMono_ttf_len - 1);
443 assert(shareTechMono);
445 release(shareTechMono);
446}
static View * init(View *self)
Definition Box.c:67
void renderCharactersBitmap(Font *self, const Renderer *renderer, const char *chars, SDL_Color color, int wrapWidth, const SDL_Point *origin, const ImageAtlas *icons)
Implements Font::renderBitmapCharacters.
void renderDeviceWillResetBitmap(Font *self)
Implements Font::renderDeviceWillReset.
void sizeCharactersBitmap(const Font *self, const char *chars, int wrapWidth, const ImageAtlas *icons, int *w, int *h)
Implements Font::sizeBitmapCharacters.
static void sizeCharacters(const Font *self, const char *chars, int *w, int *h)
Definition Font.c:352
static SDL_Surface * renderCharacters(const Font *self, const char *chars, SDL_Color color, int wrapWidth)
Definition Font.c:330
static void clearCache(void)
Definition Font.c:149
static String * nameWithAttributes(const FontAttributes *attributes)
Definition Font.c:312
static Font * fontWithName(const char *name, float pixelDensity)
Definition Font.c:224
static Font * defaultMonospaceFont(void)
Definition Font.c:180
static bool isEqual(const Object *self, const Object *other)
Definition Font.c:92
static void cacheFont(Data *data, const char *family)
Definition Font.c:122
Font * defaultMonospaceFont(void)
Definition Font.c:180
Font * initWithData(Font *self, Data *data, const FontAttributes *attributes, float pixelDensity)
Initializes this Font with the given TTF Data and attributes.
Definition Font.c:263
Font * fontWithName(const char *name, float pixelDensity)
Resolves a Font from a name in the format produced by Font::name.
Definition Font.c:224
Font * fontWithAttributes(const FontAttributes *attributes, float pixelDensity)
Resolves a new Font with the given attributes from the cached font Data.
Definition Font.c:199
String * name(const Font *self)
Definition Font.c:303

◆ initWithData()

static Font * initWithData ( Font *  self,
Data *  data,
const FontAttributes *  attributes,
float  pixelDensity 
)
static

Definition at line 263 of file Font.c.

263 {
264
265 self = (Font *) super(Object, self, init);
266 if (self) {
267
268 self->data = retain(data);
269 assert(self->data);
270
271 self->family = strdup(attributes->family);
272 assert(self->family);
273
274 self->size = attributes->size;
275 assert(self->size);
276
277 self->style = attributes->style;
278
279 self->pixelDensity = pixelDensity;
280 self->renderSize = self->size * self->pixelDensity;
281
282 SDL_IOStream *buffer = SDL_IOFromConstMem(self->data->bytes, (int) self->data->length);
283 assert(buffer);
284
285 self->font = TTF_OpenFontIO(buffer, 1, self->renderSize);
286 assert(self->font);
287
288 TTF_SetFontStyle(self->font, self->style);
289 TTF_SetFontHinting(self->font, TTF_HINTING_LIGHT_SUBPIXEL);
290
291 if (TTF_FontIsFixedWidth(self->font)) {
292 initBitmap(&self->bitmap, self);
293 }
294 }
295
296 return self;
297}
bool initBitmap(FontBitmap *bitmap, Font *font)
Bakes FONT_BITMAP_COUNT codepoints of font, from FONT_BITMAP_FIRST, into a glyph sheet,...
float pixelDensity
The display pixel density scale, greater than 1.0 on high-density displays.
Definition Font.h:134
int renderSize
The render size, adjusted for pixel density.
Definition Font.h:139
char * family
The family name.
Definition Font.h:117
FontBitmap bitmap
The glyphs of a fixed-width Font, baked into one sheet; bitmap.surface is NULL for a proportional Fon...
Definition Font.h:107
int size
The point size.
Definition Font.h:144
TTF_Font * font
The backing font.
Definition Font.h:122
Data * data
The raw font data.
Definition Font.h:112
int style
The style.
Definition Font.h:149

◆ isEqual()

static bool isEqual ( const Object *  self,
const Object *  other 
)
static
See also
Object::isEqual(const Object *, const Object *)

Definition at line 92 of file Font.c.

92 {
93
94 if (super(Object, self, isEqual, other)) {
95 return true;
96 }
97
98 if (other && $(other, isKindOfClass, _Font())) {
99
100 const Font *this = (Font *) self;
101 const Font *that = (Font *) other;
102
103 if (!strcmp(this->family, that->family) &&
104 this->size == that->size &&
105 this->style == that->style &&
106 this->renderSize == that->renderSize) {
107 return true;
108 }
109 }
110
111 return false;
112}
Class * _Font(void)
Definition Font.c:464

◆ name()

static String * name ( const Font *  self)
static

Definition at line 303 of file Font.c.

303 {
304 const FontAttributes attributes = { self->family, self->size, self->style };
305 return $$(Font, nameWithAttributes, &attributes);
306}

◆ nameWithAttributes()

static String * nameWithAttributes ( const FontAttributes *  attributes)
static

Definition at line 312 of file Font.c.

312 {
313
314 FontAttributes normalized = *attributes;
315 normalizeAttributes(&normalized);
316
317 for (const EnumName *en = FontStyleNames; en->name; en++) {
318 if (en->value == normalized.style) {
319 return str("%s-%d-%s", normalized.family, normalized.size, en->alias ?: en->name);
320 }
321 }
322
323 return str("%s-%d-%d", normalized.family, normalized.size, normalized.style);
324}

◆ normalizeAttributes()

static void normalizeAttributes ( FontAttributes *  attributes)
static

Normalizes Font attributes to their defaults, in one place, so that Font::nameWithAttributes and Font::fontWithAttributes always agree.

Definition at line 130 of file Font.c.

130 {
131
132 if (attributes->family == NULL) {
133 attributes->family = DEFAULT_FONT_FAMILY;
134 }
135
136 if (attributes->size < 1) {
137 attributes->size = DEFAULT_FONT_SIZE;
138 }
139
140 if (attributes->style < FontStyleRegular || attributes->style > FontStyleStrikeThrough) {
141 attributes->style = DEFAULT_FONT_STYLE;
142 }
143}
@ FontStyleStrikeThrough
Definition Font.h:55
@ FontStyleRegular
Definition Font.h:51

◆ renderCharacters()

static SDL_Surface * renderCharacters ( const Font *  self,
const char *  chars,
SDL_Color  color,
int  wrapWidth 
)
static

Definition at line 330 of file Font.c.

330 {
331
332 // Always the wrapping renderer: with a width of 0 it breaks on newlines only, which is what
333 // Font::sizeCharacters and the TTF_Text layout Text builds its color runs from both assume,
334 // whereas TTF_RenderText_Blended draws a newline as a missing glyph on a single line
335 SDL_Surface *surface = TTF_RenderText_Blended_Wrapped(self->font, chars, 0, color, wrapWidth * self->pixelDensity);
336
337 SDL_Surface *converted = NULL;
338 if (surface) {
339 converted = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
340 SDL_DestroySurface(surface);
341 } else {
342 MVC_LogError("%s\n", SDL_GetError());
343 }
344
345 return converted;
346}
#define MVC_LogError(fmt,...)
Definition Log.h:57

◆ sizeCharacters()

static void sizeCharacters ( const Font *  self,
const char *  chars,
int *  w,
int *  h 
)
static

Definition at line 352 of file Font.c.

352 {
353
354 if (w) {
355 *w = 0;
356 }
357 if (h) {
358 *h = 0;
359 }
360
361 if (chars) {
362 char *lines = strdup(chars);
363
364 const int font_h = TTF_GetFontHeight(self->font);
365
366 for (char *line = strtok(lines, "\n\r"); line; line = strtok(NULL, "\n\r")) {
367
368 if (w) {
369
370 int lineWidth;
371 TTF_GetStringSize(self->font, line, 0, &lineWidth, NULL);
372
373 // TTF_GetStringSize sums glyph advances, but the final glyph's ink can extend past its
374 // own advance (common with bold or large faces). Check the final glyph's bounds and
375 // ensure we take the larger value.
376 const char *end = line + strlen(line);
377 const Uint32 ch = SDL_StepBackUTF8(line, &end);
378 if (ch) {
379 int maxX, advance;
380 if (TTF_GetGlyphMetrics(self->font, ch, NULL, &maxX, NULL, NULL, &advance)) {
381 if (maxX > advance) {
382 lineWidth += maxX - advance;
383 }
384 }
385 }
386
387 *w = max(*w, lineWidth);
388 }
389 if (h) {
390 *h += font_h;
391 }
392 }
393 free(lines);
394
395 if (w) {
396 *w = ceilf(*w / self->pixelDensity);
397 }
398 if (h) {
399 *h = ceilf(*h / self->pixelDensity);
400 }
401 }
402}

Variable Documentation

◆ _cache

Dictionary* _cache
static

Definition at line 116 of file Font.c.

◆ _defaultFont

Font* _defaultFont
static

Definition at line 153 of file Font.c.

◆ _defaultMonospaceFont

Font* _defaultMonospaceFont
static

Definition at line 174 of file Font.c.

◆ FontStyleNames

const EnumName FontStyleNames[]
Initial value:
= MakeEnumNames(
MakeEnumAlias(FontStyleRegular, regular),
MakeEnumAlias(FontStyleBold, bold),
MakeEnumAlias(FontStyleItalic, italic),
MakeEnumAlias(FontStyleUnderline, underline),
MakeEnumAlias(FontStyleStrikeThrough, strikethrough)
)
@ FontStyleUnderline
Definition Font.h:54
@ FontStyleBold
Definition Font.h:52
@ FontStyleItalic
Definition Font.h:53

Definition at line 42 of file Font.c.