%% options copyright owner = Dirk Krause copyright year = 2017-xxxx SPDX-License-Identifier: BSD-3-Clause %% header /** @file dk4fontc.h LaTeX font collector. */ #ifndef DK4CONF_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4conf.h" #else #include #endif #endif #ifndef DK4TYPES_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4types.h" #else #include #endif #endif #ifndef DK4ERROR_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4error.h" #else #include #endif #endif #ifndef DK4FONT_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4font.h" #else #include #endif #endif #ifndef DK4STO_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4sto.h" #else #include #endif #endif /** How to use specified font and size. */ enum dk4_gra_tf_t_ { DK4_GRA_TF_NONE_NONE = 0 , /**< No font choosing. */ DK4_GRA_TF_NONE_SIZE = 1 , /**< No font, with size. */ DK4_GRA_TF_SIMILAR_NONE = 2 , /**< Choose similar font, no size. */ DK4_GRA_TF_SIMILAR_SIZE = 3 , /**< Choose similar font, with size. */ DK4_GRA_TF_EXACT_NONE = 4 , /**< Choose exact font but no size. */ DK4_GRA_TF_EXACT_SIZE = 5 , /**< Exact font and size. */ /** For normal text use exact font as specified. */ DK4_GRA_TF_NORMAL = DK4_GRA_TF_EXACT_SIZE , /** For special text use similar features and size. */ DK4_GRA_TF_SPECIAL = DK4_GRA_TF_SIMILAR_SIZE , }; /** How to use specified font and size. */ typedef enum dk4_gra_tf_t_ dk4_gra_tf_t; /** One font to register. */ typedef struct { double fsz; /**< Font size in pt. */ size_t nf; /**< Number of font in font collection. */ int fno; /**< Font number or feature set. */ int fex; /**< Flag: Use exact font. */ } dk4_font_item_t; /** Font collection. */ typedef struct { dk4_sto_t *s_fo; /**< Fonts by font ID or font features. */ dk4_sto_t *s_fn; /**< Fonts by number. */ dk4_sto_it_t *i_fo; /**< Iterator for fonts by ID or features. */ dk4_sto_it_t *i_fn; /**< Iterator for fonts by number. */ size_t nfonts; /**< Number of fonts stored, next font. */ } dk4_font_collector_t; #ifdef __cplusplus extern "C" { #endif /** Open new font collector, allocate resources. After using a font collector obtained from this function the collector must be closed using the dk4fontc_close() function. @param erp Error report for diagnostics. @return Valid pointer to new font collector on success, NULL on error. Error codes: - DK4_E_MEMORY_ALLOCATION_FAILED
if there is not enough memory available. */ dk4_font_collector_t * dk4fontc_open( dk4_er_t *erp ); /** Close font collector, release resources. @param fc Font collector to close and release. */ void dk4fontc_close( dk4_font_collector_t *fc ); /** Check whether a specified font is already in the collector, add if necessary. @param pdst Address of result variable for font number. @param fc Font collector to query. @param fno Font number. @param fsz Font size in pt. @param fex Flag: Use exact font (1) or similar font (0). @param erp Error report. @return 1 on success (font in collector or successfully added), 0 on error (failed to add). Error codes: - DK4_E_INVALID_ARGUMENTS
if any argument is invalid (pdst or fc is NULL, fno is outside the valid range or fsz is negative), - DK4_E_MEMORY_ALLOCATION_FAILED
if a memory allocation failed. - DK4_E_MATH_OVERFLOW
on numeric overflow in the number of used fonts (too many fonts used). */ int dk4fontc_add_font( size_t *pdst, dk4_font_collector_t *fc, int fno, double fsz, int fex, dk4_er_t *erp ); #ifdef __cplusplus } #endif /* vim: set ai sw=4 ts=4 : */ %% module #include "dk4conf.h" #ifndef DK4FONTC_H_INCLUDED #include "dk4fontc.h" #endif #ifndef DK4MEM_H_INCLUDED #include "dk4mem.h" #endif #ifndef DK4UNUSED_H_INCLUDED #include "dk4unused.h" #endif #ifndef DK4MATH_H_INCLUDED #include "dk4math.h" #endif #ifndef DK4NUMCO_H_INCLUDED #include "dk4numco.h" #endif #if DK4_HAVE_MATH_H #ifndef MATH_H_INCLUDED #if DK4_ON_WINDOWS #ifndef _USE_MATH_DEFINES #define _USE_MATH_DEFINES 1 #endif #endif #include #define MATH_H_INCLUDED 1 #endif #endif #ifndef GRA_H_INCLUDED #include "gra.h" #endif #if DK4_HAVE_ASSERT_H #ifndef ASSERT_H_INCLUDED #include #define ASSERT_H_INCLUDED 1 #endif #endif /** Minimum size difference required to see different font sizes. */ #define FNT_EPS 1.0e-4 $!trace-include /** Initialize a font item. @param ptr Item to initialize. */ static void dk4fontc_item_init(dk4_font_item_t *ptr) { $? "+ dk4fontc_item_init" #if DK4_USE_ASSERT assert(NULL != ptr); #endif dk4mem_reset(ptr, sizeof(dk4_font_item_t), NULL); ptr->fsz = 0.0; ptr->nf = (size_t)0UL; ptr->fno = DK4_FONT_TIMES_ROMAN; ptr->fex = DK4_GRA_TF_NONE_NONE; $? "- dk4fontc_item_init" } static int dk4_font_item_equal_fex( const dk4_font_item_t *pl, const dk4_font_item_t *pr ) { int back = 0; if (DK4_GRA_TF_NONE_NONE != pl->fex) { switch (pl->fex) { case DK4_GRA_TF_NONE_NONE : { /* Intentionally empty to avoid compiler warnings. */ } break; case DK4_GRA_TF_EXACT_SIZE : case DK4_GRA_TF_SIMILAR_SIZE : { if (pl->fno > pr->fno) { back = 1; } else { if (pl->fno < pr->fno) { back = -1; } } if (0 == back) { if (isgreater(pl->fsz, (FNT_EPS + pr->fsz))) { back = 1; } else { if (isgreater(pr->fsz, (FNT_EPS + pl->fsz))) { back = -1; } } } } break; case DK4_GRA_TF_EXACT_NONE : case DK4_GRA_TF_SIMILAR_NONE : { if (pl->fno > pr->fno) { back = 1; } else { if (pl->fno < pr->fno) { back = -1; } } } break; default : { /* DK4_GRA_TF_NONE_SIZE */ if (isgreater(pl->fsz, (FNT_EPS + pr->fsz))) { back = 1; } else { if (isgreater(pr->fsz, (FNT_EPS + pl->fsz))) { back = -1; } } } break; } } return back; } /** Compare two font items by font number or by font id. @param l Left font item. @param r Right font item. @param cr Comparison criteria (1=by number,0=normal). @return Comparison result. */ static int dk4_font_item_compare_by_fontno_and_size( const void *l, const void *r, int cr ) { int back = 0; const dk4_font_item_t *pl; /* Left object */ const dk4_font_item_t *pr; /* Right object */ $? "+ dk4_font_item_compare_by_fontno_and_size" pl = (const dk4_font_item_t *)l; pr = (const dk4_font_item_t *)r; if (NULL != pl) { if (NULL != pr) { switch (cr) { case 1 : { if (pl->nf > pr->nf) { back = 1; } else { if (pl->nf < pr->nf) { back = -1; } } } break; default : { /* First check domain (exact font or similar font) */ if (pl->fex > pr->fex) { back = 1; } else { if (pl->fex < pr->fex) { back = -1; } } if (0 == back) { back = dk4_font_item_equal_fex(pl, pr); } } break; } } else { back = 1; } } else { if (NULL != pr) { back = -1; } } $? "- dk4_font_item_compare_by_fontno_and_size %d", back return back; } /** Initialize new font collector. @param ptr Font collector to initialize. */ static void dk4fontc_init(dk4_font_collector_t *ptr) { $? "+ dk4fontc_init" #if DK4_USE_ASSERT assert(NULL != ptr); #endif ptr->s_fo = ptr->s_fn = NULL; ptr->i_fo = ptr->i_fn = NULL; ptr->nfonts = 0; $? "- dk4fontc_init" } void dk4fontc_close( dk4_font_collector_t *fc ) { dk4_font_item_t *fi; /* Current font item to release */ $? "+ dk4fontc_close %d", TR_IPTR(fc) #if DK4_USE_ASSERT assert(NULL != fc); #endif if (NULL != fc) { /* s_fn only contains copy */ if (NULL != fc->s_fn) { if (NULL != fc->i_fn) { dk4sto_it_close(fc->i_fn); } dk4sto_close(fc->s_fn); } fc->s_fn = NULL; fc->i_fn = NULL; /* s_fo contains the real data, we must delete here */ if (NULL != fc->s_fo) { if (NULL != fc->i_fo) { dk4sto_it_reset(fc->i_fo); do { fi = (dk4_font_item_t *)dk4sto_it_next(fc->i_fo); if (NULL != fi) { $? ". one font item to delete" dk4mem_free(fi); } } while(NULL != fi); } dk4sto_close(fc->s_fo); } fc->s_fo = NULL; fc->i_fo = NULL; dk4fontc_init(fc); dk4mem_free(fc); } $? "- dk4fontc_close" } dk4_font_collector_t * dk4fontc_open( dk4_er_t *erp ) { dk4_font_collector_t *back = NULL; int ok = 0; $? "+ dk4fontc_open" back = dk4mem_new(dk4_font_collector_t,1,erp); if (NULL != back) { dk4fontc_init(back); back->s_fo = dk4sto_open(erp); back->s_fn = dk4sto_open(erp); if ((NULL != back->s_fo) && (NULL != back->s_fn)) { dk4sto_set_comp( back->s_fo, dk4_font_item_compare_by_fontno_and_size, 0 ); dk4sto_set_comp( back->s_fn, dk4_font_item_compare_by_fontno_and_size, 1 ); back->i_fo = dk4sto_it_open(back->s_fo, erp); back->i_fn = dk4sto_it_open(back->s_fn, erp); if ((NULL != back->i_fo) && (NULL != back->i_fn)) { ok = 1; } } if (0 == ok) { dk4fontc_close(back); back = NULL; } } $? "- dk4fontc_open %d", TR_IPTR(back) return back; } int dk4fontc_add_font( size_t *pdst, dk4_font_collector_t *fc, int fno, double fsz, int fex, dk4_er_t *erp ) { dk4_font_item_t tv; /* Test value */ dk4_font_item_t *ptr; /* Item found */ dk4_font_number_t rfno; /* Real font number */ int back = 0; /* Function result */ $? "+ dk4fontc_add_font fno=%d fex=%d fsz=%lf", fno, fex, fsz #if DK4_USE_ASSERT assert(NULL != fc); assert(NULL != pdst); assert(0 <= fno); assert(0.0 < fsz); #endif /* Check command line arguments */ if ((NULL == pdst) || (NULL == fc) || (0 > fno) || (0.0 >= fsz)) { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } else { /* Initialize search record */ dk4fontc_item_init(&tv); tv.fsz = fsz; tv.nf = 0; tv.fex = fex; rfno = dk4font_number_from_int(fno); switch (fex) { case DK4_GRA_TF_SIMILAR_NONE : case DK4_GRA_TF_SIMILAR_SIZE : { tv.fno = dk4font_get_features(rfno); } break; default : { tv.fno = fno; } break; } /* Search */ ptr = (dk4_font_item_t *)dk4sto_it_find_like(fc->i_fo, &tv, 0); /* Success if found, otherwise create new entry */ if (NULL != ptr) { back = 1; *pdst = ptr->nf; } else { if (SIZE_MAX > fc->nfonts) { ptr = dk4mem_new(dk4_font_item_t,1,erp); if (NULL != ptr) { DK4_MEMCPY(ptr,&tv,sizeof(dk4_font_item_t)); ptr->nf = fc->nfonts; if (0 != dk4sto_add(fc->s_fo, ptr, erp)) { fc->nfonts += 1; if (0 != dk4sto_add(fc->s_fn, ptr, erp)) { back = 1; *pdst = ptr->nf; } } else { dk4mem_free(ptr); } } } else { dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW); } } } $? "- dk4fontc_add_font %d", back return back; } /* vim: set ai sw=4 ts=4 : */