]> git.sesse.net Git - rdpsrv/blob - Xserver/lib/font/util/fontutil.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / lib / font / util / fontutil.c
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 $ */
3
4 /*
5
6 Copyright (c) 1991  X Consortium
7
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:
15
16 The above copyright notice and this permission notice shall be included
17 in all copies or substantial portions of the Software.
18
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.
26
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.
31
32 */
33
34 /*
35  * Author:  Keith Packard, MIT X Consortium
36  */
37
38 #include    "fontmisc.h"
39 #include    "fontstruct.h"
40 #include    "FSproto.h"
41
42 /* Define global here...  doesn't hurt the servers, and avoids
43    unresolved references in font clients.  */
44
45 static int defaultGlyphCachingMode = DEFAULT_GLYPH_CACHING_MODE;
46 int glyphCachingMode = DEFAULT_GLYPH_CACHING_MODE;
47
48 void
49 GetGlyphs(font, count, chars, fontEncoding, glyphcount, glyphs)
50     FontPtr     font;
51     unsigned long count;
52     unsigned char *chars;
53     FontEncoding fontEncoding;
54     unsigned long *glyphcount;  /* RETURN */
55     CharInfoPtr *glyphs;        /* RETURN */
56 {
57     (*font->get_glyphs) (font, count, chars, fontEncoding, glyphcount, glyphs);
58 }
59
60 #define MIN(a,b)    ((a)<(b)?(a):(b))
61 #define MAX(a,b)    ((a)>(b)?(a):(b))
62
63 void
64 QueryGlyphExtents(pFont, charinfo, count, info)
65     FontPtr     pFont;
66     CharInfoPtr *charinfo;
67     unsigned long count;
68     ExtentInfoRec *info;
69 {
70     register unsigned long i;
71     xCharInfo  *pCI;
72
73     info->drawDirection = pFont->info.drawDirection;
74
75     info->fontAscent = pFont->info.fontAscent;
76     info->fontDescent = pFont->info.fontDescent;
77
78     if (count != 0) {
79
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)
85                && (pCI->ascent == 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;
92         }
93
94         if (pFont->info.constantMetrics && pFont->info.noOverlap) {
95             info->overallWidth *= count;
96             info->overallRight += (info->overallWidth -
97                                    pCI->characterWidth);
98         } else {
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(
108                                               info->overallAscent,
109                                               pCI->ascent);
110                     info->overallDescent = MAX(
111                                                info->overallDescent,
112                                                pCI->descent);
113                     info->overallLeft = MIN(
114                                             info->overallLeft,
115                                             info->overallWidth + pCI->leftSideBearing);
116                     info->overallRight = MAX(
117                                              info->overallRight,
118                                              info->overallWidth + pCI->rightSideBearing);
119                     /*
120                      * yes, this order is correct; overallWidth IS incremented
121                      * last
122                      */
123                     info->overallWidth += pCI->characterWidth;
124                 }
125             }
126         }
127     } else {
128         info->overallAscent = 0;
129         info->overallDescent = 0;
130         info->overallWidth = 0;
131         info->overallLeft = 0;
132         info->overallRight = 0;
133     }
134 }
135
136 Bool
137 QueryTextExtents(pFont, count, chars, info)
138     FontPtr     pFont;
139     unsigned long count;
140     unsigned char *chars;
141     ExtentInfoRec *info;
142 {
143     xCharInfo     **charinfo;
144     unsigned long   n;
145     FontEncoding    encoding;
146     int             cm;
147     int             i;
148     unsigned long   t;
149     xCharInfo      *defaultChar = 0;
150     unsigned char   defc[2];
151     int             firstReal;
152
153     charinfo = (xCharInfo **) xalloc(count * sizeof(xCharInfo *));
154     if (!charinfo)
155         return FALSE;
156     encoding = TwoD16Bit;
157     if (pFont->info.lastRow == 0)
158         encoding = Linear16Bit;
159     (*pFont->get_metrics) (pFont, count, chars, encoding, &n, charinfo);
160
161     /* Do default character substitution as get_metrics doesn't */
162
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)
169
170     firstReal = n;
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))
175         defaultChar = 0;
176     for (i = 0; i < n; i++)
177     {
178         if (IsNonExistentChar (charinfo[i]))
179         {
180             if (!defaultChar)
181                 continue;
182             charinfo[i] = defaultChar;
183         }
184         if (firstReal == n)
185             firstReal = i;
186     }
187     cm = pFont->info.constantMetrics;
188     pFont->info.constantMetrics = FALSE;
189     QueryGlyphExtents(pFont, charinfo + firstReal, n - firstReal, info);
190     pFont->info.constantMetrics = cm;
191     xfree(charinfo);
192     return TRUE;
193 }
194
195 Bool
196 ParseGlyphCachingMode(str)
197     char       *str;
198 {
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;
202     else return FALSE;
203     return TRUE;
204 }
205
206 void
207 InitGlyphCaching()
208 {
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
212        level of support.
213      */
214
215     glyphCachingMode = defaultGlyphCachingMode;
216 }
217
218 /* ddxen can call SetGlyphCachingMode to inform us of what level of glyph
219  * caching they can support.
220  */
221 void
222 SetGlyphCachingMode(newmode)
223     int newmode;
224 {
225     if ( (glyphCachingMode > newmode) && (newmode >= 0) )
226         glyphCachingMode = newmode;
227 }
228
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))
232
233 /* add_range(): Add range to a list of ranges, with coalescence */
234 int
235 add_range(newrange, nranges, range, charset_subset)
236 fsRange *newrange;
237 int *nranges;
238 fsRange **range;
239 Bool charset_subset;
240 {
241     int first, last, middle;
242     unsigned long keymin, keymax;
243     unsigned long ptrmin, ptrmax;
244     fsRange *ptr, *ptr1, *ptr2, *endptr;
245
246     /* There are two different ways to treat ranges:
247
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.
251
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.
255
256        The choice of treatment is selected with the "charset_subset"
257        flag */
258
259     /* If newrange covers multiple rows; break up the rows */
260     if (!charset_subset && newrange->min_char_high != newrange->max_char_high)
261     {
262         int i, err;
263         fsRange temprange;
264         for (i = newrange->min_char_high;
265              i <= newrange->max_char_high;
266              i++)
267         {
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;
273         }
274         return err;
275     }
276
277     keymin = mincharp(newrange);
278     keymax = maxcharp(newrange);
279
280     if (charset_subset && keymin > keymax)
281     {
282         unsigned long temp = keymin;
283         keymin = keymax;
284         keymax = temp;
285     }
286
287     /* add_range() maintains a sorted list; this makes possible coalescence
288        and binary searches */
289
290     /* Binary search for a range with which the new range can merge */
291
292     first = middle = 0;
293     last = *nranges - 1;
294     while (last >= first)
295     {
296         middle = (first + last) / 2;
297         ptr = (*range) + middle;
298         ptrmin = mincharp(ptr);
299         ptrmax = maxcharp(ptr);
300
301         if (ptrmin > 0 && keymax < ptrmin - 1) last = middle - 1;
302         else if (keymin > ptrmax + 1) first = middle + 1;
303         else if (!charset_subset)
304         {
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 */
309             break;
310         }
311         else break;     /* We have at least one range with which we can merge */
312     }
313
314     if (last < first)
315     {
316         /* Search failed; we need to add a new range to the list. */
317
318         /* Grow the list if necessary */
319         if (*nranges == 0 || *range == (fsRange *)0)
320         {
321             *range = (fsRange *)xalloc(range_alloc_granularity *
322                                        SIZEOF(fsRange));
323             *nranges = 0;
324         }
325         else if (!(*nranges % range_alloc_granularity))
326         {
327             *range = (fsRange *)xrealloc((char *)*range,
328                                           (*nranges + range_alloc_granularity) *
329                                           SIZEOF(fsRange));
330         }
331
332         /* If alloc failed, just return a null list */
333         if (*range == (fsRange *)0)
334         {
335             *nranges = 0;
336             return AllocError;
337         }
338
339         /* Should new entry go *at* or *after* ptr? */
340         ptr = (*range) + middle;
341         if (middle < *nranges && keymin > ptrmin) ptr++;        /* after */
342
343         /* Open up a space for our new range */
344         memmove((char *)(ptr + 1),
345                 (char *)ptr,
346                 (char *)(*range + *nranges) - (char *)ptr);
347
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;
353
354         /* Update range count */
355         (*nranges)++;
356
357         /* Done */
358         return Successful;
359     }
360
361     /* Join our new range to that pointed to by "ptr" */
362     if (keymin < ptrmin)
363     {
364         ptr->min_char_low = keymin & 0xff;
365         ptr->min_char_high = keymin >> 8;
366     }
367     if (keymax > ptrmax)
368     {
369         ptr->max_char_low = keymax & 0xff;
370         ptr->max_char_high = keymax >> 8;
371     }
372
373     ptrmin = mincharp(ptr);
374     ptrmax = maxcharp(ptr);
375
376     endptr = *range + *nranges;
377
378     for (ptr1 = ptr; ptr1 >= *range; ptr1--)
379     {
380         if (ptrmin <= maxcharp(ptr1) + 1)
381         {
382             if (!charset_subset && ptr->min_char_high != ptr1->min_char_high)
383                 break;
384             if (ptrmin >= mincharp(ptr1))
385                 ptrmin = mincharp(ptr1);
386         }
387         else break;
388     }
389     for (ptr2 = ptr; ptr2 < endptr; ptr2++)
390     {
391         if (ptr2->min_char_low == 0 &&
392             ptr2->min_char_high == 0 ||
393             ptrmax >= mincharp(ptr2) - 1)
394         {
395             if (!charset_subset && ptr->min_char_high != ptr2->min_char_high)
396                 break;
397             if (ptrmax <= maxcharp(ptr2))
398                 ptrmax = maxcharp(ptr2);
399         }
400         else break;
401     }
402
403     /* We need to coalesce ranges between ptr1 and ptr2 exclusive */
404     ptr1++;
405     ptr2--;
406     if (ptr1 != ptr2)
407     {
408         memmove(ptr1, ptr2, (char *)endptr - (char *)ptr2);
409         *nranges -= (ptr2 - ptr1);
410     }
411
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;
417
418     return Successful;
419 }