Home | History | Annotate | Line # | Download | only in util
      1 /*
      2 
      3 Copyright 1991, 1998  The Open Group
      4 
      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
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     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.
     21 
     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
     25 from The Open Group.
     26 
     27 */
     28 
     29 /*
     30  * Author:  Keith Packard, MIT X Consortium
     31  */
     32 
     33 #ifdef HAVE_CONFIG_H
     34 #include <config.h>
     35 #endif
     36 #include "libxfontint.h"
     37 #include "src/util/replace.h"
     38 #include    <X11/fonts/fontmisc.h>
     39 #include    <X11/fonts/fontstruct.h>
     40 #include    <X11/fonts/FSproto.h>
     41 #include    <X11/fonts/fontutil.h>
     42 
     43 /* Define global here...  doesn't hurt the servers, and avoids
     44    unresolved references in font clients.  */
     45 
     46 static int defaultGlyphCachingMode = DEFAULT_GLYPH_CACHING_MODE;
     47 int glyphCachingMode = DEFAULT_GLYPH_CACHING_MODE;
     48 
     49 #define MIN(a,b)    ((a)<(b)?(a):(b))
     50 #define MAX(a,b)    ((a)>(b)?(a):(b))
     51 
     52 void
     53 xfont2_query_glyph_extents(FontPtr pFont,
     54 			   CharInfoPtr *charinfo,
     55 			   unsigned long count,
     56 			   ExtentInfoRec *info)
     57 {
     58     register unsigned long i;
     59     xCharInfo  *pCI;
     60 
     61     info->drawDirection = pFont->info.drawDirection;
     62 
     63     info->fontAscent = pFont->info.fontAscent;
     64     info->fontDescent = pFont->info.fontDescent;
     65 
     66     if (count != 0) {
     67 
     68 	pCI = &((*charinfo)->metrics); charinfo++;
     69 	/* ignore nonexisting characters when calculating text extents */
     70 	if ( !((pCI->characterWidth == 0)
     71 	       && (pCI->rightSideBearing == 0)
     72 	       && (pCI->leftSideBearing == 0)
     73 	       && (pCI->ascent == 0)
     74 	       && (pCI->descent == 0)) ) {
     75 	    info->overallAscent = pCI->ascent;
     76 	    info->overallDescent = pCI->descent;
     77 	    info->overallLeft = pCI->leftSideBearing;
     78 	    info->overallRight = pCI->rightSideBearing;
     79 	    info->overallWidth = pCI->characterWidth;
     80 	}
     81 
     82 	if (pFont->info.constantMetrics && pFont->info.noOverlap) {
     83 	    info->overallWidth *= count;
     84 	    info->overallRight += (info->overallWidth -
     85 				   pCI->characterWidth);
     86 	} else {
     87 	    for (i = 1; i < count; i++) {
     88 		pCI = &((*charinfo)->metrics); charinfo++;
     89 		/* ignore nonexisting characters when calculating extents */
     90 		if ( !((pCI->characterWidth == 0)
     91 		       && (pCI->rightSideBearing == 0)
     92 		       && (pCI->leftSideBearing == 0)
     93 		       && (pCI->ascent == 0)
     94 		       && (pCI->descent == 0)) ) {
     95 		    info->overallAscent = MAX(
     96 					      info->overallAscent,
     97 					      pCI->ascent);
     98 		    info->overallDescent = MAX(
     99 					       info->overallDescent,
    100 					       pCI->descent);
    101 		    info->overallLeft = MIN(
    102 					    info->overallLeft,
    103 					    info->overallWidth + pCI->leftSideBearing);
    104 		    info->overallRight = MAX(
    105 					     info->overallRight,
    106 					     info->overallWidth + pCI->rightSideBearing);
    107 		    /*
    108 		     * yes, this order is correct; overallWidth IS incremented
    109 		     * last
    110 		     */
    111 		    info->overallWidth += pCI->characterWidth;
    112 		}
    113 	    }
    114 	}
    115     } else {
    116 	info->overallAscent = 0;
    117 	info->overallDescent = 0;
    118 	info->overallWidth = 0;
    119 	info->overallLeft = 0;
    120 	info->overallRight = 0;
    121     }
    122 }
    123 
    124 Bool
    125 xfont2_query_text_extents(FontPtr pFont,
    126 			  unsigned long count,
    127 			  unsigned char *chars,
    128 			  ExtentInfoRec *info)
    129 {
    130     xCharInfo     **charinfo;
    131     unsigned long   n;
    132     FontEncoding    encoding;
    133     int             cm;
    134     int             i;
    135     unsigned long   t;
    136     xCharInfo      *defaultChar = 0;
    137     unsigned char   defc[2];
    138     int             firstReal;
    139 
    140     charinfo = mallocarray(count, sizeof(xCharInfo *));
    141     if (!charinfo)
    142 	return FALSE;
    143     encoding = TwoD16Bit;
    144     if (pFont->info.lastRow == 0)
    145 	encoding = Linear16Bit;
    146     (*pFont->get_metrics) (pFont, count, chars, encoding, &n, charinfo);
    147 
    148     /* Do default character substitution as get_metrics doesn't */
    149 
    150 #define IsNonExistentChar(ci) (!(ci) || \
    151 			       ((ci)->ascent == 0 && \
    152 			       (ci)->descent == 0 && \
    153 			       (ci)->leftSideBearing == 0 && \
    154 			       (ci)->rightSideBearing == 0 && \
    155 			       (ci)->characterWidth == 0))
    156 
    157     firstReal = n;
    158     defc[0] = pFont->info.defaultCh >> 8;
    159     defc[1] = pFont->info.defaultCh;
    160     (*pFont->get_metrics) (pFont, 1, defc, encoding, &t, &defaultChar);
    161     if ((IsNonExistentChar (defaultChar)))
    162 	defaultChar = 0;
    163     for (i = 0; i < n; i++)
    164     {
    165 	if ((IsNonExistentChar (charinfo[i])))
    166 	{
    167 	    if (!defaultChar)
    168 		continue;
    169 	    charinfo[i] = defaultChar;
    170 	}
    171 	if (firstReal == n)
    172 	    firstReal = i;
    173     }
    174     cm = pFont->info.constantMetrics;
    175     pFont->info.constantMetrics = FALSE;
    176     xfont2_query_glyph_extents(pFont, (CharInfoPtr*) charinfo + firstReal,
    177 			       n - firstReal, info);
    178     pFont->info.constantMetrics = cm;
    179     free(charinfo);
    180     return TRUE;
    181 }
    182 
    183 Bool
    184 xfont2_parse_glyph_caching_mode(char *str)
    185 {
    186     if (!strcmp(str, "none")) defaultGlyphCachingMode = CACHING_OFF;
    187     else if (!strcmp(str, "all")) defaultGlyphCachingMode = CACHE_ALL_GLYPHS;
    188     else if (!strcmp(str, "16")) defaultGlyphCachingMode = CACHE_16_BIT_GLYPHS;
    189     else return FALSE;
    190     return TRUE;
    191 }
    192 
    193 void
    194 xfont2_init_glyph_caching(void)
    195 {
    196     /* Set glyphCachingMode to the mode the server hopes to
    197        support.  DDX drivers that do not support the requested level
    198        of glyph caching can call SetGlyphCachingMode to lower the
    199        level of support.
    200      */
    201 
    202     glyphCachingMode = defaultGlyphCachingMode;
    203 }
    204 
    205 /* ddxen can call SetGlyphCachingMode to inform us of what level of glyph
    206  * caching they can support.
    207  */
    208 void
    209 xfont2_set_glyph_caching_mode(int newmode)
    210 {
    211     if ( (glyphCachingMode > newmode) && (newmode >= 0) )
    212 	glyphCachingMode = newmode;
    213 }
    214 
    215 #define range_alloc_granularity 16
    216 #define mincharp(p) ((p)->min_char_low + ((p)->min_char_high << 8))
    217 #define maxcharp(p) ((p)->max_char_low + ((p)->max_char_high << 8))
    218 
    219 /* add_range(): Add range to a list of ranges, with coalescence */
    220 int
    221 add_range(fsRange *newrange,
    222 	  int *nranges,
    223 	  fsRange **range,
    224 	  Bool charset_subset)
    225 {
    226     int first, last, middle;
    227     unsigned long keymin, keymax;
    228     unsigned long ptrmin = 0, ptrmax = 0;
    229     fsRange *ptr = NULL, *ptr1, *ptr2, *endptr;
    230 
    231     /* There are two different ways to treat ranges:
    232 
    233        1) Charset subsetting (support of the HP XLFD enhancements), in
    234 	  which a range of 0x1234,0x3456 means all numbers between
    235 	  0x1234 and 0x3456, and in which min and max might be swapped.
    236 
    237        2) Row/column ranges, in which a range of 0x1234,0x3456 means the
    238 	  ranges 0x1234-0x1256, 0x1334-0x1356, ...  , 0x3434-0x3456.
    239 	  This is for support of glyph caching.
    240 
    241        The choice of treatment is selected with the "charset_subset"
    242        flag */
    243 
    244     /* If newrange covers multiple rows; break up the rows */
    245     if (!charset_subset && newrange->min_char_high != newrange->max_char_high)
    246     {
    247 	int i, err = 0;
    248 	fsRange temprange;
    249 	for (i = newrange->min_char_high;
    250 	     i <= newrange->max_char_high;
    251 	     i++)
    252 	{
    253 	    temprange.min_char_low = newrange->min_char_low;
    254 	    temprange.max_char_low = newrange->max_char_low;
    255 	    temprange.min_char_high = temprange.max_char_high = i;
    256 	    err = add_range(&temprange, nranges, range, charset_subset);
    257 	    if (err != Successful) break;
    258 	}
    259 	return err;
    260     }
    261 
    262     keymin = mincharp(newrange);
    263     keymax = maxcharp(newrange);
    264 
    265     if (charset_subset && keymin > keymax)
    266     {
    267 	unsigned long temp = keymin;
    268 	keymin = keymax;
    269 	keymax = temp;
    270     }
    271 
    272     /* add_range() maintains a sorted list; this makes possible coalescence
    273        and binary searches */
    274 
    275     /* Binary search for a range with which the new range can merge */
    276 
    277     first = middle = 0;
    278     last = *nranges - 1;
    279     while (last >= first)
    280     {
    281 	middle = (first + last) / 2;
    282 	ptr = (*range) + middle;
    283 	ptrmin = mincharp(ptr);
    284 	ptrmax = maxcharp(ptr);
    285 
    286 	if (ptrmin > 0 && keymax < ptrmin - 1) last = middle - 1;
    287 	else if (keymin > ptrmax + 1) first = middle + 1;
    288 	else if (!charset_subset)
    289 	{
    290 	    /* We might have a range with which to merge... IF the
    291 	       result doesn't cross rows */
    292 	    if (newrange->min_char_high != ptr->min_char_high)
    293 		last = first - 1;	/* Force adding a new range */
    294 	    break;
    295 	}
    296 	else break;	/* We have at least one range with which we can merge */
    297     }
    298 
    299     if (last < first)
    300     {
    301 	/* Search failed; we need to add a new range to the list. */
    302 
    303 	/* Grow the list if necessary */
    304 	if (*nranges == 0 || *range == (fsRange *)0)
    305 	{
    306 	    *range = mallocarray(range_alloc_granularity, SIZEOF(fsRange));
    307 	    *nranges = 0;
    308 	}
    309 	else if (!(*nranges % range_alloc_granularity))
    310 	{
    311 	    *range = reallocarray(*range, (*nranges + range_alloc_granularity),
    312 				  SIZEOF(fsRange));
    313 	}
    314 
    315 	/* If alloc failed, just return a null list */
    316 	if (*range == (fsRange *)0)
    317 	{
    318 	    *nranges = 0;
    319 	    return AllocError;
    320 	}
    321 
    322 	/* Should new entry go *at* or *after* ptr? */
    323 	ptr = (*range) + middle;
    324 	if (middle < *nranges && keymin > ptrmin) ptr++;	/* after */
    325 
    326 	/* Open up a space for our new range */
    327 	memmove((char *)(ptr + 1),
    328 		(char *)ptr,
    329 		(char *)(*range + *nranges) - (char *)ptr);
    330 
    331 	/* Insert the new range */
    332 	ptr->min_char_low = keymin & 0xff;
    333 	ptr->min_char_high = keymin >> 8;
    334 	ptr->max_char_low = keymax & 0xff;
    335 	ptr->max_char_high = keymax >> 8;
    336 
    337 	/* Update range count */
    338 	(*nranges)++;
    339 
    340 	/* Done */
    341 	return Successful;
    342     }
    343 
    344     /* Join our new range to that pointed to by "ptr" */
    345     if (keymin < ptrmin)
    346     {
    347 	ptr->min_char_low = keymin & 0xff;
    348 	ptr->min_char_high = keymin >> 8;
    349     }
    350     if (keymax > ptrmax)
    351     {
    352 	ptr->max_char_low = keymax & 0xff;
    353 	ptr->max_char_high = keymax >> 8;
    354     }
    355 
    356     ptrmin = mincharp(ptr);
    357     ptrmax = maxcharp(ptr);
    358 
    359     endptr = *range + *nranges;
    360 
    361     for (ptr1 = ptr; ptr1 >= *range; ptr1--)
    362     {
    363 	if (ptrmin <= maxcharp(ptr1) + 1)
    364 	{
    365 	    if (!charset_subset && ptr->min_char_high != ptr1->min_char_high)
    366 		break;
    367 	    if (ptrmin >= mincharp(ptr1))
    368 		ptrmin = mincharp(ptr1);
    369 	}
    370 	else break;
    371     }
    372     for (ptr2 = ptr; ptr2 < endptr; ptr2++)
    373     {
    374 	if ((ptr2->min_char_low == 0 && ptr2->min_char_high == 0) ||
    375 	    ptrmax >= mincharp(ptr2) - 1)
    376 	{
    377 	    if (!charset_subset && ptr->min_char_high != ptr2->min_char_high)
    378 		break;
    379 	    if (ptrmax <= maxcharp(ptr2))
    380 		ptrmax = maxcharp(ptr2);
    381 	}
    382 	else break;
    383     }
    384 
    385     /* We need to coalesce ranges between ptr1 and ptr2 exclusive */
    386     ptr1++;
    387     ptr2--;
    388     if (ptr1 != ptr2)
    389     {
    390 	memmove(ptr1, ptr2, (char *)endptr - (char *)ptr2);
    391 	*nranges -= (ptr2 - ptr1);
    392     }
    393 
    394     /* Write the new range into the range list */
    395     ptr1->min_char_low = ptrmin & 0xff;
    396     ptr1->min_char_high = ptrmin >> 8;
    397     ptr1->max_char_low = ptrmax & 0xff;
    398     ptr1->max_char_high = ptrmax >> 8;
    399 
    400     return Successful;
    401 }
    402