fontutil.c revision 7f7f5e4e
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 1527f7f5e4eSmrg charinfo = malloc(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; 1917f7f5e4eSmrg free(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 { 3187f7f5e4eSmrg *range = malloc(range_alloc_granularity * SIZEOF(fsRange)); 31923a0898aSmrg *nranges = 0; 32023a0898aSmrg } 32123a0898aSmrg else if (!(*nranges % range_alloc_granularity)) 32223a0898aSmrg { 3237f7f5e4eSmrg *range = realloc(*range, (*nranges + range_alloc_granularity) * 3247f7f5e4eSmrg SIZEOF(fsRange)); 32523a0898aSmrg } 32623a0898aSmrg 32723a0898aSmrg /* If alloc failed, just return a null list */ 32823a0898aSmrg if (*range == (fsRange *)0) 32923a0898aSmrg { 33023a0898aSmrg *nranges = 0; 33123a0898aSmrg return AllocError; 33223a0898aSmrg } 33323a0898aSmrg 33423a0898aSmrg /* Should new entry go *at* or *after* ptr? */ 33523a0898aSmrg ptr = (*range) + middle; 33623a0898aSmrg if (middle < *nranges && keymin > ptrmin) ptr++; /* after */ 33723a0898aSmrg 33823a0898aSmrg /* Open up a space for our new range */ 33923a0898aSmrg memmove((char *)(ptr + 1), 34023a0898aSmrg (char *)ptr, 34123a0898aSmrg (char *)(*range + *nranges) - (char *)ptr); 34223a0898aSmrg 34323a0898aSmrg /* Insert the new range */ 34423a0898aSmrg ptr->min_char_low = keymin & 0xff; 34523a0898aSmrg ptr->min_char_high = keymin >> 8; 34623a0898aSmrg ptr->max_char_low = keymax & 0xff; 34723a0898aSmrg ptr->max_char_high = keymax >> 8; 34823a0898aSmrg 34923a0898aSmrg /* Update range count */ 35023a0898aSmrg (*nranges)++; 35123a0898aSmrg 35223a0898aSmrg /* Done */ 35323a0898aSmrg return Successful; 35423a0898aSmrg } 35523a0898aSmrg 35623a0898aSmrg /* Join our new range to that pointed to by "ptr" */ 35723a0898aSmrg if (keymin < ptrmin) 35823a0898aSmrg { 35923a0898aSmrg ptr->min_char_low = keymin & 0xff; 36023a0898aSmrg ptr->min_char_high = keymin >> 8; 36123a0898aSmrg } 36223a0898aSmrg if (keymax > ptrmax) 36323a0898aSmrg { 36423a0898aSmrg ptr->max_char_low = keymax & 0xff; 36523a0898aSmrg ptr->max_char_high = keymax >> 8; 36623a0898aSmrg } 36723a0898aSmrg 36823a0898aSmrg ptrmin = mincharp(ptr); 36923a0898aSmrg ptrmax = maxcharp(ptr); 37023a0898aSmrg 37123a0898aSmrg endptr = *range + *nranges; 37223a0898aSmrg 37323a0898aSmrg for (ptr1 = ptr; ptr1 >= *range; ptr1--) 37423a0898aSmrg { 37523a0898aSmrg if (ptrmin <= maxcharp(ptr1) + 1) 37623a0898aSmrg { 37723a0898aSmrg if (!charset_subset && ptr->min_char_high != ptr1->min_char_high) 37823a0898aSmrg break; 37923a0898aSmrg if (ptrmin >= mincharp(ptr1)) 38023a0898aSmrg ptrmin = mincharp(ptr1); 38123a0898aSmrg } 38223a0898aSmrg else break; 38323a0898aSmrg } 38423a0898aSmrg for (ptr2 = ptr; ptr2 < endptr; ptr2++) 38523a0898aSmrg { 38623a0898aSmrg if ((ptr2->min_char_low == 0 && ptr2->min_char_high == 0) || 38723a0898aSmrg ptrmax >= mincharp(ptr2) - 1) 38823a0898aSmrg { 38923a0898aSmrg if (!charset_subset && ptr->min_char_high != ptr2->min_char_high) 39023a0898aSmrg break; 39123a0898aSmrg if (ptrmax <= maxcharp(ptr2)) 39223a0898aSmrg ptrmax = maxcharp(ptr2); 39323a0898aSmrg } 39423a0898aSmrg else break; 39523a0898aSmrg } 39623a0898aSmrg 39723a0898aSmrg /* We need to coalesce ranges between ptr1 and ptr2 exclusive */ 39823a0898aSmrg ptr1++; 39923a0898aSmrg ptr2--; 40023a0898aSmrg if (ptr1 != ptr2) 40123a0898aSmrg { 40223a0898aSmrg memmove(ptr1, ptr2, (char *)endptr - (char *)ptr2); 40323a0898aSmrg *nranges -= (ptr2 - ptr1); 40423a0898aSmrg } 40523a0898aSmrg 40623a0898aSmrg /* Write the new range into the range list */ 40723a0898aSmrg ptr1->min_char_low = ptrmin & 0xff; 40823a0898aSmrg ptr1->min_char_high = ptrmin >> 8; 40923a0898aSmrg ptr1->max_char_low = ptrmax & 0xff; 41023a0898aSmrg ptr1->max_char_high = ptrmax >> 8; 41123a0898aSmrg 41223a0898aSmrg return Successful; 41323a0898aSmrg} 414