3 Copyright 1991, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
30 * Author: Keith Packard, MIT X Consortium
36 #include <X11/fonts/fontmisc.h>
37 #include <X11/fonts/fontstruct.h>
38 #include <X11/fonts/FSproto.h>
39 #include <X11/fonts/fontutil.h>
41 /* Define global here... doesn't hurt the servers, and avoids
42 unresolved references in font clients. */
44 static int defaultGlyphCachingMode = DEFAULT_GLYPH_CACHING_MODE;
45 int glyphCachingMode = DEFAULT_GLYPH_CACHING_MODE;
48 GetGlyphs(FontPtr font,
51 FontEncoding fontEncoding,
52 unsigned long *glyphcount, /* RETURN */
53 CharInfoPtr *glyphs) /* RETURN */
55 (*font->get_glyphs) (font, count, chars, fontEncoding, glyphcount, glyphs);
58 #define MIN(a,b) ((a)<(b)?(a):(b))
59 #define MAX(a,b) ((a)>(b)?(a):(b))
62 QueryGlyphExtents(FontPtr pFont,
63 CharInfoPtr *charinfo,
67 register unsigned long i;
70 info->drawDirection = pFont->info.drawDirection;
72 info->fontAscent = pFont->info.fontAscent;
73 info->fontDescent = pFont->info.fontDescent;
77 pCI = &((*charinfo)->metrics); charinfo++;
78 /* ignore nonexisting characters when calculating text extents */
79 if ( !((pCI->characterWidth == 0)
80 && (pCI->rightSideBearing == 0)
81 && (pCI->leftSideBearing == 0)
83 && (pCI->descent == 0)) ) {
84 info->overallAscent = pCI->ascent;
85 info->overallDescent = pCI->descent;
86 info->overallLeft = pCI->leftSideBearing;
87 info->overallRight = pCI->rightSideBearing;
88 info->overallWidth = pCI->characterWidth;
91 if (pFont->info.constantMetrics && pFont->info.noOverlap) {
92 info->overallWidth *= count;
93 info->overallRight += (info->overallWidth -
96 for (i = 1; i < count; i++) {
97 pCI = &((*charinfo)->metrics); charinfo++;
98 /* ignore nonexisting characters when calculating extents */
99 if ( !((pCI->characterWidth == 0)
100 && (pCI->rightSideBearing == 0)
101 && (pCI->leftSideBearing == 0)
102 && (pCI->ascent == 0)
103 && (pCI->descent == 0)) ) {
104 info->overallAscent = MAX(
107 info->overallDescent = MAX(
108 info->overallDescent,
110 info->overallLeft = MIN(
112 info->overallWidth + pCI->leftSideBearing);
113 info->overallRight = MAX(
115 info->overallWidth + pCI->rightSideBearing);
117 * yes, this order is correct; overallWidth IS incremented
120 info->overallWidth += pCI->characterWidth;
125 info->overallAscent = 0;
126 info->overallDescent = 0;
127 info->overallWidth = 0;
128 info->overallLeft = 0;
129 info->overallRight = 0;
134 QueryTextExtents(FontPtr pFont,
136 unsigned char *chars,
139 xCharInfo **charinfo;
141 FontEncoding encoding;
145 xCharInfo *defaultChar = 0;
146 unsigned char defc[2];
149 charinfo = malloc(count * sizeof(xCharInfo *));
152 encoding = TwoD16Bit;
153 if (pFont->info.lastRow == 0)
154 encoding = Linear16Bit;
155 (*pFont->get_metrics) (pFont, count, chars, encoding, &n, charinfo);
157 /* Do default character substitution as get_metrics doesn't */
159 #define IsNonExistentChar(ci) (!(ci) || \
160 ((ci)->ascent == 0 && \
161 (ci)->descent == 0 && \
162 (ci)->leftSideBearing == 0 && \
163 (ci)->rightSideBearing == 0 && \
164 (ci)->characterWidth == 0))
167 defc[0] = pFont->info.defaultCh >> 8;
168 defc[1] = pFont->info.defaultCh;
169 (*pFont->get_metrics) (pFont, 1, defc, encoding, &t, &defaultChar);
170 if ((IsNonExistentChar (defaultChar)))
172 for (i = 0; i < n; i++)
174 if ((IsNonExistentChar (charinfo[i])))
178 charinfo[i] = defaultChar;
183 cm = pFont->info.constantMetrics;
184 pFont->info.constantMetrics = FALSE;
185 QueryGlyphExtents(pFont, (CharInfoPtr*) charinfo + firstReal,
186 n - firstReal, info);
187 pFont->info.constantMetrics = cm;
193 ParseGlyphCachingMode(char *str)
195 if (!strcmp(str, "none")) defaultGlyphCachingMode = CACHING_OFF;
196 else if (!strcmp(str, "all")) defaultGlyphCachingMode = CACHE_ALL_GLYPHS;
197 else if (!strcmp(str, "16")) defaultGlyphCachingMode = CACHE_16_BIT_GLYPHS;
203 InitGlyphCaching(void)
205 /* Set glyphCachingMode to the mode the server hopes to
206 support. DDX drivers that do not support the requested level
207 of glyph caching can call SetGlyphCachingMode to lower the
211 glyphCachingMode = defaultGlyphCachingMode;
214 /* ddxen can call SetGlyphCachingMode to inform us of what level of glyph
215 * caching they can support.
218 SetGlyphCachingMode(int newmode)
220 if ( (glyphCachingMode > newmode) && (newmode >= 0) )
221 glyphCachingMode = newmode;
224 #define range_alloc_granularity 16
225 #define mincharp(p) ((p)->min_char_low + ((p)->min_char_high << 8))
226 #define maxcharp(p) ((p)->max_char_low + ((p)->max_char_high << 8))
228 /* add_range(): Add range to a list of ranges, with coalescence */
230 add_range(fsRange *newrange,
235 int first, last, middle;
236 unsigned long keymin, keymax;
237 unsigned long ptrmin = 0, ptrmax = 0;
238 fsRange *ptr = NULL, *ptr1, *ptr2, *endptr;
240 /* There are two different ways to treat ranges:
242 1) Charset subsetting (support of the HP XLFD enhancements), in
243 which a range of 0x1234,0x3456 means all numbers between
244 0x1234 and 0x3456, and in which min and max might be swapped.
246 2) Row/column ranges, in which a range of 0x1234,0x3456 means the
247 ranges 0x1234-0x1256, 0x1334-0x1356, ... , 0x3434-0x3456.
248 This is for support of glyph caching.
250 The choice of treatment is selected with the "charset_subset"
253 /* If newrange covers multiple rows; break up the rows */
254 if (!charset_subset && newrange->min_char_high != newrange->max_char_high)
258 for (i = newrange->min_char_high;
259 i <= newrange->max_char_high;
262 temprange.min_char_low = newrange->min_char_low;
263 temprange.max_char_low = newrange->max_char_low;
264 temprange.min_char_high = temprange.max_char_high = i;
265 err = add_range(&temprange, nranges, range, charset_subset);
266 if (err != Successful) break;
271 keymin = mincharp(newrange);
272 keymax = maxcharp(newrange);
274 if (charset_subset && keymin > keymax)
276 unsigned long temp = keymin;
281 /* add_range() maintains a sorted list; this makes possible coalescence
282 and binary searches */
284 /* Binary search for a range with which the new range can merge */
288 while (last >= first)
290 middle = (first + last) / 2;
291 ptr = (*range) + middle;
292 ptrmin = mincharp(ptr);
293 ptrmax = maxcharp(ptr);
295 if (ptrmin > 0 && keymax < ptrmin - 1) last = middle - 1;
296 else if (keymin > ptrmax + 1) first = middle + 1;
297 else if (!charset_subset)
299 /* We might have a range with which to merge... IF the
300 result doesn't cross rows */
301 if (newrange->min_char_high != ptr->min_char_high)
302 last = first - 1; /* Force adding a new range */
305 else break; /* We have at least one range with which we can merge */
310 /* Search failed; we need to add a new range to the list. */
312 /* Grow the list if necessary */
313 if (*nranges == 0 || *range == (fsRange *)0)
315 *range = malloc(range_alloc_granularity * SIZEOF(fsRange));
318 else if (!(*nranges % range_alloc_granularity))
320 *range = realloc(*range, (*nranges + range_alloc_granularity) *
324 /* If alloc failed, just return a null list */
325 if (*range == (fsRange *)0)
331 /* Should new entry go *at* or *after* ptr? */
332 ptr = (*range) + middle;
333 if (middle < *nranges && keymin > ptrmin) ptr++; /* after */
335 /* Open up a space for our new range */
336 memmove((char *)(ptr + 1),
338 (char *)(*range + *nranges) - (char *)ptr);
340 /* Insert the new range */
341 ptr->min_char_low = keymin & 0xff;
342 ptr->min_char_high = keymin >> 8;
343 ptr->max_char_low = keymax & 0xff;
344 ptr->max_char_high = keymax >> 8;
346 /* Update range count */
353 /* Join our new range to that pointed to by "ptr" */
356 ptr->min_char_low = keymin & 0xff;
357 ptr->min_char_high = keymin >> 8;
361 ptr->max_char_low = keymax & 0xff;
362 ptr->max_char_high = keymax >> 8;
365 ptrmin = mincharp(ptr);
366 ptrmax = maxcharp(ptr);
368 endptr = *range + *nranges;
370 for (ptr1 = ptr; ptr1 >= *range; ptr1--)
372 if (ptrmin <= maxcharp(ptr1) + 1)
374 if (!charset_subset && ptr->min_char_high != ptr1->min_char_high)
376 if (ptrmin >= mincharp(ptr1))
377 ptrmin = mincharp(ptr1);
381 for (ptr2 = ptr; ptr2 < endptr; ptr2++)
383 if ((ptr2->min_char_low == 0 && ptr2->min_char_high == 0) ||
384 ptrmax >= mincharp(ptr2) - 1)
386 if (!charset_subset && ptr->min_char_high != ptr2->min_char_high)
388 if (ptrmax <= maxcharp(ptr2))
389 ptrmax = maxcharp(ptr2);
394 /* We need to coalesce ranges between ptr1 and ptr2 exclusive */
399 memmove(ptr1, ptr2, (char *)endptr - (char *)ptr2);
400 *nranges -= (ptr2 - ptr1);
403 /* Write the new range into the range list */
404 ptr1->min_char_low = ptrmin & 0xff;
405 ptr1->min_char_high = ptrmin >> 8;
406 ptr1->max_char_low = ptrmax & 0xff;
407 ptr1->max_char_high = ptrmax >> 8;