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