fontutil.c revision a96d7823
1/* 2 3Copyright 1991, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27*/ 28 29/* 30 * Author: Keith Packard, MIT X Consortium 31 */ 32 33#ifdef HAVE_CONFIG_H 34#include <config.h> 35#endif 36#include "libxfontint.h" 37#include <X11/fonts/fontmisc.h> 38#include <X11/fonts/fontstruct.h> 39#include <X11/fonts/FSproto.h> 40#include <X11/fonts/fontutil.h> 41 42/* Define global here... doesn't hurt the servers, and avoids 43 unresolved references in font clients. */ 44 45static int defaultGlyphCachingMode = DEFAULT_GLYPH_CACHING_MODE; 46int glyphCachingMode = DEFAULT_GLYPH_CACHING_MODE; 47 48#define MIN(a,b) ((a)<(b)?(a):(b)) 49#define MAX(a,b) ((a)>(b)?(a):(b)) 50 51void 52xfont2_query_glyph_extents(FontPtr pFont, 53 CharInfoPtr *charinfo, 54 unsigned long count, 55 ExtentInfoRec *info) 56{ 57 register unsigned long i; 58 xCharInfo *pCI; 59 60 info->drawDirection = pFont->info.drawDirection; 61 62 info->fontAscent = pFont->info.fontAscent; 63 info->fontDescent = pFont->info.fontDescent; 64 65 if (count != 0) { 66 67 pCI = &((*charinfo)->metrics); charinfo++; 68 /* ignore nonexisting characters when calculating text extents */ 69 if ( !((pCI->characterWidth == 0) 70 && (pCI->rightSideBearing == 0) 71 && (pCI->leftSideBearing == 0) 72 && (pCI->ascent == 0) 73 && (pCI->descent == 0)) ) { 74 info->overallAscent = pCI->ascent; 75 info->overallDescent = pCI->descent; 76 info->overallLeft = pCI->leftSideBearing; 77 info->overallRight = pCI->rightSideBearing; 78 info->overallWidth = pCI->characterWidth; 79 } 80 81 if (pFont->info.constantMetrics && pFont->info.noOverlap) { 82 info->overallWidth *= count; 83 info->overallRight += (info->overallWidth - 84 pCI->characterWidth); 85 } else { 86 for (i = 1; i < count; i++) { 87 pCI = &((*charinfo)->metrics); charinfo++; 88 /* ignore nonexisting characters when calculating extents */ 89 if ( !((pCI->characterWidth == 0) 90 && (pCI->rightSideBearing == 0) 91 && (pCI->leftSideBearing == 0) 92 && (pCI->ascent == 0) 93 && (pCI->descent == 0)) ) { 94 info->overallAscent = MAX( 95 info->overallAscent, 96 pCI->ascent); 97 info->overallDescent = MAX( 98 info->overallDescent, 99 pCI->descent); 100 info->overallLeft = MIN( 101 info->overallLeft, 102 info->overallWidth + pCI->leftSideBearing); 103 info->overallRight = MAX( 104 info->overallRight, 105 info->overallWidth + pCI->rightSideBearing); 106 /* 107 * yes, this order is correct; overallWidth IS incremented 108 * last 109 */ 110 info->overallWidth += pCI->characterWidth; 111 } 112 } 113 } 114 } else { 115 info->overallAscent = 0; 116 info->overallDescent = 0; 117 info->overallWidth = 0; 118 info->overallLeft = 0; 119 info->overallRight = 0; 120 } 121} 122 123Bool 124xfont2_query_text_extents(FontPtr pFont, 125 unsigned long count, 126 unsigned char *chars, 127 ExtentInfoRec *info) 128{ 129 xCharInfo **charinfo; 130 unsigned long n; 131 FontEncoding encoding; 132 int cm; 133 int i; 134 unsigned long t; 135 xCharInfo *defaultChar = 0; 136 unsigned char defc[2]; 137 int firstReal; 138 139 charinfo = malloc(count * sizeof(xCharInfo *)); 140 if (!charinfo) 141 return FALSE; 142 encoding = TwoD16Bit; 143 if (pFont->info.lastRow == 0) 144 encoding = Linear16Bit; 145 (*pFont->get_metrics) (pFont, count, chars, encoding, &n, charinfo); 146 147 /* Do default character substitution as get_metrics doesn't */ 148 149#define IsNonExistentChar(ci) (!(ci) || \ 150 ((ci)->ascent == 0 && \ 151 (ci)->descent == 0 && \ 152 (ci)->leftSideBearing == 0 && \ 153 (ci)->rightSideBearing == 0 && \ 154 (ci)->characterWidth == 0)) 155 156 firstReal = n; 157 defc[0] = pFont->info.defaultCh >> 8; 158 defc[1] = pFont->info.defaultCh; 159 (*pFont->get_metrics) (pFont, 1, defc, encoding, &t, &defaultChar); 160 if ((IsNonExistentChar (defaultChar))) 161 defaultChar = 0; 162 for (i = 0; i < n; i++) 163 { 164 if ((IsNonExistentChar (charinfo[i]))) 165 { 166 if (!defaultChar) 167 continue; 168 charinfo[i] = defaultChar; 169 } 170 if (firstReal == n) 171 firstReal = i; 172 } 173 cm = pFont->info.constantMetrics; 174 pFont->info.constantMetrics = FALSE; 175 xfont2_query_glyph_extents(pFont, (CharInfoPtr*) charinfo + firstReal, 176 n - firstReal, info); 177 pFont->info.constantMetrics = cm; 178 free(charinfo); 179 return TRUE; 180} 181 182Bool 183xfont2_parse_glyph_caching_mode(char *str) 184{ 185 if (!strcmp(str, "none")) defaultGlyphCachingMode = CACHING_OFF; 186 else if (!strcmp(str, "all")) defaultGlyphCachingMode = CACHE_ALL_GLYPHS; 187 else if (!strcmp(str, "16")) defaultGlyphCachingMode = CACHE_16_BIT_GLYPHS; 188 else return FALSE; 189 return TRUE; 190} 191 192void 193xfont2_init_glyph_caching(void) 194{ 195 /* Set glyphCachingMode to the mode the server hopes to 196 support. DDX drivers that do not support the requested level 197 of glyph caching can call SetGlyphCachingMode to lower the 198 level of support. 199 */ 200 201 glyphCachingMode = defaultGlyphCachingMode; 202} 203 204/* ddxen can call SetGlyphCachingMode to inform us of what level of glyph 205 * caching they can support. 206 */ 207void 208xfont2_set_glyph_caching_mode(int newmode) 209{ 210 if ( (glyphCachingMode > newmode) && (newmode >= 0) ) 211 glyphCachingMode = newmode; 212} 213 214#define range_alloc_granularity 16 215#define mincharp(p) ((p)->min_char_low + ((p)->min_char_high << 8)) 216#define maxcharp(p) ((p)->max_char_low + ((p)->max_char_high << 8)) 217 218/* add_range(): Add range to a list of ranges, with coalescence */ 219int 220add_range(fsRange *newrange, 221 int *nranges, 222 fsRange **range, 223 Bool charset_subset) 224{ 225 int first, last, middle; 226 unsigned long keymin, keymax; 227 unsigned long ptrmin = 0, ptrmax = 0; 228 fsRange *ptr = NULL, *ptr1, *ptr2, *endptr; 229 230 /* There are two different ways to treat ranges: 231 232 1) Charset subsetting (support of the HP XLFD enhancements), in 233 which a range of 0x1234,0x3456 means all numbers between 234 0x1234 and 0x3456, and in which min and max might be swapped. 235 236 2) Row/column ranges, in which a range of 0x1234,0x3456 means the 237 ranges 0x1234-0x1256, 0x1334-0x1356, ... , 0x3434-0x3456. 238 This is for support of glyph caching. 239 240 The choice of treatment is selected with the "charset_subset" 241 flag */ 242 243 /* If newrange covers multiple rows; break up the rows */ 244 if (!charset_subset && newrange->min_char_high != newrange->max_char_high) 245 { 246 int i, err = 0; 247 fsRange temprange; 248 for (i = newrange->min_char_high; 249 i <= newrange->max_char_high; 250 i++) 251 { 252 temprange.min_char_low = newrange->min_char_low; 253 temprange.max_char_low = newrange->max_char_low; 254 temprange.min_char_high = temprange.max_char_high = i; 255 err = add_range(&temprange, nranges, range, charset_subset); 256 if (err != Successful) break; 257 } 258 return err; 259 } 260 261 keymin = mincharp(newrange); 262 keymax = maxcharp(newrange); 263 264 if (charset_subset && keymin > keymax) 265 { 266 unsigned long temp = keymin; 267 keymin = keymax; 268 keymax = temp; 269 } 270 271 /* add_range() maintains a sorted list; this makes possible coalescence 272 and binary searches */ 273 274 /* Binary search for a range with which the new range can merge */ 275 276 first = middle = 0; 277 last = *nranges - 1; 278 while (last >= first) 279 { 280 middle = (first + last) / 2; 281 ptr = (*range) + middle; 282 ptrmin = mincharp(ptr); 283 ptrmax = maxcharp(ptr); 284 285 if (ptrmin > 0 && keymax < ptrmin - 1) last = middle - 1; 286 else if (keymin > ptrmax + 1) first = middle + 1; 287 else if (!charset_subset) 288 { 289 /* We might have a range with which to merge... IF the 290 result doesn't cross rows */ 291 if (newrange->min_char_high != ptr->min_char_high) 292 last = first - 1; /* Force adding a new range */ 293 break; 294 } 295 else break; /* We have at least one range with which we can merge */ 296 } 297 298 if (last < first) 299 { 300 /* Search failed; we need to add a new range to the list. */ 301 302 /* Grow the list if necessary */ 303 if (*nranges == 0 || *range == (fsRange *)0) 304 { 305 *range = malloc(range_alloc_granularity * SIZEOF(fsRange)); 306 *nranges = 0; 307 } 308 else if (!(*nranges % range_alloc_granularity)) 309 { 310 *range = realloc(*range, (*nranges + range_alloc_granularity) * 311 SIZEOF(fsRange)); 312 } 313 314 /* If alloc failed, just return a null list */ 315 if (*range == (fsRange *)0) 316 { 317 *nranges = 0; 318 return AllocError; 319 } 320 321 /* Should new entry go *at* or *after* ptr? */ 322 ptr = (*range) + middle; 323 if (middle < *nranges && keymin > ptrmin) ptr++; /* after */ 324 325 /* Open up a space for our new range */ 326 memmove((char *)(ptr + 1), 327 (char *)ptr, 328 (char *)(*range + *nranges) - (char *)ptr); 329 330 /* Insert the new range */ 331 ptr->min_char_low = keymin & 0xff; 332 ptr->min_char_high = keymin >> 8; 333 ptr->max_char_low = keymax & 0xff; 334 ptr->max_char_high = keymax >> 8; 335 336 /* Update range count */ 337 (*nranges)++; 338 339 /* Done */ 340 return Successful; 341 } 342 343 /* Join our new range to that pointed to by "ptr" */ 344 if (keymin < ptrmin) 345 { 346 ptr->min_char_low = keymin & 0xff; 347 ptr->min_char_high = keymin >> 8; 348 } 349 if (keymax > ptrmax) 350 { 351 ptr->max_char_low = keymax & 0xff; 352 ptr->max_char_high = keymax >> 8; 353 } 354 355 ptrmin = mincharp(ptr); 356 ptrmax = maxcharp(ptr); 357 358 endptr = *range + *nranges; 359 360 for (ptr1 = ptr; ptr1 >= *range; ptr1--) 361 { 362 if (ptrmin <= maxcharp(ptr1) + 1) 363 { 364 if (!charset_subset && ptr->min_char_high != ptr1->min_char_high) 365 break; 366 if (ptrmin >= mincharp(ptr1)) 367 ptrmin = mincharp(ptr1); 368 } 369 else break; 370 } 371 for (ptr2 = ptr; ptr2 < endptr; ptr2++) 372 { 373 if ((ptr2->min_char_low == 0 && ptr2->min_char_high == 0) || 374 ptrmax >= mincharp(ptr2) - 1) 375 { 376 if (!charset_subset && ptr->min_char_high != ptr2->min_char_high) 377 break; 378 if (ptrmax <= maxcharp(ptr2)) 379 ptrmax = maxcharp(ptr2); 380 } 381 else break; 382 } 383 384 /* We need to coalesce ranges between ptr1 and ptr2 exclusive */ 385 ptr1++; 386 ptr2--; 387 if (ptr1 != ptr2) 388 { 389 memmove(ptr1, ptr2, (char *)endptr - (char *)ptr2); 390 *nranges -= (ptr2 - ptr1); 391 } 392 393 /* Write the new range into the range list */ 394 ptr1->min_char_low = ptrmin & 0xff; 395 ptr1->min_char_high = ptrmin >> 8; 396 ptr1->max_char_low = ptrmax & 0xff; 397 ptr1->max_char_high = ptrmax >> 8; 398 399 return Successful; 400} 401