| 1 | /**************************************************************************** |
| 2 | * |
| 3 | * ftcglyph.h |
| 4 | * |
| 5 | * FreeType abstract glyph cache (specification). |
| 6 | * |
| 7 | * Copyright (C) 2000-2023 by |
| 8 | * David Turner, Robert Wilhelm, and Werner Lemberg. |
| 9 | * |
| 10 | * This file is part of the FreeType project, and may only be used, |
| 11 | * modified, and distributed under the terms of the FreeType project |
| 12 | * license, LICENSE.TXT. By continuing to use, modify, or distribute |
| 13 | * this file you indicate that you have read the license and |
| 14 | * understand and accept it fully. |
| 15 | * |
| 16 | */ |
| 17 | |
| 18 | |
| 19 | /* |
| 20 | * |
| 21 | * FTC_GCache is an _abstract_ cache object optimized to store glyph |
| 22 | * data. It works as follows: |
| 23 | * |
| 24 | * - It manages FTC_GNode objects. Each one of them can hold one or more |
| 25 | * glyph `items'. Item types are not specified in the FTC_GCache but |
| 26 | * in classes that extend it. |
| 27 | * |
| 28 | * - Glyph attributes, like face ID, character size, render mode, etc., |
| 29 | * can be grouped into abstract `glyph families'. This avoids storing |
| 30 | * the attributes within the FTC_GCache, since it is likely that many |
| 31 | * FTC_GNodes will belong to the same family in typical uses. |
| 32 | * |
| 33 | * - Each FTC_GNode is thus an FTC_Node with two additional fields: |
| 34 | * |
| 35 | * * gindex: A glyph index, or the first index in a glyph range. |
| 36 | * * family: A pointer to a glyph `family'. |
| 37 | * |
| 38 | * - Family types are not fully specific in the FTC_Family type, but |
| 39 | * by classes that extend it. |
| 40 | * |
| 41 | * Note that both FTC_ImageCache and FTC_SBitCache extend FTC_GCache. |
| 42 | * They share an FTC_Family sub-class called FTC_BasicFamily which is |
| 43 | * used to store the following data: face ID, pixel/point sizes, load |
| 44 | * flags. For more details see the file `src/cache/ftcbasic.c'. |
| 45 | * |
| 46 | * Client applications can extend FTC_GNode with their own FTC_GNode |
| 47 | * and FTC_Family sub-classes to implement more complex caches (e.g., |
| 48 | * handling automatic synthesis, like obliquing & emboldening, colored |
| 49 | * glyphs, etc.). |
| 50 | * |
| 51 | * See also the FTC_ICache & FTC_SCache classes in `ftcimage.h' and |
| 52 | * `ftcsbits.h', which both extend FTC_GCache with additional |
| 53 | * optimizations. |
| 54 | * |
| 55 | * A typical FTC_GCache implementation must provide at least the |
| 56 | * following: |
| 57 | * |
| 58 | * - FTC_GNode sub-class, e.g. MyNode, with relevant methods: |
| 59 | * my_node_new (must call FTC_GNode_Init) |
| 60 | * my_node_free (must call FTC_GNode_Done) |
| 61 | * my_node_compare (must call ftc_gnode_compare) |
| 62 | * my_node_remove_faceid (must call ftc_gnode_unselect in case |
| 63 | * of match) |
| 64 | * |
| 65 | * - FTC_Family sub-class, e.g. MyFamily, with relevant methods: |
| 66 | * my_family_compare |
| 67 | * my_family_init |
| 68 | * my_family_reset (optional) |
| 69 | * my_family_done |
| 70 | * |
| 71 | * - FTC_GQuery sub-class, e.g. MyQuery, to hold cache-specific query |
| 72 | * data. |
| 73 | * |
| 74 | * - Constant structures for a FTC_GNodeClass. |
| 75 | * |
| 76 | * - MyCacheNew() can be implemented easily as a call to the convenience |
| 77 | * function FTC_GCache_New. |
| 78 | * |
| 79 | * - MyCacheLookup with a call to FTC_GCache_Lookup. This function will |
| 80 | * automatically: |
| 81 | * |
| 82 | * - Search for the corresponding family in the cache, or create |
| 83 | * a new one if necessary. Put it in FTC_GQUERY(myquery).family |
| 84 | * |
| 85 | * - Call FTC_Cache_Lookup. |
| 86 | * |
| 87 | * If it returns NULL, you should create a new node, then call |
| 88 | * ftc_cache_add as usual. |
| 89 | */ |
| 90 | |
| 91 | |
| 92 | /************************************************************************** |
| 93 | * |
| 94 | * Important: The functions defined in this file are only used to |
| 95 | * implement an abstract glyph cache class. You need to |
| 96 | * provide additional logic to implement a complete cache. |
| 97 | * |
| 98 | */ |
| 99 | |
| 100 | |
| 101 | /*************************************************************************/ |
| 102 | /*************************************************************************/ |
| 103 | /*************************************************************************/ |
| 104 | /*************************************************************************/ |
| 105 | /*************************************************************************/ |
| 106 | /********* *********/ |
| 107 | /********* WARNING, THIS IS BETA CODE. *********/ |
| 108 | /********* *********/ |
| 109 | /*************************************************************************/ |
| 110 | /*************************************************************************/ |
| 111 | /*************************************************************************/ |
| 112 | /*************************************************************************/ |
| 113 | /*************************************************************************/ |
| 114 | |
| 115 | |
| 116 | #ifndef FTCGLYPH_H_ |
| 117 | #define FTCGLYPH_H_ |
| 118 | |
| 119 | |
| 120 | #include "ftcmanag.h" |
| 121 | |
| 122 | |
| 123 | FT_BEGIN_HEADER |
| 124 | |
| 125 | |
| 126 | /* |
| 127 | * We can group glyphs into `families'. Each family correspond to a |
| 128 | * given face ID, character size, transform, etc. |
| 129 | * |
| 130 | * Families are implemented as MRU list nodes. They are |
| 131 | * reference-counted. |
| 132 | */ |
| 133 | |
| 134 | typedef struct FTC_FamilyRec_ |
| 135 | { |
| 136 | FTC_MruNodeRec mrunode; |
| 137 | FT_UInt num_nodes; /* current number of nodes in this family */ |
| 138 | FTC_Cache cache; |
| 139 | FTC_MruListClass clazz; |
| 140 | |
| 141 | } FTC_FamilyRec, *FTC_Family; |
| 142 | |
| 143 | #define FTC_FAMILY( x ) ( (FTC_Family)(x) ) |
| 144 | #define FTC_FAMILY_P( x ) ( (FTC_Family*)(x) ) |
| 145 | |
| 146 | |
| 147 | typedef struct FTC_GNodeRec_ |
| 148 | { |
| 149 | FTC_NodeRec node; |
| 150 | FTC_Family family; |
| 151 | FT_UInt gindex; |
| 152 | |
| 153 | } FTC_GNodeRec, *FTC_GNode; |
| 154 | |
| 155 | #define FTC_GNODE( x ) ( (FTC_GNode)(x) ) |
| 156 | #define FTC_GNODE_P( x ) ( (FTC_GNode*)(x) ) |
| 157 | |
| 158 | |
| 159 | typedef struct FTC_GQueryRec_ |
| 160 | { |
| 161 | FT_UInt gindex; |
| 162 | FTC_Family family; |
| 163 | |
| 164 | } FTC_GQueryRec, *FTC_GQuery; |
| 165 | |
| 166 | #define FTC_GQUERY( x ) ( (FTC_GQuery)(x) ) |
| 167 | |
| 168 | |
| 169 | /************************************************************************** |
| 170 | * |
| 171 | * These functions are exported so that they can be called from |
| 172 | * user-provided cache classes; otherwise, they are really part of the |
| 173 | * cache sub-system internals. |
| 174 | */ |
| 175 | |
| 176 | /* must be called by derived FTC_Node_InitFunc routines */ |
| 177 | FT_LOCAL( void ) |
| 178 | FTC_GNode_Init( FTC_GNode node, |
| 179 | FT_UInt gindex, /* glyph index for node */ |
| 180 | FTC_Family family ); |
| 181 | |
| 182 | /* call this function to clear a node's family -- this is necessary */ |
| 183 | /* to implement the `node_remove_faceid' cache method correctly */ |
| 184 | FT_LOCAL( void ) |
| 185 | FTC_GNode_UnselectFamily( FTC_GNode gnode, |
| 186 | FTC_Cache cache ); |
| 187 | |
| 188 | /* must be called by derived FTC_Node_DoneFunc routines */ |
| 189 | FT_LOCAL( void ) |
| 190 | FTC_GNode_Done( FTC_GNode node, |
| 191 | FTC_Cache cache ); |
| 192 | |
| 193 | |
| 194 | FT_LOCAL( void ) |
| 195 | FTC_Family_Init( FTC_Family family, |
| 196 | FTC_Cache cache ); |
| 197 | |
| 198 | typedef struct FTC_GCacheRec_ |
| 199 | { |
| 200 | FTC_CacheRec cache; |
| 201 | FTC_MruListRec families; |
| 202 | |
| 203 | } FTC_GCacheRec, *FTC_GCache; |
| 204 | |
| 205 | #define FTC_GCACHE( x ) ((FTC_GCache)(x)) |
| 206 | |
| 207 | |
| 208 | #if 0 |
| 209 | /* can be used as @FTC_Cache_InitFunc */ |
| 210 | FT_LOCAL( FT_Error ) |
| 211 | FTC_GCache_Init( FTC_GCache cache ); |
| 212 | #endif |
| 213 | |
| 214 | |
| 215 | #if 0 |
| 216 | /* can be used as @FTC_Cache_DoneFunc */ |
| 217 | FT_LOCAL( void ) |
| 218 | FTC_GCache_Done( FTC_GCache cache ); |
| 219 | #endif |
| 220 | |
| 221 | |
| 222 | /* the glyph cache class adds fields for the family implementation */ |
| 223 | typedef struct FTC_GCacheClassRec_ |
| 224 | { |
| 225 | FTC_CacheClassRec clazz; |
| 226 | FTC_MruListClass family_class; |
| 227 | |
| 228 | } FTC_GCacheClassRec; |
| 229 | |
| 230 | typedef const FTC_GCacheClassRec* FTC_GCacheClass; |
| 231 | |
| 232 | #define FTC_GCACHE_CLASS( x ) ((FTC_GCacheClass)(x)) |
| 233 | |
| 234 | #define FTC_CACHE_GCACHE_CLASS( x ) \ |
| 235 | FTC_GCACHE_CLASS( FTC_CACHE( x )->org_class ) |
| 236 | #define FTC_CACHE_FAMILY_CLASS( x ) \ |
| 237 | ( (FTC_MruListClass)FTC_CACHE_GCACHE_CLASS( x )->family_class ) |
| 238 | |
| 239 | |
| 240 | /* convenience function; use it instead of FTC_Manager_Register_Cache */ |
| 241 | FT_LOCAL( FT_Error ) |
| 242 | FTC_GCache_New( FTC_Manager manager, |
| 243 | FTC_GCacheClass clazz, |
| 244 | FTC_GCache *acache ); |
| 245 | |
| 246 | #ifndef FTC_INLINE |
| 247 | FT_LOCAL( FT_Error ) |
| 248 | FTC_GCache_Lookup( FTC_GCache cache, |
| 249 | FT_Offset hash, |
| 250 | FT_UInt gindex, |
| 251 | FTC_GQuery query, |
| 252 | FTC_Node *anode ); |
| 253 | #endif |
| 254 | |
| 255 | |
| 256 | /* */ |
| 257 | |
| 258 | |
| 259 | #define FTC_FAMILY_FREE( family, cache ) \ |
| 260 | FTC_MruList_Remove( &FTC_GCACHE((cache))->families, \ |
| 261 | (FTC_MruNode)(family) ) |
| 262 | |
| 263 | |
| 264 | #ifdef FTC_INLINE |
| 265 | |
| 266 | #define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ |
| 267 | gindex, query, node, error ) \ |
| 268 | FT_BEGIN_STMNT \ |
| 269 | FTC_GCache _gcache = FTC_GCACHE( cache ); \ |
| 270 | FTC_GQuery _gquery = (FTC_GQuery)( query ); \ |
| 271 | FTC_MruNode_CompareFunc _fcompare = (FTC_MruNode_CompareFunc)(famcmp); \ |
| 272 | FTC_MruNode _mrunode; \ |
| 273 | \ |
| 274 | \ |
| 275 | _gquery->gindex = (gindex); \ |
| 276 | \ |
| 277 | FTC_MRULIST_LOOKUP_CMP( &_gcache->families, _gquery, _fcompare, \ |
| 278 | _mrunode, error ); \ |
| 279 | _gquery->family = FTC_FAMILY( _mrunode ); \ |
| 280 | if ( !error ) \ |
| 281 | { \ |
| 282 | FTC_Family _gqfamily = _gquery->family; \ |
| 283 | \ |
| 284 | \ |
| 285 | _gqfamily->num_nodes++; \ |
| 286 | \ |
| 287 | FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ); \ |
| 288 | \ |
| 289 | if ( --_gqfamily->num_nodes == 0 ) \ |
| 290 | FTC_FAMILY_FREE( _gqfamily, _gcache ); \ |
| 291 | } \ |
| 292 | FT_END_STMNT |
| 293 | /* */ |
| 294 | |
| 295 | #else /* !FTC_INLINE */ |
| 296 | |
| 297 | #define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ |
| 298 | gindex, query, node, error ) \ |
| 299 | FT_BEGIN_STMNT \ |
| 300 | \ |
| 301 | error = FTC_GCache_Lookup( FTC_GCACHE( cache ), hash, gindex, \ |
| 302 | FTC_GQUERY( query ), &node ); \ |
| 303 | \ |
| 304 | FT_END_STMNT |
| 305 | |
| 306 | #endif /* !FTC_INLINE */ |
| 307 | |
| 308 | |
| 309 | FT_END_HEADER |
| 310 | |
| 311 | |
| 312 | #endif /* FTCGLYPH_H_ */ |
| 313 | |
| 314 | |
| 315 | /* END */ |
| 316 | |