1 /* $XConsortium: fontutil.c /main/11 1996/09/12 10:08:59 kaleb $ */
2 /* $XFree86: xc/lib/font/util/fontutil.c,v 3.1 1996/12/23 06:02:33 dawes Exp $ */
6 Copyright (c) 1991 X Consortium
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
16 The above copyright notice and this permission notice shall be included
17 in all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 OTHER DEALINGS IN THE SOFTWARE.
27 Except as contained in this notice, the name of the X Consortium shall
28 not be used in advertising or otherwise to promote the sale, use or
29 other dealings in this Software without prior written authorization
30 from the X Consortium.
35 * Author: Keith Packard, MIT X Consortium
39 #include "fontstruct.h"
42 /* Define global here... doesn't hurt the servers, and avoids
43 unresolved references in font clients. */
45 static int defaultGlyphCachingMode = DEFAULT_GLYPH_CACHING_MODE;
46 int glyphCachingMode = DEFAULT_GLYPH_CACHING_MODE;
49 GetGlyphs(font, count, chars, fontEncoding, glyphcount, glyphs)
53 FontEncoding fontEncoding;
54 unsigned long *glyphcount; /* RETURN */
55 CharInfoPtr *glyphs; /* RETURN */
57 (*font->get_glyphs) (font, count, chars, fontEncoding, glyphcount, glyphs);
60 #define MIN(a,b) ((a)<(b)?(a):(b))
61 #define MAX(a,b) ((a)>(b)?(a):(b))
64 QueryGlyphExtents(pFont, charinfo, count, info)
66 CharInfoPtr *charinfo;
70 register unsigned long i;
73 info->drawDirection = pFont->info.drawDirection;
75 info->fontAscent = pFont->info.fontAscent;
76 info->fontDescent = pFont->info.fontDescent;
80 pCI = &((*charinfo)->metrics); charinfo++;
81 /* ignore nonexisting characters when calculating text extents */
82 if ( !((pCI->characterWidth == 0)
83 && (pCI->rightSideBearing == 0)
84 && (pCI->leftSideBearing == 0)
86 && (pCI->descent == 0)) ) {
87 info->overallAscent = pCI->ascent;
88 info->overallDescent = pCI->descent;
89 info->overallLeft = pCI->leftSideBearing;
90 info->overallRight = pCI->rightSideBearing;
91 info->overallWidth = pCI->characterWidth;
94 if (pFont->info.constantMetrics && pFont->info.noOverlap) {
95 info->overallWidth *= count;
96 info->overallRight += (info->overallWidth -
99 for (i = 1; i < count; i++) {
100 pCI = &((*charinfo)->metrics); charinfo++;
101 /* ignore nonexisting characters when calculating extents */
102 if ( !((pCI->characterWidth == 0)
103 && (pCI->rightSideBearing == 0)
104 && (pCI->leftSideBearing == 0)
105 && (pCI->ascent == 0)
106 && (pCI->descent == 0)) ) {
107 info->overallAscent = MAX(
110 info->overallDescent = MAX(
111 info->overallDescent,
113 info->overallLeft = MIN(
115 info->overallWidth + pCI->leftSideBearing);
116 info->overallRight = MAX(
118 info->overallWidth + pCI->rightSideBearing);
120 * yes, this order is correct; overallWidth IS incremented
123 info->overallWidth += pCI->characterWidth;
128 info->overallAscent = 0;
129 info->overallDescent = 0;
130 info->overallWidth = 0;
131 info->overallLeft = 0;
132 info->overallRight = 0;
137 QueryTextExtents(pFont, count, chars, info)
140 unsigned char *chars;
143 xCharInfo **charinfo;
145 FontEncoding encoding;
149 xCharInfo *defaultChar = 0;
150 unsigned char defc[2];
153 charinfo = (xCharInfo **) xalloc(count * sizeof(xCharInfo *));
156 encoding = TwoD16Bit;
157 if (pFont->info.lastRow == 0)
158 encoding = Linear16Bit;
159 (*pFont->get_metrics) (pFont, count, chars, encoding, &n, charinfo);
161 /* Do default character substitution as get_metrics doesn't */
163 #define IsNonExistentChar(ci) (!(ci) || \
164 (ci)->ascent == 0 && \
165 (ci)->descent == 0 && \
166 (ci)->leftSideBearing == 0 && \
167 (ci)->rightSideBearing == 0 && \
168 (ci)->characterWidth == 0)
171 defc[0] = pFont->info.defaultCh >> 8;
172 defc[1] = pFont->info.defaultCh;
173 (*pFont->get_metrics) (pFont, 1, defc, encoding, &t, &defaultChar);
174 if (IsNonExistentChar (defaultChar))
176 for (i = 0; i < n; i++)
178 if (IsNonExistentChar (charinfo[i]))
182 charinfo[i] = defaultChar;
187 cm = pFont->info.constantMetrics;
188 pFont->info.constantMetrics = FALSE;
189 QueryGlyphExtents(pFont, charinfo + firstReal, n - firstReal, info);
190 pFont->info.constantMetrics = cm;
196 ParseGlyphCachingMode(str)
199 if (!strcmp(str, "none")) defaultGlyphCachingMode = CACHING_OFF;
200 else if (!strcmp(str, "all")) defaultGlyphCachingMode = CACHE_ALL_GLYPHS;
201 else if (!strcmp(str, "16")) defaultGlyphCachingMode = CACHE_16_BIT_GLYPHS;
209 /* Set glyphCachingMode to the mode the server hopes to
210 support. DDX drivers that do not support the requested level
211 of glyph caching can call SetGlyphCachingMode to lower the
215 glyphCachingMode = defaultGlyphCachingMode;
218 /* ddxen can call SetGlyphCachingMode to inform us of what level of glyph
219 * caching they can support.
222 SetGlyphCachingMode(newmode)
225 if ( (glyphCachingMode > newmode) && (newmode >= 0) )
226 glyphCachingMode = newmode;
229 #define range_alloc_granularity 16
230 #define mincharp(p) ((p)->min_char_low + ((p)->min_char_high << 8))
231 #define maxcharp(p) ((p)->max_char_low + ((p)->max_char_high << 8))
233 /* add_range(): Add range to a list of ranges, with coalescence */
235 add_range(newrange, nranges, range, charset_subset)
241 int first, last, middle;
242 unsigned long keymin, keymax;
243 unsigned long ptrmin, ptrmax;
244 fsRange *ptr, *ptr1, *ptr2, *endptr;
246 /* There are two different ways to treat ranges:
248 1) Charset subsetting (support of the HP XLFD enhancements), in
249 which a range of 0x1234,0x3456 means all numbers between
250 0x1234 and 0x3456, and in which min and max might be swapped.
252 2) Row/column ranges, in which a range of 0x1234,0x3456 means the
253 ranges 0x1234-0x1256, 0x1334-0x1356, ... , 0x3434-0x3456.
254 This is for support of glyph caching.
256 The choice of treatment is selected with the "charset_subset"
259 /* If newrange covers multiple rows; break up the rows */
260 if (!charset_subset && newrange->min_char_high != newrange->max_char_high)
264 for (i = newrange->min_char_high;
265 i <= newrange->max_char_high;
268 temprange.min_char_low = newrange->min_char_low;
269 temprange.max_char_low = newrange->max_char_low;
270 temprange.min_char_high = temprange.max_char_high = i;
271 err = add_range(&temprange, nranges, range, charset_subset);
272 if (err != Successful) break;
277 keymin = mincharp(newrange);
278 keymax = maxcharp(newrange);
280 if (charset_subset && keymin > keymax)
282 unsigned long temp = keymin;
287 /* add_range() maintains a sorted list; this makes possible coalescence
288 and binary searches */
290 /* Binary search for a range with which the new range can merge */
294 while (last >= first)
296 middle = (first + last) / 2;
297 ptr = (*range) + middle;
298 ptrmin = mincharp(ptr);
299 ptrmax = maxcharp(ptr);
301 if (ptrmin > 0 && keymax < ptrmin - 1) last = middle - 1;
302 else if (keymin > ptrmax + 1) first = middle + 1;
303 else if (!charset_subset)
305 /* We might have a range with which to merge... IF the
306 result doesn't cross rows */
307 if (newrange->min_char_high != ptr->min_char_high)
308 last = first - 1; /* Force adding a new range */
311 else break; /* We have at least one range with which we can merge */
316 /* Search failed; we need to add a new range to the list. */
318 /* Grow the list if necessary */
319 if (*nranges == 0 || *range == (fsRange *)0)
321 *range = (fsRange *)xalloc(range_alloc_granularity *
325 else if (!(*nranges % range_alloc_granularity))
327 *range = (fsRange *)xrealloc((char *)*range,
328 (*nranges + range_alloc_granularity) *
332 /* If alloc failed, just return a null list */
333 if (*range == (fsRange *)0)
339 /* Should new entry go *at* or *after* ptr? */
340 ptr = (*range) + middle;
341 if (middle < *nranges && keymin > ptrmin) ptr++; /* after */
343 /* Open up a space for our new range */
344 memmove((char *)(ptr + 1),
346 (char *)(*range + *nranges) - (char *)ptr);
348 /* Insert the new range */
349 ptr->min_char_low = keymin & 0xff;
350 ptr->min_char_high = keymin >> 8;
351 ptr->max_char_low = keymax & 0xff;
352 ptr->max_char_high = keymax >> 8;
354 /* Update range count */
361 /* Join our new range to that pointed to by "ptr" */
364 ptr->min_char_low = keymin & 0xff;
365 ptr->min_char_high = keymin >> 8;
369 ptr->max_char_low = keymax & 0xff;
370 ptr->max_char_high = keymax >> 8;
373 ptrmin = mincharp(ptr);
374 ptrmax = maxcharp(ptr);
376 endptr = *range + *nranges;
378 for (ptr1 = ptr; ptr1 >= *range; ptr1--)
380 if (ptrmin <= maxcharp(ptr1) + 1)
382 if (!charset_subset && ptr->min_char_high != ptr1->min_char_high)
384 if (ptrmin >= mincharp(ptr1))
385 ptrmin = mincharp(ptr1);
389 for (ptr2 = ptr; ptr2 < endptr; ptr2++)
391 if (ptr2->min_char_low == 0 &&
392 ptr2->min_char_high == 0 ||
393 ptrmax >= mincharp(ptr2) - 1)
395 if (!charset_subset && ptr->min_char_high != ptr2->min_char_high)
397 if (ptrmax <= maxcharp(ptr2))
398 ptrmax = maxcharp(ptr2);
403 /* We need to coalesce ranges between ptr1 and ptr2 exclusive */
408 memmove(ptr1, ptr2, (char *)endptr - (char *)ptr2);
409 *nranges -= (ptr2 - ptr1);
412 /* Write the new range into the range list */
413 ptr1->min_char_low = ptrmin & 0xff;
414 ptr1->min_char_high = ptrmin >> 8;
415 ptr1->max_char_low = ptrmax & 0xff;
416 ptr1->max_char_high = ptrmax >> 8;