add font management

Tue, 07 Nov 2023 21:24:06 +0100

author
Mike Becker <universe@uap-core.de>
date
Tue, 07 Nov 2023 21:24:06 +0100
changeset 11
d83af80eb09b
parent 10
05d329adcecc
child 12
d89e0ebc76d2

add font management

fonts/OFL.txt file | annotate | diff | comparison | revisions
fonts/OpenSans-Bold.ttf file | annotate | diff | comparison | revisions
fonts/OpenSans-BoldItalic.ttf file | annotate | diff | comparison | revisions
fonts/OpenSans-Italic.ttf file | annotate | diff | comparison | revisions
fonts/OpenSans-Regular.ttf file | annotate | diff | comparison | revisions
src/Makefile file | annotate | diff | comparison | revisions
src/ascension/context.h file | annotate | diff | comparison | revisions
src/ascension/font.h file | annotate | diff | comparison | revisions
src/context.c file | annotate | diff | comparison | revisions
src/font.c file | annotate | diff | comparison | revisions
test/Makefile file | annotate | diff | comparison | revisions
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/fonts/OFL.txt	Tue Nov 07 21:24:06 2023 +0100
     1.3 @@ -0,0 +1,93 @@
     1.4 +Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans)
     1.5 +
     1.6 +This Font Software is licensed under the SIL Open Font License, Version 1.1.
     1.7 +This license is copied below, and is also available with a FAQ at:
     1.8 +http://scripts.sil.org/OFL
     1.9 +
    1.10 +
    1.11 +-----------------------------------------------------------
    1.12 +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
    1.13 +-----------------------------------------------------------
    1.14 +
    1.15 +PREAMBLE
    1.16 +The goals of the Open Font License (OFL) are to stimulate worldwide
    1.17 +development of collaborative font projects, to support the font creation
    1.18 +efforts of academic and linguistic communities, and to provide a free and
    1.19 +open framework in which fonts may be shared and improved in partnership
    1.20 +with others.
    1.21 +
    1.22 +The OFL allows the licensed fonts to be used, studied, modified and
    1.23 +redistributed freely as long as they are not sold by themselves. The
    1.24 +fonts, including any derivative works, can be bundled, embedded, 
    1.25 +redistributed and/or sold with any software provided that any reserved
    1.26 +names are not used by derivative works. The fonts and derivatives,
    1.27 +however, cannot be released under any other type of license. The
    1.28 +requirement for fonts to remain under this license does not apply
    1.29 +to any document created using the fonts or their derivatives.
    1.30 +
    1.31 +DEFINITIONS
    1.32 +"Font Software" refers to the set of files released by the Copyright
    1.33 +Holder(s) under this license and clearly marked as such. This may
    1.34 +include source files, build scripts and documentation.
    1.35 +
    1.36 +"Reserved Font Name" refers to any names specified as such after the
    1.37 +copyright statement(s).
    1.38 +
    1.39 +"Original Version" refers to the collection of Font Software components as
    1.40 +distributed by the Copyright Holder(s).
    1.41 +
    1.42 +"Modified Version" refers to any derivative made by adding to, deleting,
    1.43 +or substituting -- in part or in whole -- any of the components of the
    1.44 +Original Version, by changing formats or by porting the Font Software to a
    1.45 +new environment.
    1.46 +
    1.47 +"Author" refers to any designer, engineer, programmer, technical
    1.48 +writer or other person who contributed to the Font Software.
    1.49 +
    1.50 +PERMISSION & CONDITIONS
    1.51 +Permission is hereby granted, free of charge, to any person obtaining
    1.52 +a copy of the Font Software, to use, study, copy, merge, embed, modify,
    1.53 +redistribute, and sell modified and unmodified copies of the Font
    1.54 +Software, subject to the following conditions:
    1.55 +
    1.56 +1) Neither the Font Software nor any of its individual components,
    1.57 +in Original or Modified Versions, may be sold by itself.
    1.58 +
    1.59 +2) Original or Modified Versions of the Font Software may be bundled,
    1.60 +redistributed and/or sold with any software, provided that each copy
    1.61 +contains the above copyright notice and this license. These can be
    1.62 +included either as stand-alone text files, human-readable headers or
    1.63 +in the appropriate machine-readable metadata fields within text or
    1.64 +binary files as long as those fields can be easily viewed by the user.
    1.65 +
    1.66 +3) No Modified Version of the Font Software may use the Reserved Font
    1.67 +Name(s) unless explicit written permission is granted by the corresponding
    1.68 +Copyright Holder. This restriction only applies to the primary font name as
    1.69 +presented to the users.
    1.70 +
    1.71 +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
    1.72 +Software shall not be used to promote, endorse or advertise any
    1.73 +Modified Version, except to acknowledge the contribution(s) of the
    1.74 +Copyright Holder(s) and the Author(s) or with their explicit written
    1.75 +permission.
    1.76 +
    1.77 +5) The Font Software, modified or unmodified, in part or in whole,
    1.78 +must be distributed entirely under this license, and must not be
    1.79 +distributed under any other license. The requirement for fonts to
    1.80 +remain under this license does not apply to any document created
    1.81 +using the Font Software.
    1.82 +
    1.83 +TERMINATION
    1.84 +This license becomes null and void if any of the above conditions are
    1.85 +not met.
    1.86 +
    1.87 +DISCLAIMER
    1.88 +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    1.89 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
    1.90 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
    1.91 +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
    1.92 +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    1.93 +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
    1.94 +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    1.95 +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
    1.96 +OTHER DEALINGS IN THE FONT SOFTWARE.
     2.1 Binary file fonts/OpenSans-Bold.ttf has changed
     3.1 Binary file fonts/OpenSans-BoldItalic.ttf has changed
     4.1 Binary file fonts/OpenSans-Italic.ttf has changed
     5.1 Binary file fonts/OpenSans-Regular.ttf has changed
     6.1 --- a/src/Makefile	Tue Nov 07 21:13:04 2023 +0100
     6.2 +++ b/src/Makefile	Tue Nov 07 21:24:06 2023 +0100
     6.3 @@ -27,7 +27,7 @@
     6.4  
     6.5  BUILD_DIR=../build/lib
     6.6  
     6.7 -SRC  = context.c error.c window.c
     6.8 +SRC  = context.c error.c window.c font.c
     6.9  
    6.10  OBJ = $(SRC:%.c=$(BUILD_DIR)/%.o)
    6.11  
    6.12 @@ -41,17 +41,26 @@
    6.13  FORCE:
    6.14  
    6.15  $(BUILD_DIR)/context.o: context.c ascension/context.h ascension/window.h \
    6.16 - ascension/datatypes.h ascension/utils.h
    6.17 + ascension/datatypes.h ascension/font.h ascension/error.h \
    6.18 + ascension/utils.h
    6.19  	@echo "Compiling $<"
    6.20  	$(CC) -o $@ $(CFLAGS) -c $<
    6.21  
    6.22  $(BUILD_DIR)/error.o: error.c ascension/context.h ascension/window.h \
    6.23 - ascension/datatypes.h ascension/error.h ascension/utils.h
    6.24 + ascension/datatypes.h ascension/font.h ascension/error.h \
    6.25 + ascension/utils.h
    6.26 +	@echo "Compiling $<"
    6.27 +	$(CC) -o $@ $(CFLAGS) -c $<
    6.28 +
    6.29 +$(BUILD_DIR)/font.o: font.c ascension/font.h ascension/context.h \
    6.30 + ascension/window.h ascension/datatypes.h ascension/font.h \
    6.31 + ascension/error.h
    6.32  	@echo "Compiling $<"
    6.33  	$(CC) -o $@ $(CFLAGS) -c $<
    6.34  
    6.35  $(BUILD_DIR)/window.o: window.c ascension/window.h ascension/datatypes.h \
    6.36 - ascension/context.h ascension/window.h ascension/error.h
    6.37 + ascension/context.h ascension/window.h ascension/font.h \
    6.38 + ascension/error.h ascension/utils.h
    6.39  	@echo "Compiling $<"
    6.40  	$(CC) -o $@ $(CFLAGS) -c $<
    6.41  
     7.1 --- a/src/ascension/context.h	Tue Nov 07 21:13:04 2023 +0100
     7.2 +++ b/src/ascension/context.h	Tue Nov 07 21:24:06 2023 +0100
     7.3 @@ -29,6 +29,7 @@
     7.4  #define ASCENSION_CONTEXT_H
     7.5  
     7.6  #include "window.h"
     7.7 +#include "font.h"
     7.8  
     7.9  #include <cx/buffer.h>
    7.10  #include <cx/list.h>
    7.11 @@ -53,6 +54,8 @@
    7.12      unsigned int flags;
    7.13      CxBuffer error_buffer;
    7.14      AscWindow windows[ASC_MAX_WINDOWS];
    7.15 +    AscFont fonts[ASC_MAX_FONTS];
    7.16 +    unsigned int fonts_loaded;
    7.17  } AscContext;
    7.18  
    7.19  /** Global ascension context. */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/ascension/font.h	Tue Nov 07 21:24:06 2023 +0100
     8.3 @@ -0,0 +1,102 @@
     8.4 +/*
     8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     8.6 + * Copyright 2023 Mike Becker. All rights reserved.
     8.7 + *
     8.8 + * Redistribution and use in source and binary forms, with or without
     8.9 + * modification, are permitted provided that the following conditions are met:
    8.10 + *
    8.11 + *   1. Redistributions of source code must retain the above copyright
    8.12 + *      notice, this list of conditions and the following disclaimer.
    8.13 + *
    8.14 + *   2. Redistributions in binary form must reproduce the above copyright
    8.15 + *      notice, this list of conditions and the following disclaimer in the
    8.16 + *      documentation and/or other materials provided with the distribution.
    8.17 + *
    8.18 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    8.19 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    8.20 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    8.21 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    8.22 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    8.23 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    8.24 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    8.25 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    8.26 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    8.27 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    8.28 + * POSSIBILITY OF SUCH DAMAGE.
    8.29 + */
    8.30 +
    8.31 +#ifndef ASCENSION_FONT_H
    8.32 +#define ASCENSION_FONT_H
    8.33 +
    8.34 +#include <SDL2/SDL_ttf.h>
    8.35 +
    8.36 +#ifndef ASC_MAX_FONTS
    8.37 +/** The maximum number of style/size combinations that can be loaded in parallel. */
    8.38 +#define ASC_MAX_FONTS 64u
    8.39 +#endif // ASC_MAX_FONTS
    8.40 +
    8.41 +#ifdef __cplusplus
    8.42 +extern "C" {
    8.43 +#endif
    8.44 +
    8.45 +enum AscFontStyle {
    8.46 +    ASC_FONT_REGULAR,
    8.47 +    ASC_FONT_BOLD,
    8.48 +    ASC_FONT_ITALIC,
    8.49 +    ASC_FONT_BOLD_ITALIC,
    8.50 +};
    8.51 +
    8.52 +typedef struct AscFont {
    8.53 +    /**
    8.54 +     * Style of the font.
    8.55 +     */
    8.56 +    enum AscFontStyle style;
    8.57 +    /**
    8.58 +     * Point size.
    8.59 +     */
    8.60 +    int size;
    8.61 +    /**
    8.62 +     * Pointer to the SDL TTF font structure.
    8.63 +     */
    8.64 +    TTF_Font *ptr;
    8.65 +} AscFont;
    8.66 +
    8.67 +/**
    8.68 + * Loads a font with the given style and size.
    8.69 + *
    8.70 + * The font is cached and returned faster the next time you call this
    8.71 + * function with the same arguments. However, when you reach the maximum
    8.72 + * number of fonts, the cache is completely cleared and rebuilt.
    8.73 + *
    8.74 + * That means in general, that you should not be using too many fonts of
    8.75 + * different sizes at the same time, and you should not keep the pointer
    8.76 + * returned by this function too long, because you would risking cache misses.
    8.77 + *
    8.78 + * @param style the style
    8.79 + * @param size the point size
    8.80 + * @return a pointer to the font structure (do not free)
    8.81 + */
    8.82 +AscFont const *asc_font(enum AscFontStyle style, int size);
    8.83 +
    8.84 +/**
    8.85 + * Unloads all cached fonts from the context.
    8.86 + */
    8.87 +void asc_font_cache_clear(void);
    8.88 +
    8.89 +/**
    8.90 + * Checks, if the font is still loaded and reloads it, if required.
    8.91 + *
    8.92 + * There is no need to call this function manually. Every Ascension function
    8.93 + * that you pass a font will do that for you and use the returned pointer in
    8.94 + * case of a cache miss.
    8.95 + *
    8.96 + * @param font the font to validate
    8.97 + * @return \p font, or a pointer to the new location of the loaded font
    8.98 + */
    8.99 +AscFont const *asc_font_cache_validate(AscFont const *font);
   8.100 +
   8.101 +#ifdef __cplusplus
   8.102 +} // extern "C"
   8.103 +#endif
   8.104 +
   8.105 +#endif //ASCENSION_FONT_H
     9.1 --- a/src/context.c	Tue Nov 07 21:13:04 2023 +0100
     9.2 +++ b/src/context.c	Tue Nov 07 21:24:06 2023 +0100
     9.3 @@ -39,7 +39,7 @@
     9.4  void asc_context_initialize(void) {
     9.5      if (asc_test_flag(asc_context.flags, ASC_FLAG_INITILIZED))
     9.6          return;
     9.7 -    asc_clear_flag(&asc_context.flags, ASC_FLAG_HAS_ERROR);
     9.8 +    memset(&asc_context, 0, sizeof(AscContext));
     9.9  
    9.10      // initialize error buffer
    9.11      cxBufferInit(
    9.12 @@ -50,9 +50,6 @@
    9.13              CX_BUFFER_AUTO_EXTEND
    9.14      );
    9.15  
    9.16 -    // initialize data
    9.17 -    memset(asc_context.windows, 0, sizeof (asc_context.windows));
    9.18 -
    9.19      // initialize SDL
    9.20      if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    9.21          asc_error(SDL_GetError());
    9.22 @@ -71,6 +68,7 @@
    9.23      for (unsigned int i = 0 ; i < ASC_MAX_WINDOWS ; i++) {
    9.24          asc_window_destroy(&asc_context.windows[i]);
    9.25      }
    9.26 +    asc_font_cache_clear();
    9.27  
    9.28      // quit SDL
    9.29      if (TTF_WasInit())
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/font.c	Tue Nov 07 21:24:06 2023 +0100
    10.3 @@ -0,0 +1,90 @@
    10.4 +/*
    10.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    10.6 + * Copyright 2023 Mike Becker. All rights reserved.
    10.7 + *
    10.8 + * Redistribution and use in source and binary forms, with or without
    10.9 + * modification, are permitted provided that the following conditions are met:
   10.10 + *
   10.11 + *   1. Redistributions of source code must retain the above copyright
   10.12 + *      notice, this list of conditions and the following disclaimer.
   10.13 + *
   10.14 + *   2. Redistributions in binary form must reproduce the above copyright
   10.15 + *      notice, this list of conditions and the following disclaimer in the
   10.16 + *      documentation and/or other materials provided with the distribution.
   10.17 + *
   10.18 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   10.19 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   10.20 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   10.21 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   10.22 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   10.23 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   10.24 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   10.25 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   10.26 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   10.27 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   10.28 + * POSSIBILITY OF SUCH DAMAGE.
   10.29 + */
   10.30 +
   10.31 +#include "ascension/font.h"
   10.32 +#include "ascension/context.h"
   10.33 +#include "ascension/error.h"
   10.34 +
   10.35 +static char const *asc_font_filename(enum AscFontStyle style) {
   10.36 +    // TODO: do not assume we are running from the program dir
   10.37 +    switch (style) {
   10.38 +        case ASC_FONT_REGULAR:
   10.39 +            return "fonts/OpenSans-Regular.ttf";
   10.40 +        case ASC_FONT_BOLD:
   10.41 +            return "fonts/OpenSans-Bold.ttf";
   10.42 +        case ASC_FONT_ITALIC:
   10.43 +            return "fonts/OpenSans-Italic.ttf";
   10.44 +        case ASC_FONT_BOLD_ITALIC:
   10.45 +            return "fonts/OpenSans-BoldItalic.ttf";
   10.46 +    }
   10.47 +}
   10.48 +
   10.49 +AscFont const *asc_font(enum AscFontStyle style, int size) {
   10.50 +    for (unsigned int i = 0 ; i < asc_context.fonts_loaded ; i++) {
   10.51 +        AscFont *font = &asc_context.fonts[i];
   10.52 +        if (font->size == size && font->style == style) {
   10.53 +            return font;
   10.54 +        }
   10.55 +    }
   10.56 +
   10.57 +    if (asc_context.fonts_loaded == ASC_MAX_FONTS) {
   10.58 +        asc_dprintf("WARNING: Maximum number of fonts reached, wiping cache!");
   10.59 +        asc_font_cache_clear();
   10.60 +    }
   10.61 +
   10.62 +    unsigned int slot = asc_context.fonts_loaded++;
   10.63 +    AscFont *font = &asc_context.fonts[slot];
   10.64 +    font->size = size;
   10.65 +    font->style = style;
   10.66 +    font->ptr = TTF_OpenFont(asc_font_filename(style), size);
   10.67 +    if (font->ptr == NULL) {
   10.68 +        asc_context.fonts_loaded--;
   10.69 +        asc_error(TTF_GetError());
   10.70 +        return NULL;
   10.71 +    }
   10.72 +    asc_dprintf("Loaded font size %u, style %u in slot %u", size, style, slot);
   10.73 +    return font;
   10.74 +}
   10.75 +
   10.76 +void asc_font_cache_clear(void) {
   10.77 +    asc_dprintf("Fonts in cache that are being unloaded: %u", asc_context.fonts_loaded);
   10.78 +    while (asc_context.fonts_loaded > 0) {
   10.79 +        unsigned int i = --asc_context.fonts_loaded;
   10.80 +        AscFont *font = &asc_context.fonts[i];
   10.81 +        TTF_CloseFont(font->ptr);
   10.82 +        font->ptr = NULL;
   10.83 +    }
   10.84 +}
   10.85 +
   10.86 +AscFont const *asc_font_cache_validate(AscFont const *font) {
   10.87 +    if (font->ptr) {
   10.88 +        return font;
   10.89 +    } else {
   10.90 +        asc_dprintf("Cache miss for font size %u, style %u", font->size, font->style);
   10.91 +        return asc_font(font->style, font->size);
   10.92 +    }
   10.93 +}
    11.1 --- a/test/Makefile	Tue Nov 07 21:13:04 2023 +0100
    11.2 +++ b/test/Makefile	Tue Nov 07 21:24:06 2023 +0100
    11.3 @@ -40,7 +40,8 @@
    11.4  
    11.5  $(BUILD_DIR)/sandbox.o: sandbox.c ../src/ascension/ascension.h \
    11.6   ../src/ascension/context.h ../src/ascension/window.h \
    11.7 - ../src/ascension/datatypes.h ../src/ascension/error.h
    11.8 + ../src/ascension/datatypes.h ../src/ascension/font.h \
    11.9 + ../src/ascension/error.h
   11.10  	@echo "Compiling $<"
   11.11  	$(CC) -o $@ $(CFLAGS) -c $<
   11.12  

mercurial