fontutil.c revision 23a0898a
123a0898aSmrg/* $Xorg: fontutil.c,v 1.4 2001/02/09 02:04:04 xorgcvs Exp $ */ 223a0898aSmrg 323a0898aSmrg/* 423a0898aSmrg 523a0898aSmrgCopyright 1991, 1998 The Open Group 623a0898aSmrg 723a0898aSmrgPermission to use, copy, modify, distribute, and sell this software and its 823a0898aSmrgdocumentation for any purpose is hereby granted without fee, provided that 923a0898aSmrgthe above copyright notice appear in all copies and that both that 1023a0898aSmrgcopyright notice and this permission notice appear in supporting 1123a0898aSmrgdocumentation. 1223a0898aSmrg 1323a0898aSmrgThe above copyright notice and this permission notice shall be included 1423a0898aSmrgin all copies or substantial portions of the Software. 1523a0898aSmrg 1623a0898aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1723a0898aSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1823a0898aSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1923a0898aSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 2023a0898aSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2123a0898aSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2223a0898aSmrgOTHER DEALINGS IN THE SOFTWARE. 2323a0898aSmrg 2423a0898aSmrgExcept as contained in this notice, the name of The Open Group shall 2523a0898aSmrgnot be used in advertising or otherwise to promote the sale, use or 2623a0898aSmrgother dealings in this Software without prior written authorization 2723a0898aSmrgfrom The Open Group. 2823a0898aSmrg 2923a0898aSmrg*/ 3023a0898aSmrg/* $XFree86: xc/lib/font/util/fontutil.c,v 3.6 2001/10/28 03:32:46 tsi Exp $ */ 3123a0898aSmrg 3223a0898aSmrg/* 3323a0898aSmrg * Author: Keith Packard, MIT X Consortium 3423a0898aSmrg */ 3523a0898aSmrg 3623a0898aSmrg#ifdef HAVE_CONFIG_H 3723a0898aSmrg#include <config.h> 3823a0898aSmrg#endif 3923a0898aSmrg#include <X11/fonts/fontmisc.h> 4023a0898aSmrg#include <X11/fonts/fontstruct.h> 4123a0898aSmrg#include <X11/fonts/FSproto.h> 4223a0898aSmrg#include <X11/fonts/fontutil.h> 4323a0898aSmrg 4423a0898aSmrg/* Define global here... doesn't hurt the servers, and avoids 4523a0898aSmrg unresolved references in font clients. */ 4623a0898aSmrg 4723a0898aSmrgstatic int defaultGlyphCachingMode = DEFAULT_GLYPH_CACHING_MODE; 4823a0898aSmrgint glyphCachingMode = DEFAULT_GLYPH_CACHING_MODE; 4923a0898aSmrg 5023a0898aSmrgvoid 5123a0898aSmrgGetGlyphs(FontPtr font, 5223a0898aSmrg unsigned long count, 5323a0898aSmrg unsigned char *chars, 5423a0898aSmrg FontEncoding fontEncoding, 5523a0898aSmrg unsigned long *glyphcount, /* RETURN */ 5623a0898aSmrg CharInfoPtr *glyphs) /* RETURN */ 5723a0898aSmrg{ 5823a0898aSmrg (*font->get_glyphs) (font, count, chars, fontEncoding, glyphcount, glyphs); 5923a0898aSmrg} 6023a0898aSmrg 6123a0898aSmrg#define MIN(a,b) ((a)<(b)?(a):(b)) 6223a0898aSmrg#define MAX(a,b) ((a)>(b)?(a):(b)) 6323a0898aSmrg 6423a0898aSmrgvoid 6523a0898aSmrgQueryGlyphExtents(FontPtr pFont, 6623a0898aSmrg CharInfoPtr *charinfo, 6723a0898aSmrg unsigned long count, 6823a0898aSmrg ExtentInfoRec *info) 6923a0898aSmrg{ 7023a0898aSmrg register unsigned long i; 7123a0898aSmrg xCharInfo *pCI; 7223a0898aSmrg 7323a0898aSmrg info->drawDirection = pFont->info.drawDirection; 7423a0898aSmrg 7523a0898aSmrg info->fontAscent = pFont->info.fontAscent; 7623a0898aSmrg info->fontDescent = pFont->info.fontDescent; 7723a0898aSmrg 7823a0898aSmrg if (count != 0) { 7923a0898aSmrg 8023a0898aSmrg pCI = &((*charinfo)->metrics); charinfo++; 8123a0898aSmrg /* ignore nonexisting characters when calculating text extents */ 8223a0898aSmrg if ( !((pCI->characterWidth == 0) 8323a0898aSmrg && (pCI->rightSideBearing == 0) 8423a0898aSmrg && (pCI->leftSideBearing == 0) 8523a0898aSmrg && (pCI->ascent == 0) 8623a0898aSmrg && (pCI->descent == 0)) ) { 8723a0898aSmrg info->overallAscent = pCI->ascent; 8823a0898aSmrg info->overallDescent = pCI->descent; 8923a0898aSmrg info->overallLeft = pCI->leftSideBearing; 9023a0898aSmrg info->overallRight = pCI->rightSideBearing; 9123a0898aSmrg info->overallWidth = pCI->characterWidth; 9223a0898aSmrg } 9323a0898aSmrg 9423a0898aSmrg if (pFont->info.constantMetrics && pFont->info.noOverlap) { 9523a0898aSmrg info->overallWidth *= count; 9623a0898aSmrg info->overallRight += (info->overallWidth - 9723a0898aSmrg pCI->characterWidth); 9823a0898aSmrg } else { 9923a0898aSmrg for (i = 1; i < count; i++) { 10023a0898aSmrg pCI = &((*charinfo)->metrics); charinfo++; 10123a0898aSmrg /* ignore nonexisting characters when calculating extents */ 10223a0898aSmrg if ( !((pCI->characterWidth == 0) 10323a0898aSmrg && (pCI->rightSideBearing == 0) 10423a0898aSmrg && (pCI->leftSideBearing == 0) 10523a0898aSmrg && (pCI->ascent == 0) 10623a0898aSmrg && (pCI->descent == 0)) ) { 10723a0898aSmrg info->overallAscent = MAX( 10823a0898aSmrg info->overallAscent, 10923a0898aSmrg pCI->ascent); 11023a0898aSmrg info->overallDescent = MAX( 11123a0898aSmrg info->overallDescent, 11223a0898aSmrg pCI->descent); 11323a0898aSmrg info->overallLeft = MIN( 11423a0898aSmrg info->overallLeft, 11523a0898aSmrg info->overallWidth + pCI->leftSideBearing); 11623a0898aSmrg info->overallRight = MAX( 11723a0898aSmrg info->overallRight, 11823a0898aSmrg info->overallWidth + pCI->rightSideBearing); 11923a0898aSmrg /* 12023a0898aSmrg * yes, this order is correct; overallWidth IS incremented 12123a0898aSmrg * last 12223a0898aSmrg */ 12323a0898aSmrg info->overallWidth += pCI->characterWidth; 12423a0898aSmrg } 12523a0898aSmrg } 12623a0898aSmrg } 12723a0898aSmrg } else { 12823a0898aSmrg info->overallAscent = 0; 12923a0898aSmrg info->overallDescent = 0; 13023a0898aSmrg info->overallWidth = 0; 13123a0898aSmrg info->overallLeft = 0; 13223a0898aSmrg info->overallRight = 0; 13323a0898aSmrg } 13423a0898aSmrg} 13523a0898aSmrg 13623a0898aSmrgBool 13723a0898aSmrgQueryTextExtents(FontPtr pFont, 13823a0898aSmrg unsigned long count, 13923a0898aSmrg unsigned char *chars, 14023a0898aSmrg ExtentInfoRec *info) 14123a0898aSmrg{ 14223a0898aSmrg xCharInfo **charinfo; 14323a0898aSmrg unsigned long n; 14423a0898aSmrg FontEncoding encoding; 14523a0898aSmrg int cm; 14623a0898aSmrg int i; 14723a0898aSmrg unsigned long t; 14823a0898aSmrg xCharInfo *defaultChar = 0; 14923a0898aSmrg unsigned char defc[2]; 15023a0898aSmrg int firstReal; 15123a0898aSmrg 15223a0898aSmrg charinfo = (xCharInfo **) xalloc(count * sizeof(xCharInfo *)); 15323a0898aSmrg if (!charinfo) 15423a0898aSmrg return FALSE; 15523a0898aSmrg encoding = TwoD16Bit; 15623a0898aSmrg if (pFont->info.lastRow == 0) 15723a0898aSmrg encoding = Linear16Bit; 15823a0898aSmrg (*pFont->get_metrics) (pFont, count, chars, encoding, &n, charinfo); 15923a0898aSmrg 16023a0898aSmrg /* Do default character substitution as get_metrics doesn't */ 16123a0898aSmrg 16223a0898aSmrg#define IsNonExistentChar(ci) (!(ci) || \ 16323a0898aSmrg ((ci)->ascent == 0 && \ 16423a0898aSmrg (ci)->descent == 0 && \ 16523a0898aSmrg (ci)->leftSideBearing == 0 && \ 16623a0898aSmrg (ci)->rightSideBearing == 0 && \ 16723a0898aSmrg (ci)->characterWidth == 0)) 16823a0898aSmrg 16923a0898aSmrg firstReal = n; 17023a0898aSmrg defc[0] = pFont->info.defaultCh >> 8; 17123a0898aSmrg defc[1] = pFont->info.defaultCh; 17223a0898aSmrg (*pFont->get_metrics) (pFont, 1, defc, encoding, &t, &defaultChar); 17323a0898aSmrg if ((IsNonExistentChar (defaultChar))) 17423a0898aSmrg defaultChar = 0; 17523a0898aSmrg for (i = 0; i < n; i++) 17623a0898aSmrg { 17723a0898aSmrg if ((IsNonExistentChar (charinfo[i]))) 17823a0898aSmrg { 17923a0898aSmrg if (!defaultChar) 18023a0898aSmrg continue; 18123a0898aSmrg charinfo[i] = defaultChar; 18223a0898aSmrg } 18323a0898aSmrg if (firstReal == n) 18423a0898aSmrg firstReal = i; 18523a0898aSmrg } 18623a0898aSmrg cm = pFont->info.constantMetrics; 18723a0898aSmrg pFont->info.constantMetrics = FALSE; 18823a0898aSmrg QueryGlyphExtents(pFont, (CharInfoPtr*) charinfo + firstReal, 18923a0898aSmrg n - firstReal, info); 19023a0898aSmrg pFont->info.constantMetrics = cm; 19123a0898aSmrg xfree(charinfo); 19223a0898aSmrg return TRUE; 19323a0898aSmrg} 19423a0898aSmrg 19523a0898aSmrgBool 19623a0898aSmrgParseGlyphCachingMode(char *str) 19723a0898aSmrg{ 19823a0898aSmrg if (!strcmp(str, "none")) defaultGlyphCachingMode = CACHING_OFF; 19923a0898aSmrg else if (!strcmp(str, "all")) defaultGlyphCachingMode = CACHE_ALL_GLYPHS; 20023a0898aSmrg else if (!strcmp(str, "16")) defaultGlyphCachingMode = CACHE_16_BIT_GLYPHS; 20123a0898aSmrg else return FALSE; 20223a0898aSmrg return TRUE; 20323a0898aSmrg} 20423a0898aSmrg 20523a0898aSmrgvoid 20623a0898aSmrgInitGlyphCaching(void) 20723a0898aSmrg{ 20823a0898aSmrg /* Set glyphCachingMode to the mode the server hopes to 20923a0898aSmrg support. DDX drivers that do not support the requested level 21023a0898aSmrg of glyph caching can call SetGlyphCachingMode to lower the 21123a0898aSmrg level of support. 21223a0898aSmrg */ 21323a0898aSmrg 21423a0898aSmrg glyphCachingMode = defaultGlyphCachingMode; 21523a0898aSmrg} 21623a0898aSmrg 21723a0898aSmrg/* ddxen can call SetGlyphCachingMode to inform us of what level of glyph 21823a0898aSmrg * caching they can support. 21923a0898aSmrg */ 22023a0898aSmrgvoid 22123a0898aSmrgSetGlyphCachingMode(int newmode) 22223a0898aSmrg{ 22323a0898aSmrg if ( (glyphCachingMode > newmode) && (newmode >= 0) ) 22423a0898aSmrg glyphCachingMode = newmode; 22523a0898aSmrg} 22623a0898aSmrg 22723a0898aSmrg#define range_alloc_granularity 16 22823a0898aSmrg#define mincharp(p) ((p)->min_char_low + ((p)->min_char_high << 8)) 22923a0898aSmrg#define maxcharp(p) ((p)->max_char_low + ((p)->max_char_high << 8)) 23023a0898aSmrg 23123a0898aSmrg/* add_range(): Add range to a list of ranges, with coalescence */ 23223a0898aSmrgint 23323a0898aSmrgadd_range(fsRange *newrange, 23423a0898aSmrg int *nranges, 23523a0898aSmrg fsRange **range, 23623a0898aSmrg Bool charset_subset) 23723a0898aSmrg{ 23823a0898aSmrg int first, last, middle; 23923a0898aSmrg unsigned long keymin, keymax; 24023a0898aSmrg unsigned long ptrmin = 0, ptrmax = 0; 24123a0898aSmrg fsRange *ptr = NULL, *ptr1, *ptr2, *endptr; 24223a0898aSmrg 24323a0898aSmrg /* There are two different ways to treat ranges: 24423a0898aSmrg 24523a0898aSmrg 1) Charset subsetting (support of the HP XLFD enhancements), in 24623a0898aSmrg which a range of 0x1234,0x3456 means all numbers between 24723a0898aSmrg 0x1234 and 0x3456, and in which min and max might be swapped. 24823a0898aSmrg 24923a0898aSmrg 2) Row/column ranges, in which a range of 0x1234,0x3456 means the 25023a0898aSmrg ranges 0x1234-0x1256, 0x1334-0x1356, ... , 0x3434-0x3456. 25123a0898aSmrg This is for support of glyph caching. 25223a0898aSmrg 25323a0898aSmrg The choice of treatment is selected with the "charset_subset" 25423a0898aSmrg flag */ 25523a0898aSmrg 25623a0898aSmrg /* If newrange covers multiple rows; break up the rows */ 25723a0898aSmrg if (!charset_subset && newrange->min_char_high != newrange->max_char_high) 25823a0898aSmrg { 25923a0898aSmrg int i, err = 0; 26023a0898aSmrg fsRange temprange; 26123a0898aSmrg for (i = newrange->min_char_high; 26223a0898aSmrg i <= newrange->max_char_high; 26323a0898aSmrg i++) 26423a0898aSmrg { 26523a0898aSmrg temprange.min_char_low = newrange->min_char_low; 26623a0898aSmrg temprange.max_char_low = newrange->max_char_low; 26723a0898aSmrg temprange.min_char_high = temprange.max_char_high = i; 26823a0898aSmrg err = add_range(&temprange, nranges, range, charset_subset); 26923a0898aSmrg if (err != Successful) break; 27023a0898aSmrg } 27123a0898aSmrg return err; 27223a0898aSmrg } 27323a0898aSmrg 27423a0898aSmrg keymin = mincharp(newrange); 27523a0898aSmrg keymax = maxcharp(newrange); 27623a0898aSmrg 27723a0898aSmrg if (charset_subset && keymin > keymax) 27823a0898aSmrg { 27923a0898aSmrg unsigned long temp = keymin; 28023a0898aSmrg keymin = keymax; 28123a0898aSmrg keymax = temp; 28223a0898aSmrg } 28323a0898aSmrg 28423a0898aSmrg /* add_range() maintains a sorted list; this makes possible coalescence 28523a0898aSmrg and binary searches */ 28623a0898aSmrg 28723a0898aSmrg /* Binary search for a range with which the new range can merge */ 28823a0898aSmrg 28923a0898aSmrg first = middle = 0; 29023a0898aSmrg last = *nranges - 1; 29123a0898aSmrg while (last >= first) 29223a0898aSmrg { 29323a0898aSmrg middle = (first + last) / 2; 29423a0898aSmrg ptr = (*range) + middle; 29523a0898aSmrg ptrmin = mincharp(ptr); 29623a0898aSmrg ptrmax = maxcharp(ptr); 29723a0898aSmrg 29823a0898aSmrg if (ptrmin > 0 && keymax < ptrmin - 1) last = middle - 1; 29923a0898aSmrg else if (keymin > ptrmax + 1) first = middle + 1; 30023a0898aSmrg else if (!charset_subset) 30123a0898aSmrg { 30223a0898aSmrg /* We might have a range with which to merge... IF the 30323a0898aSmrg result doesn't cross rows */ 30423a0898aSmrg if (newrange->min_char_high != ptr->min_char_high) 30523a0898aSmrg last = first - 1; /* Force adding a new range */ 30623a0898aSmrg break; 30723a0898aSmrg } 30823a0898aSmrg else break; /* We have at least one range with which we can merge */ 30923a0898aSmrg } 31023a0898aSmrg 31123a0898aSmrg if (last < first) 31223a0898aSmrg { 31323a0898aSmrg /* Search failed; we need to add a new range to the list. */ 31423a0898aSmrg 31523a0898aSmrg /* Grow the list if necessary */ 31623a0898aSmrg if (*nranges == 0 || *range == (fsRange *)0) 31723a0898aSmrg { 31823a0898aSmrg *range = (fsRange *)xalloc(range_alloc_granularity * 31923a0898aSmrg SIZEOF(fsRange)); 32023a0898aSmrg *nranges = 0; 32123a0898aSmrg } 32223a0898aSmrg else if (!(*nranges % range_alloc_granularity)) 32323a0898aSmrg { 32423a0898aSmrg *range = (fsRange *)xrealloc((char *)*range, 32523a0898aSmrg (*nranges + range_alloc_granularity) * 32623a0898aSmrg SIZEOF(fsRange)); 32723a0898aSmrg } 32823a0898aSmrg 32923a0898aSmrg /* If alloc failed, just return a null list */ 33023a0898aSmrg if (*range == (fsRange *)0) 33123a0898aSmrg { 33223a0898aSmrg *nranges = 0; 33323a0898aSmrg return AllocError; 33423a0898aSmrg } 33523a0898aSmrg 33623a0898aSmrg /* Should new entry go *at* or *after* ptr? */ 33723a0898aSmrg ptr = (*range) + middle; 33823a0898aSmrg if (middle < *nranges && keymin > ptrmin) ptr++; /* after */ 33923a0898aSmrg 34023a0898aSmrg /* Open up a space for our new range */ 34123a0898aSmrg memmove((char *)(ptr + 1), 34223a0898aSmrg (char *)ptr, 34323a0898aSmrg (char *)(*range + *nranges) - (char *)ptr); 34423a0898aSmrg 34523a0898aSmrg /* Insert the new range */ 34623a0898aSmrg ptr->min_char_low = keymin & 0xff; 34723a0898aSmrg ptr->min_char_high = keymin >> 8; 34823a0898aSmrg ptr->max_char_low = keymax & 0xff; 34923a0898aSmrg ptr->max_char_high = keymax >> 8; 35023a0898aSmrg 35123a0898aSmrg /* Update range count */ 35223a0898aSmrg (*nranges)++; 35323a0898aSmrg 35423a0898aSmrg /* Done */ 35523a0898aSmrg return Successful; 35623a0898aSmrg } 35723a0898aSmrg 35823a0898aSmrg /* Join our new range to that pointed to by "ptr" */ 35923a0898aSmrg if (keymin < ptrmin) 36023a0898aSmrg { 36123a0898aSmrg ptr->min_char_low = keymin & 0xff; 36223a0898aSmrg ptr->min_char_high = keymin >> 8; 36323a0898aSmrg } 36423a0898aSmrg if (keymax > ptrmax) 36523a0898aSmrg { 36623a0898aSmrg ptr->max_char_low = keymax & 0xff; 36723a0898aSmrg ptr->max_char_high = keymax >> 8; 36823a0898aSmrg } 36923a0898aSmrg 37023a0898aSmrg ptrmin = mincharp(ptr); 37123a0898aSmrg ptrmax = maxcharp(ptr); 37223a0898aSmrg 37323a0898aSmrg endptr = *range + *nranges; 37423a0898aSmrg 37523a0898aSmrg for (ptr1 = ptr; ptr1 >= *range; ptr1--) 37623a0898aSmrg { 37723a0898aSmrg if (ptrmin <= maxcharp(ptr1) + 1) 37823a0898aSmrg { 37923a0898aSmrg if (!charset_subset && ptr->min_char_high != ptr1->min_char_high) 38023a0898aSmrg break; 38123a0898aSmrg if (ptrmin >= mincharp(ptr1)) 38223a0898aSmrg ptrmin = mincharp(ptr1); 38323a0898aSmrg } 38423a0898aSmrg else break; 38523a0898aSmrg } 38623a0898aSmrg for (ptr2 = ptr; ptr2 < endptr; ptr2++) 38723a0898aSmrg { 38823a0898aSmrg if ((ptr2->min_char_low == 0 && ptr2->min_char_high == 0) || 38923a0898aSmrg ptrmax >= mincharp(ptr2) - 1) 39023a0898aSmrg { 39123a0898aSmrg if (!charset_subset && ptr->min_char_high != ptr2->min_char_high) 39223a0898aSmrg break; 39323a0898aSmrg if (ptrmax <= maxcharp(ptr2)) 39423a0898aSmrg ptrmax = maxcharp(ptr2); 39523a0898aSmrg } 39623a0898aSmrg else break; 39723a0898aSmrg } 39823a0898aSmrg 39923a0898aSmrg /* We need to coalesce ranges between ptr1 and ptr2 exclusive */ 40023a0898aSmrg ptr1++; 40123a0898aSmrg ptr2--; 40223a0898aSmrg if (ptr1 != ptr2) 40323a0898aSmrg { 40423a0898aSmrg memmove(ptr1, ptr2, (char *)endptr - (char *)ptr2); 40523a0898aSmrg *nranges -= (ptr2 - ptr1); 40623a0898aSmrg } 40723a0898aSmrg 40823a0898aSmrg /* Write the new range into the range list */ 40923a0898aSmrg ptr1->min_char_low = ptrmin & 0xff; 41023a0898aSmrg ptr1->min_char_high = ptrmin >> 8; 41123a0898aSmrg ptr1->max_char_low = ptrmax & 0xff; 41223a0898aSmrg ptr1->max_char_high = ptrmax >> 8; 41323a0898aSmrg 41423a0898aSmrg return Successful; 41523a0898aSmrg} 41623a0898aSmrg 41723a0898aSmrg/* It is difficult to find a good place for this. */ 41823a0898aSmrg#ifdef NEED_STRCASECMP 41923a0898aSmrgint 42023a0898aSmrgf_strcasecmp(const char *s1, const char *s2) 42123a0898aSmrg{ 42223a0898aSmrg char c1, c2; 42323a0898aSmrg 42423a0898aSmrg if (*s1 == 0) 42523a0898aSmrg if (*s2 == 0) 42623a0898aSmrg return 0; 42723a0898aSmrg else 42823a0898aSmrg return 1; 42923a0898aSmrg 43023a0898aSmrg c1 = (isupper (*s1) ? tolower (*s1) : *s1); 43123a0898aSmrg c2 = (isupper (*s2) ? tolower (*s2) : *s2); 43223a0898aSmrg while (c1 == c2) { 43323a0898aSmrg if (c1 == '\0') 43423a0898aSmrg return 0; 43523a0898aSmrg s1++; 43623a0898aSmrg s2++; 43723a0898aSmrg c1 = (isupper (*s1) ? tolower (*s1) : *s1); 43823a0898aSmrg c2 = (isupper (*s2) ? tolower (*s2) : *s2); 43923a0898aSmrg } 44023a0898aSmrg return c1 - c2; 44123a0898aSmrg} 44223a0898aSmrg#endif 44323a0898aSmrg 444