#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <X11/fonts/fontmisc.h>
#include <X11/fonts/fontstruct.h>
#include <X11/fonts/FSproto.h>
#include <X11/fonts/fontutil.h>
static int defaultGlyphCachingMode = DEFAULT_GLYPH_CACHING_MODE;
int glyphCachingMode = DEFAULT_GLYPH_CACHING_MODE;
void
GetGlyphs(FontPtr font,
unsigned long count,
unsigned char *chars,
FontEncoding fontEncoding,
unsigned long *glyphcount,
CharInfoPtr *glyphs)
{
(*font->get_glyphs) (font, count, chars, fontEncoding, glyphcount, glyphs);
}
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
void
QueryGlyphExtents(FontPtr pFont,
CharInfoPtr *charinfo,
unsigned long count,
ExtentInfoRec *info)
{
register unsigned long i;
xCharInfo *pCI;
info->drawDirection = pFont->info.drawDirection;
info->fontAscent = pFont->info.fontAscent;
info->fontDescent = pFont->info.fontDescent;
if (count != 0) {
pCI = &((*charinfo)->metrics); charinfo++;
if ( !((pCI->characterWidth == 0)
&& (pCI->rightSideBearing == 0)
&& (pCI->leftSideBearing == 0)
&& (pCI->ascent == 0)
&& (pCI->descent == 0)) ) {
info->overallAscent = pCI->ascent;
info->overallDescent = pCI->descent;
info->overallLeft = pCI->leftSideBearing;
info->overallRight = pCI->rightSideBearing;
info->overallWidth = pCI->characterWidth;
}
if (pFont->info.constantMetrics && pFont->info.noOverlap) {
info->overallWidth *= count;
info->overallRight += (info->overallWidth -
pCI->characterWidth);
} else {
for (i = 1; i < count; i++) {
pCI = &((*charinfo)->metrics); charinfo++;
if ( !((pCI->characterWidth == 0)
&& (pCI->rightSideBearing == 0)
&& (pCI->leftSideBearing == 0)
&& (pCI->ascent == 0)
&& (pCI->descent == 0)) ) {
info->overallAscent = MAX(
info->overallAscent,
pCI->ascent);
info->overallDescent = MAX(
info->overallDescent,
pCI->descent);
info->overallLeft = MIN(
info->overallLeft,
info->overallWidth + pCI->leftSideBearing);
info->overallRight = MAX(
info->overallRight,
info->overallWidth + pCI->rightSideBearing);
info->overallWidth += pCI->characterWidth;
}
}
}
} else {
info->overallAscent = 0;
info->overallDescent = 0;
info->overallWidth = 0;
info->overallLeft = 0;
info->overallRight = 0;
}
}
Bool
QueryTextExtents(FontPtr pFont,
unsigned long count,
unsigned char *chars,
ExtentInfoRec *info)
{
xCharInfo **charinfo;
unsigned long n;
FontEncoding encoding;
int cm;
int i;
unsigned long t;
xCharInfo *defaultChar = 0;
unsigned char defc[2];
int firstReal;
charinfo = malloc(count * sizeof(xCharInfo *));
if (!charinfo)
return FALSE;
encoding = TwoD16Bit;
if (pFont->info.lastRow == 0)
encoding = Linear16Bit;
(*pFont->get_metrics) (pFont, count, chars, encoding, &n, charinfo);
#define IsNonExistentChar(ci) (!(ci) || \
((ci)->ascent == 0 && \
(ci)->descent == 0 && \
(ci)->leftSideBearing == 0 && \
(ci)->rightSideBearing == 0 && \
(ci)->characterWidth == 0))
firstReal = n;
defc[0] = pFont->info.defaultCh >> 8;
defc[1] = pFont->info.defaultCh;
(*pFont->get_metrics) (pFont, 1, defc, encoding, &t, &defaultChar);
if ((IsNonExistentChar (defaultChar)))
defaultChar = 0;
for (i = 0; i < n; i++)
{
if ((IsNonExistentChar (charinfo[i])))
{
if (!defaultChar)
continue;
charinfo[i] = defaultChar;
}
if (firstReal == n)
firstReal = i;
}
cm = pFont->info.constantMetrics;
pFont->info.constantMetrics = FALSE;
QueryGlyphExtents(pFont, (CharInfoPtr*) charinfo + firstReal,
n - firstReal, info);
pFont->info.constantMetrics = cm;
free(charinfo);
return TRUE;
}
Bool
ParseGlyphCachingMode(char *str)
{
if (!strcmp(str, "none")) defaultGlyphCachingMode = CACHING_OFF;
else if (!strcmp(str, "all")) defaultGlyphCachingMode = CACHE_ALL_GLYPHS;
else if (!strcmp(str, "16")) defaultGlyphCachingMode = CACHE_16_BIT_GLYPHS;
else return FALSE;
return TRUE;
}
void
InitGlyphCaching(void)
{
glyphCachingMode = defaultGlyphCachingMode;
}
void
SetGlyphCachingMode(int newmode)
{
if ( (glyphCachingMode > newmode) && (newmode >= 0) )
glyphCachingMode = newmode;
}
#define range_alloc_granularity 16
#define mincharp(p) ((p)->min_char_low + ((p)->min_char_high << 8))
#define maxcharp(p) ((p)->max_char_low + ((p)->max_char_high << 8))
int
add_range(fsRange *newrange,
int *nranges,
fsRange **range,
Bool charset_subset)
{
int first, last, middle;
unsigned long keymin, keymax;
unsigned long ptrmin = 0, ptrmax = 0;
fsRange *ptr = NULL, *ptr1, *ptr2, *endptr;
if (!charset_subset && newrange->min_char_high != newrange->max_char_high)
{
int i, err = 0;
fsRange temprange;
for (i = newrange->min_char_high;
i <= newrange->max_char_high;
i++)
{
temprange.min_char_low = newrange->min_char_low;
temprange.max_char_low = newrange->max_char_low;
temprange.min_char_high = temprange.max_char_high = i;
err = add_range(&temprange, nranges, range, charset_subset);
if (err != Successful) break;
}
return err;
}
keymin = mincharp(newrange);
keymax = maxcharp(newrange);
if (charset_subset && keymin > keymax)
{
unsigned long temp = keymin;
keymin = keymax;
keymax = temp;
}
first = middle = 0;
last = *nranges - 1;
while (last >= first)
{
middle = (first + last) / 2;
ptr = (*range) + middle;
ptrmin = mincharp(ptr);
ptrmax = maxcharp(ptr);
if (ptrmin > 0 && keymax < ptrmin - 1) last = middle - 1;
else if (keymin > ptrmax + 1) first = middle + 1;
else if (!charset_subset)
{
if (newrange->min_char_high != ptr->min_char_high)
last = first - 1;
break;
}
else break;
}
if (last < first)
{
if (*nranges == 0 || *range == (fsRange *)0)
{
*range = malloc(range_alloc_granularity * SIZEOF(fsRange));
*nranges = 0;
}
else if (!(*nranges % range_alloc_granularity))
{
*range = realloc(*range, (*nranges + range_alloc_granularity) *
SIZEOF(fsRange));
}
if (*range == (fsRange *)0)
{
*nranges = 0;
return AllocError;
}
ptr = (*range) + middle;
if (middle < *nranges && keymin > ptrmin) ptr++;
memmove((char *)(ptr + 1),
(char *)ptr,
(char *)(*range + *nranges) - (char *)ptr);
ptr->min_char_low = keymin & 0xff;
ptr->min_char_high = keymin >> 8;
ptr->max_char_low = keymax & 0xff;
ptr->max_char_high = keymax >> 8;
(*nranges)++;
return Successful;
}
if (keymin < ptrmin)
{
ptr->min_char_low = keymin & 0xff;
ptr->min_char_high = keymin >> 8;
}
if (keymax > ptrmax)
{
ptr->max_char_low = keymax & 0xff;
ptr->max_char_high = keymax >> 8;
}
ptrmin = mincharp(ptr);
ptrmax = maxcharp(ptr);
endptr = *range + *nranges;
for (ptr1 = ptr; ptr1 >= *range; ptr1--)
{
if (ptrmin <= maxcharp(ptr1) + 1)
{
if (!charset_subset && ptr->min_char_high != ptr1->min_char_high)
break;
if (ptrmin >= mincharp(ptr1))
ptrmin = mincharp(ptr1);
}
else break;
}
for (ptr2 = ptr; ptr2 < endptr; ptr2++)
{
if ((ptr2->min_char_low == 0 && ptr2->min_char_high == 0) ||
ptrmax >= mincharp(ptr2) - 1)
{
if (!charset_subset && ptr->min_char_high != ptr2->min_char_high)
break;
if (ptrmax <= maxcharp(ptr2))
ptrmax = maxcharp(ptr2);
}
else break;
}
ptr1++;
ptr2--;
if (ptr1 != ptr2)
{
memmove(ptr1, ptr2, (char *)endptr - (char *)ptr2);
*nranges -= (ptr2 - ptr1);
}
ptr1->min_char_low = ptrmin & 0xff;
ptr1->min_char_high = ptrmin >> 8;
ptr1->max_char_low = ptrmax & 0xff;
ptr1->max_char_high = ptrmax >> 8;
return Successful;
}