#include "unix/guts.h"
static
PHash xfontCache = NULL;
static
Bool have_vector_fonts =
false
;
static
PHash encodings = NULL;
static
char
**ignore_encodings;
static
int
n_ignore_encodings;
static
char
*s_ignore_encodings;
static
Bool do_core_fonts =
true
;
static
Bool do_no_scaled_fonts =
false
;
#define MY_MATRIX (PDrawable(self)->current_state.matrix)
#define DEBUG_FONT(font) font.height,font.width,font.size,font.name,font.encoding
static
Bool detail_font_info( PFontInfo f, PFont font, PCachedFont kf, Bool bySize);
static
Bool xlfd_parse_font(
char
* xlfd_name, PFontInfo info, Bool do_vector_fonts);
static
void
str_lwr(
char
*d,
const
char
*s)
{
while
( *s) {
*d++ =
tolower
( *s++);
}
*d =
'\0'
;
}
Bool
prima_corefont_init(
char
*error_buf)
{
char
**names;
int
count, j , i, vector_fonts = 0;
PFontInfo info;
if
( do_core_fonts) {
int
nocorefonts = 0;
apc_fetch_resource(
"Prima"
,
""
,
"Nocorefonts"
,
"nocorefonts"
,
NULL_HANDLE, frUnix_int, &nocorefonts);
if
( nocorefonts) do_core_fonts =
false
;
}
guts. font_names = names = XListFonts( DISP,
do_core_fonts ?
"*"
:
"-*-fixed-*"
,
INT_MAX, &count);
if
( !names) {
sprintf
( error_buf,
"No fonts returned by XListFonts, cannot continue"
);
return
false
;
}
info =
malloc
(
sizeof
( FontInfo) * count);
if
( !info) {
sprintf
( error_buf,
"No memory (%d bytes)"
, (
int
)
sizeof
(FontInfo)*count);
return
false
;
}
bzero( info,
sizeof
( FontInfo) * count);
n_ignore_encodings = 0;
ignore_encodings = NULL;
s_ignore_encodings = NULL;
if
( apc_fetch_resource(
"Prima"
,
""
,
"IgnoreEncodings"
,
"ignoreEncodings"
,
NULL_HANDLE, frString, &s_ignore_encodings))
{
char
*e = s_ignore_encodings;
char
*s = e;
while
(*e) {
while
(*e && *e !=
';'
) {
e++;
}
if
(*e ==
';'
) {
n_ignore_encodings++;
*e =
'\0'
;
s = ++e;
}
else
if
(e > s) {
n_ignore_encodings++;
}
}
ignore_encodings =
malloc
(
sizeof
(
char
*) * n_ignore_encodings);
if
( !ignore_encodings) {
sprintf
( error_buf,
"No memory"
);
return
false
;
}
bzero( ignore_encodings,
sizeof
(
char
*) * n_ignore_encodings);
s = s_ignore_encodings;
for
(i = 0; i < n_ignore_encodings; i++) {
ignore_encodings[i] = s;
while
(*s) s++;
s++;
}
}
encodings = hash_create();
apc_fetch_resource(
"Prima"
,
""
,
"Noscaledfonts"
,
"noscaledfonts"
,
NULL_HANDLE, frUnix_int, &guts. no_scaled_fonts);
if
( do_no_scaled_fonts) guts. no_scaled_fonts = 1;
for
( i = 0, j = 0; i < count; i++) {
if
( xlfd_parse_font( names[i], info + j,
true
)) {
vector_fonts += ( info[j]. font. vector == fvBitmap ) ? 0 : 1;
info[j]. xname = names[ i];
j++;
}
}
guts. font_info = info;
guts. n_fonts = j;
if
( vector_fonts > 0) have_vector_fonts =
true
;
xfontCache = hash_create();
{
int
len;
char
* s =
setlocale
( LC_CTYPE, NULL);
while
( *s && *s !=
'.'
) s++;
while
( *s && *s ==
'.'
) s++;
strlcpy( guts. locale, s, 31);
len =
strlen
( guts. locale);
if
( !hash_fetch( encodings, guts. locale, len)) {
str_lwr( guts. locale, guts. locale);
if
( !hash_fetch( encodings, guts. locale, len) &&
(
(
strncmp
( guts. locale,
"iso-"
, 4) == 0)||
(
strncmp
( guts. locale,
"iso_"
, 4) == 0)
)
) {
s = guts. locale + 3;
while
( *s) {
*s = s[1];
s++;
}
if
( !hash_fetch( encodings, guts. locale, len - 1))
guts. locale[0] = 0;
}
}
if
(
strcmp
( guts. locale,
"utf-8"
) == 0 )
strcpy
( guts. locale,
"iso10646-1"
);
}
return
true
;
}
Bool
prima_corefont_set_option(
char
* option,
char
* value)
{
if
(
strcmp
( option,
"no-core-fonts"
) == 0) {
if
( value) warn(
"`--no-core' option has no parameters"
);
do_core_fonts =
false
;
return
true
;
}
else
if
(
strcmp
( option,
"noscaled"
) == 0) {
if
( value) warn(
"`--noscaled' option has no parameters"
);
do_no_scaled_fonts =
true
;
return
true
;
}
return
false
;
}
void
prima_corefont_encodings(PHash hash)
{
HE *he;
hv_iterinit(( HV*) encodings);
for
(;;) {
if
(( he = hv_iternext( encodings)) == NULL)
break
;
hash_store( hash, HeKEY( he), HeKLEN( he), (
void
*)1);
}
}
Bool
prima_corefont_encoding(
char
* encoding)
{
return
hash_fetch( encodings, encoding,
strlen
( encoding)) != NULL;
}
static
void
font_query_name( XFontStruct * s, PFontInfo f)
{
unsigned
long
v;
char
* c;
if
( !f-> flags. encoding) {
c = NULL;
if
( XGetFontProperty( s, FXA_CHARSET_REGISTRY, &v) && v) {
XCHECKPOINT;
c = XGetAtomName( DISP, (Atom)v);
XCHECKPOINT;
if
( c) {
f-> flags. encoding =
true
;
str_lwr( f-> font. encoding, c);
XFree( c);
}
}
if
( c) {
c = NULL;
if
( XGetFontProperty( s, FXA_CHARSET_ENCODING, &v) && v) {
XCHECKPOINT;
c = XGetAtomName( DISP, (Atom)v);
XCHECKPOINT;
if
( c) {
strcat
( f-> font. encoding,
"-"
);
str_lwr( f-> font. encoding +
strlen
( f-> font. encoding), c);
XFree( c);
}
}
}
if
( !c) {
f-> flags. encoding =
false
;
f-> font. encoding[0] = 0;
}
}
if
( ! f-> flags. family && XGetFontProperty( s, FXA_FOUNDRY, &v) && v) {
XCHECKPOINT;
c = XGetAtomName( DISP, (Atom)v);
XCHECKPOINT;
if
( c) {
f-> flags. family =
true
;
strlcpy( f-> font. family, c, 255);
str_lwr( f-> font. family, f-> font. family);
XFree( c);
}
}
if
( ! f-> flags. name && XGetFontProperty( s, FXA_FAMILY_NAME, &v) && v) {
XCHECKPOINT;
c = XGetAtomName( DISP, (Atom)v);
XCHECKPOINT;
if
( c) {
f-> flags. name =
true
;
strlcpy( f-> font. name, c, 255);
str_lwr( f-> font. name, f-> font. name);
XFree( c);
}
}
if
( ! f-> flags. family && ! f-> flags. name) {
c = f-> xname;
if
(
strchr
( c,
'-'
) == NULL) {
strcpy
( f-> font. name, c);
strcpy
( f-> font. family, c);
}
else
{
char
* d = c;
int
cnt = 0, lim;
if
( *d ==
'-'
) d++;
while
( *(c++)) {
if
( *c ==
'-'
|| *(c + 1)==0) {
if
( c == d )
continue
;
if
( cnt == 0 ) {
lim = ( c - d > 255 ) ? 255 : c - d;
strlcpy( f-> font. family, d, lim);
cnt++;
}
else
if
( cnt == 1) {
lim = ( c - d > 255 ) ? 255 : c - d;
strlcpy( f-> font. name, d, lim);
break
;
}
else
break
;
d = c + 1;
}
}
if
((
strlen
( f-> font. family) == 0) || (
strcmp
( f-> font. family,
"*"
) == 0))
strcpy
( f-> font. family, guts. default_font. family);
if
((
strlen
( f-> font. name) == 0) || (
strcmp
( f-> font. name,
"*"
) == 0)) {
if
( guts. default_font_ok) {
strcpy
( f-> font. name, guts. default_font. name);
}
else
{
Font fx = f-> font;
prima_fill_default_font( &fx);
if
( f-> flags. encoding)
strcpy
( fx. encoding, f-> font. encoding);
prima_font_pick( &fx, NULL, NULL, FONTKEY_CORE);
strcpy
( f-> font. name, fx. name);
}
}
else
{
char
c[512];
snprintf( c, 512,
"%s %s"
, f-> font. family, f-> font. name);
strlcpy( f-> font. name, c, 256);
}
}
str_lwr( f-> font. family, f-> font. family);
str_lwr( f-> font. name, f-> font. name);
f-> flags. name =
true
;
f-> flags. family =
true
;
}
else
if
( ! f-> flags. family ) {
str_lwr( f-> font. family, f-> font. name);
f-> flags. name =
true
;
}
else
if
( ! f-> flags. name ) {
str_lwr( f-> font. name, f-> font. family);
f-> flags. name =
true
;
}
}
static
Bool
xlfd_parse_font(
char
* xlfd_name, PFontInfo info, Bool do_vector_fonts)
{
char
*b, *t, *c = xlfd_name;
int
nh = 0;
Bool conformant = 0;
int
style = 0;
int
vector = 0;
bzero( &info-> font,
sizeof
(info->font));
bzero( &info-> flags,
sizeof
(info->flags));
info-> flags. sloppy =
true
;
while
(*c)
if
( *c++ ==
'-'
) nh++;
c = xlfd_name;
if
( nh == 14) {
if
( *c ==
'+'
)
while
(*c && *c !=
'-'
) c++;
t = info-> font. family;
if
( *c ==
'-'
) {
++c;
while
( *c && *c !=
'-'
) { *t++ = *c++; }
*t++ =
'\0'
;
}
if
( *c ==
'-'
) {
++c; b = t;
while
( *c && *c !=
'-'
) { *t++ = *c++; }
info-> name_offset = c - xlfd_name;
*t =
'\0'
;
info-> flags. name =
true
;
info-> flags. family =
true
;
strcpy
( info-> font. name, b);
if
(
( info-> font.family[0] ==
'*'
&& info-> font.family[1] == 0) ||
( b[0] ==
'*'
&& b[1] == 0)
) {
Font xf;
int
noname = ( b[0] ==
'*'
&& b[1] == 0);
int
nofamily = ( info-> font.family[0] ==
'*'
&& info-> font.family[1] == 0);
if
( guts. default_font_ok)
xf = guts. default_font;
else
prima_fill_default_font( &xf);
if
( !nofamily)
strcpy
( xf. family, info-> font. family);
if
( !noname)
strcpy
( xf. name, info-> font. name);
prima_font_pick( &xf, NULL, NULL, FONTKEY_CORE);
if
( noname)
strcpy
( info-> font. name, xf. name);
if
( nofamily)
strcpy
( info-> font. family, xf. family);
}
if
(
(
strcmp
( info->font.name,
"clean"
) == 0) ||
(
strcmp
( info->font.name,
"fixed"
) == 0) ||
(
strcmp
( info->font.name,
"bitstream charter"
) == 0)
)
info-> flags. known = 1;
}
if
( *c ==
'-'
) {
b = ++c;
while
( *c && *c !=
'-'
) c++;
if
(
c-b == 0 ||
(c-b == 6 && strncasecmp( b,
"medium"
, 6) == 0) ||
(c-b == 7 && strncasecmp( b,
"regular"
, 7) == 0)
) {
info-> font. style = fsNormal;
style++;
info-> font. weight = fwMedium;
info-> flags. weight =
true
;
}
else
if
( c-b == 4 && strncasecmp( b,
"bold"
, 4) == 0) {
info-> font. style = fsBold;
style++;
info-> font. weight = fwBold;
info-> flags. weight =
true
;
}
else
if
( c-b == 8 && strncasecmp( b,
"demibold"
, 8) == 0) {
info-> font. style = fsBold;
style++;
info-> font. weight = fwSemiBold;
info-> flags. weight =
true
;
}
else
if
( c-b == 1 && *b ==
'*'
) {
info-> font. style = fsNormal;
style++;
info-> font. weight = fwMedium;
info-> flags. weight =
true
;
}
}
if
( *c ==
'-'
) {
b = ++c;
while
( *c && *c !=
'-'
) c++;
if
( c-b == 1 && (*b ==
'R'
|| *b ==
'r'
)) {
style++;
}
else
if
( c-b == 1 && (*b ==
'I'
|| *b ==
'i'
)) {
info-> font. style |= fsItalic;
style++;
}
else
if
( c-b == 1 && (*b ==
'O'
|| *b ==
'o'
)) {
info-> font. style |= fsItalic;
style++;
}
else
if
( c-b == 2 && (*b ==
'R'
|| *b ==
'r'
) && (b[1] ==
'I'
|| b[1] ==
'i'
)) {
info-> font. style |= fsItalic;
style++;
}
else
if
( c-b == 2 && (*b ==
'R'
|| *b ==
'r'
) && (b[1] ==
'O'
|| b[1] ==
'o'
)) {
info-> font. style |= fsItalic;
style++;
}
}
if
( *c ==
'-'
) {
b = ++c;
while
( *c && *c !=
'-'
) c++;
if
( c-b == 9 && strncasecmp( b,
"condensed"
, 9) == 0) {
info-> font. style |= fsThin;
style++;
}
}
if
( *c ==
'-'
) {
++c;
while
( *c && *c !=
'-'
) c++;
}
if
( *c ==
'-'
) {
c++; b = c;
if
( *c !=
'-'
)
info-> font. height =
strtol
( c, &b, 10);
if
( c != b) {
if
( info-> font. height) {
info-> flags. height =
true
;
}
else
{
vector++;
}
c = b;
}
else
if
(
strncmp
( c,
"*-"
, 2) == 0) c++;
}
if
( *c ==
'-'
) {
c++; b = c;
if
( *c !=
'-'
)
info-> font. size =
strtol
( c, &b, 10);
if
( c != b) {
if
( info-> font. size) {
info-> flags. size =
true
;
info-> font. size = ( info-> font. size < 10) ?
1 : ( info-> font. size / 10);
}
else
{
vector++;
}
c = b;
}
else
if
(
strncmp
( c,
"*-"
, 2) == 0) c++;
}
if
( *c ==
'-'
) {
c++; b = c;
if
( *c !=
'-'
)
info-> font. xDeviceRes =
strtol
( c, &b, 10);
if
( c != b) {
if
( info-> font. xDeviceRes) {
info-> flags. xDeviceRes =
true
;
}
else
{
vector++;
}
c = b;
}
else
if
(
strncmp
( c,
"*-"
, 2) == 0) c++;
}
if
( *c ==
'-'
) {
c++; b = c;
if
( *c !=
'-'
)
info-> font. yDeviceRes =
strtol
( c, &b, 10);
if
( c != b) {
if
( info-> font. yDeviceRes) {
info-> flags. yDeviceRes =
true
;
}
else
{
vector++;
}
c = b;
}
else
if
(
strncmp
( c,
"*-"
, 2) == 0) c++;
}
if
( *c ==
'-'
) {
b = ++c;
while
( *c && *c !=
'-'
) c++;
if
( c - b == 1) {
if
(
strchr
(
"pP"
, *b)) {
info-> font. pitch = fpVariable;
info-> flags. pitch =
true
;
}
else
if
(
strchr
(
"mMcC"
, *b)) {
info-> font. pitch = fpFixed;
info-> flags. pitch =
true
;
}
else
if
( *b ==
'*'
) {
info-> font. pitch = fpDefault;
info-> flags. pitch =
true
;
}
}
}
if
( *c ==
'-'
) {
c++; b = c;
if
( *c !=
'-'
)
info-> font. width =
strtol
( c, &b, 10);
if
( c != b) {
if
( info-> font. width) {
info-> flags. width =
true
;
info-> font. width = ( info-> font. width < 10) ?
1 : ( info-> font. width / 10);
}
else
{
vector++;
}
c = b;
}
else
if
(
strncmp
( c,
"*-"
, 2) == 0) c++;
}
if
( *c ==
'-'
) {
++c;
info-> info_offset = c - xlfd_name;
if
(
strchr
( c,
'*'
) == NULL) {
info-> flags. encoding = 1;
strcpy
( info-> font. encoding, c);
hash_store( encodings, c,
strlen
( c), (
void
*)1);
}
else
info-> font. encoding[0] = 0;
if
(
( strncasecmp( c,
"sunolglyph"
,
strlen
(
"sunolglyph"
)) == 0) ||
( strncasecmp( c,
"sunolcursor"
,
strlen
(
"sunolcursor"
)) == 0) ||
( strncasecmp( c,
"misc"
,
strlen
(
"misc"
)) == 0)
)
info-> flags. funky = 1;
while
( *c && *c !=
'-'
) c++;
}
if
( *c ==
'-'
) {
int
m;
c++;
for
(m = 0; m < n_ignore_encodings; m++) {
if
(
strcmp
(c, ignore_encodings[m]) == 0)
goto
skip_font;
}
if
(
(
strncmp
( c,
"0"
,
strlen
(
"0"
)) == 0) ||
(
strncmp
( c,
"fontspecific"
,
strlen
(
"fontspecific"
)) == 0) ||
(
strncmp
( c,
"special"
,
strlen
(
"special"
)) == 0)
)
info-> flags. funky = 1;
while
( *c && *c !=
'-'
) c++;
if
( !*c && info-> flags. pitch &&
( !do_vector_fonts || vector == 5 || vector == 3 ||
( info-> flags. height &&
info-> flags. size &&
info-> flags. xDeviceRes &&
info-> flags. yDeviceRes &&
info-> flags. width))) {
conformant =
true
;
if
( style == 2) info-> flags. style =
true
;
if
( do_vector_fonts && ( vector == 5 || vector == 3)) {
char
pattern[ 1024], *pat = pattern;
int
dash = 0;
info-> font. vector = fvScalableBitmap;
if
( guts. no_scaled_fonts) info-> flags. disabled =
true
;
info-> flags. bad_vector = (vector == 3);
c = xlfd_name;
while
(*c) {
if
( *c ==
'%'
) {
*pat++ = *c;
*pat++ = *c++;
}
else
if
( *c ==
'-'
) {
dash++;
*pat++ = *c++;
switch
( dash) {
case
9:
case
10:
if
( vector == 3)
break
;
case
7:
case
8:
case
12:
*pat++ =
'%'
;
*pat++ =
'd'
;
while
(*c && *c !=
'-'
) c++;
break
;
}
}
else
{
*pat++ = *c++;
}
}
*pat++ =
'\0'
;
if
(( info-> vecname =
malloc
( pat - pattern)))
strcpy
( info-> vecname, pattern);
}
else
info-> font. vector = fvBitmap;
info-> flags. vector =
true
;
}
}
}
skip_font:
return
conformant;
}
Bool
prima_corefont_pick_default_font_with_encoding(
void
)
{
PFontInfo info;
int
i, best = -1, best_weight = 0, max_weight = 5;
if
( !guts. no_scaled_fonts) max_weight++;
for
( i = 0, info = guts. font_info; i < guts. n_fonts; i++, info++) {
if
(
strcmp
( info-> font. encoding, guts. locale) == 0) {
int
weight = 0;
if
( info-> font. style == fsNormal) weight++;
if
( info-> font. weight == fwMedium) weight++;
if
( info-> font. pitch == fpVariable) weight++;
if
( info-> font. vector > fvBitmap) weight++;
if
(
(
strcmp
( info-> font.name,
"helvetica"
) == 0 ) ||
(
strcmp
( info-> font.name,
"arial"
) == 0 )
)
weight+=2;
if
(
(
strcmp
( info-> font.name,
"lucida"
) == 0 ) ||
(
strcmp
( info-> font.name,
"verdana"
) == 0 )
)
weight++;
if
( weight > best_weight) {
best_weight = weight;
best = i;
if
( weight == max_weight)
break
;
}
}
}
if
( best >= 0) {
prima_fill_default_font( &guts. default_font);
strcpy
( guts. default_font. name, guts. font_info[best].font.name);
strcpy
( guts. default_font. encoding, guts. locale);
prima_font_pick( &guts. default_font, NULL, NULL, FONTKEY_CORE);
guts. default_font. pitch = fpDefault;
return
true
;
}
return
false
;
}
void
prima_corefont_pp2font(
char
* ppFontNameSize, PFont font)
{
int
i, newEntry = 0, len, dash = 0;
FontInfo fi;
XFontStruct * xf;
Font dummy, def_dummy, *def;
char
buf[512], *p;
if
( !font) font = &dummy;
len =
strlen
( ppFontNameSize);
for
( i = 0, p = ppFontNameSize; i < len; i++, p++)
if
( *p ==
'-'
) dash++;
if
(( dash == 14) && guts. locale[0] && (
strcmp
( ppFontNameSize + len - 4,
"-*-*"
) == 0)) {
memcpy
( buf, ppFontNameSize, len - 3);
buf[ len - 3] = 0;
strncat
( buf, guts. locale, 512 -
strlen
(buf) - 1);
buf[511] = 0;
ppFontNameSize = buf;
len =
strlen
( ppFontNameSize);
}
memset
( font, 0,
sizeof
( Font));
for
( i = 0; i < guts. n_fonts; i++) {
if
(
strcmp
( guts. font_info[i]. xname, ppFontNameSize) == 0) {
*font = guts. font_info[i]. font;
return
;
}
}
xf = ( XFontStruct * ) hash_fetch( xfontCache, ppFontNameSize, len);
if
( !xf ) {
xf = XLoadQueryFont( DISP, ppFontNameSize);
if
( !xf) {
Fdebug(
"font: cannot load %s"
, ppFontNameSize);
if
( !guts. default_font_ok) {
prima_fill_default_font( font);
prima_font_pick( font, NULL, NULL, 0 );
font-> pitch = fpDefault;
}
#ifdef USE_XFT
if
( !guts. use_xft || !prima_xft_parse( ppFontNameSize, font))
#endif
if
( font != &guts. default_font)
*font = guts. default_font;
return
;
}
hash_store( xfontCache, ppFontNameSize, len, xf);
newEntry = 1;
}
bzero( &fi,
sizeof
( fi));
fi. flags. sloppy =
true
;
fi. xname = ppFontNameSize;
xlfd_parse_font( ppFontNameSize, &fi,
false
);
font_query_name( xf, &fi);
detail_font_info( &fi, font, NULL,
false
);
*font = fi. font;
if
( guts. default_font_ok) {
def = &guts. default_font;
}
else
{
prima_fill_default_font( def = &def_dummy);
if
( !prima_font_pick( def, NULL, NULL, 0))
goto
NO_DEFAULT_FONT;
}
if
( font-> height == 0) font-> height = def-> height;
if
( font-> size == 0) font-> size = def-> size;
if
(
strlen
( font-> name) == 0)
strcpy
( font-> name, def-> name);
if
(
strlen
( font-> family) == 0)
strcpy
( font-> family, def-> family);
NO_DEFAULT_FONT:
prima_font_pick( font, NULL, NULL, 0);
if
(
( stricmp( font-> family, fi. font. family) == 0) &&
( stricmp( font-> name, fi. font. name) == 0)
) newEntry = 0;
if
( newEntry ) {
PFontInfo n =
realloc
( guts. font_info,
sizeof
( FontInfo) * (guts. n_fonts + 1));
if
( n) {
guts. font_info = n;
fi. font = *font;
guts. font_info[ guts. n_fonts++] = fi;
}
}
Fdebug(
"font: %s%s parsed to: %d.[w=%d,s=%g].%s.%s"
,
newEntry ?
"new "
:
""
, ppFontNameSize, DEBUG_FONT((*font)));
}
static
void
cleanup_rotated_font_entry( PRotatedFont r, unsigned
int
glyph_id )
{
unsigned
int
i = r->length;
while
(i--) {
if
( r-> map[i] )
if
( r-> map[i] && i != glyph_id ) {
prima_free_ximage( r-> map[i]);
r-> map[i] = NULL;
guts.rotated_font_cache_size -= r->arenaSize;
}
}
}
static
Bool
free_rotated_entries( PCachedFont f,
int
keyLen,
void
* key,
void
* this_font)
{
PRotatedFont r;
if
( f->type != FONTKEY_CORE )
return
false
;
r = f->rotated;
while
( r ) {
if
( r != this_font )
cleanup_rotated_font_entry( r, UINT_MAX );
r = (PRotatedFont) r-> next;
}
return
guts.rotated_font_cache_size < MAX_ROTATED_FONT_CACHE_SIZE / 2;
}
static
void
cleanup_rotated_font_cache( PRotatedFont this_font, unsigned
int
this_glyph )
{
if
( guts. font_hash)
hash_first_that( guts. font_hash, (
void
*)free_rotated_entries, this_font, NULL, NULL);
if
( guts.rotated_font_cache_size < MAX_ROTATED_FONT_CACHE_SIZE )
return
;
cleanup_rotated_font_entry( this_font, this_glyph);
}
void
prima_corefont_free_cached_font( PCachedFont f)
{
while
( f-> rotated) {
PRotatedFont r = f-> rotated;
while
( r-> length--) {
if
( r-> map[ r-> length]) {
prima_free_ximage( r-> map[ r-> length]);
r-> map[ r-> length] = NULL;
guts.rotated_font_cache_size -= r->arenaSize;
}
}
f-> rotated = ( PRotatedFont) r-> next;
XFreeGC( DISP, r-> arena_gc);
if
( r-> arena)
XFreePixmap( DISP, r-> arena);
if
( r-> arena_bits)
free
( r-> arena_bits);
free
( r);
}
}
void
prima_corefont_done(
void
)
{
int
i;
if
( guts. font_names)
XFreeFontNames( guts. font_names);
if
( guts. font_info) {
for
( i = 0; i < guts. n_fonts; i++)
if
( guts. font_info[i]. vecname)
free
( guts. font_info[i]. vecname);
free
( guts. font_info);
}
guts. font_names = NULL;
guts. n_fonts = 0;
guts. font_info = NULL;
free
(ignore_encodings);
free
(s_ignore_encodings);
if
( guts. font_hash)
hash_first_that( guts. font_hash, (
void
*)free_rotated_entries, NULL, NULL, NULL);
hash_destroy( xfontCache,
false
);
xfontCache = NULL;
hash_destroy( encodings,
false
);
encodings = NULL;
}
void
prima_corefont_build_key( PFontKey key, PFont f, Bool bySize)
{
key-> height = bySize ? -f-> size * FONT_SIZE_GRANULARITY : f-> height;
key-> width = f-> width;
key-> style = f-> style & ~(fsUnderlined|fsOutline|fsStruckOut) & fsMask;
key-> pitch = f-> pitch & fpMask;
strcpy
( key-> name, f-> name);
strcat
( key-> name,
"\1"
);
strcat
( key-> name, f-> encoding);
}
static
Bool
detail_font_info( PFontInfo f, PFont font, PCachedFont kf, Bool bySize)
{
XFontStruct *s = NULL;
unsigned
long
v;
char
name[ 1024];
FontInfo fi;
PFontInfo of = f;
int
height = 0, size = 0;
HeightGuessStack hgs;
if
( f-> vecname) {
if
( bySize)
size = font-> size * 10 + .5;
else
{
height = font-> height * 10;
prima_font_init_try_height( &hgs, height, f-> flags. heights_cache ? f-> heights_cache[0] : height);
if
( f-> flags. heights_cache)
height = prima_font_try_height( &hgs, f-> heights_cache[1]);
}
}
AGAIN:
if
( f-> vecname) {
memmove
( &fi, f,
sizeof
( fi));
fi. flags. size = fi. flags. height = fi. flags. width = fi. flags. ascent =
fi. flags. descent = fi. flags. internalLeading = 0;
f = &fi;
if
( f-> flags. bad_vector) {
sprintf
( name, f-> vecname, (
int
)((
float
)height / 10.0 + 0.5), size, font-> width * 10);
}
else
{
sprintf
( name, f-> vecname, (
int
)((
float
)height / 10.0 + 0.5), size, 0, 0, font-> width * 10);
}
Fdebug(
"font: construct by %s h=%g, s=%d"
, bySize ?
"size"
:
"height"
, (
float
)height/10, size);
}
else
{
strcpy
( name, f-> xname);
}
Fdebug(
"font: loading %s"
, name);
s = hash_fetch( xfontCache, name,
strlen
( name));
if
( !s) {
s = XLoadQueryFont( DISP, name);
XCHECKPOINT;
if
( !s) {
if
( of-> flags. disabled)
warn(
"font %s pick-up error"
, name);
of-> flags. disabled =
true
;
Fdebug(
"font: kill %s"
, name);
return
false
;
}
else
{
hash_store( xfontCache, name,
strlen
( name), s);
}
}
if
( f-> flags. sloppy || f-> vecname) {
int
h = s-> max_bounds. ascent + s-> max_bounds. descent;
if
( h > 0 )
f-> font. height = h;
f-> flags. height =
true
;
if
( f-> vecname && !bySize && f-> font. height != font-> height) {
int
h = prima_font_try_height( &hgs, f-> font. height * 10);
Fdebug(
"font height pick: %d::%d => %d, advised %d"
, hgs.sp-1, font-> height, f-> font. height, h);
if
( h > 9) {
if
( !of-> flags. heights_cache) {
of-> heights_cache[0] = font-> height * 10;
of-> heights_cache[1] = f-> font. height;
}
height = h;
goto
AGAIN;
}
}
if
( !f-> flags. yDeviceRes) {
if
( XGetFontProperty( s, FXA_RESOLUTION_Y, &v) && v) {
XCHECKPOINT;
f-> font. yDeviceRes = v;
}
else
{
f-> font. yDeviceRes = 72;
}
f-> flags. yDeviceRes =
true
;
}
if
( !f-> flags. xDeviceRes) {
if
( XGetFontProperty( s, FXA_RESOLUTION_X, &v) && v) {
XCHECKPOINT;
f-> font. xDeviceRes = v;
}
else
{
f-> font. xDeviceRes = 72;
}
f-> flags. xDeviceRes =
true
;
}
if
( !f-> flags. internalLeading) {
if
( XGetFontProperty( s, FXA_CAP_HEIGHT, &v) && v) {
XCHECKPOINT;
f-> font. internalLeading = s-> max_bounds. ascent - v;
}
else
{
if
( f-> flags. height) {
f-> font. internalLeading = s-> max_bounds. ascent + s-> max_bounds. descent - f-> font. height;
}
else
if
( f-> flags. size) {
f-> font. internalLeading = s-> max_bounds. ascent + s-> max_bounds. descent -
( f-> font. size * f-> font. yDeviceRes) / 72.0;
}
else
{
f-> font. internalLeading = 0;
}
}
f-> flags. internalLeading =
true
;
}
if
( !f-> flags. underlines) {
int
underlinePos, underlineThickness;
if
( XGetFontProperty( s, XA_UNDERLINE_POSITION, &v) && v) {
XCHECKPOINT;
underlinePos = -s-> max_bounds. descent + v;
}
else
underlinePos = - s-> max_bounds. descent + 1;
if
( XGetFontProperty( s, XA_UNDERLINE_THICKNESS, &v) && v) {
XCHECKPOINT;
underlineThickness = v;
}
else
underlineThickness = 1;
underlinePos -= underlineThickness;
if
( -underlinePos + underlineThickness / 2 > s-> max_bounds. descent)
underlinePos = -s-> max_bounds. descent + underlineThickness / 2;
f-> font.underlinePosition = underlinePos;
f-> font.underlineThickness = underlineThickness;
f-> flags.underlines =
true
;
}
if
( bySize) {
if
( f-> vecname) {
f-> font. size = (
float
) size / 10;
}
else
if
( !f-> flags. size)
f-> font. size = font-> size;
}
else
{
if
( f-> vecname && f-> font. height < font-> height) {
f-> font. internalLeading += font-> height - f-> font. height;
f-> font. height = font-> height;
}
if
( !f-> flags. size) {
if
( XGetFontProperty( s, FXA_POINT_SIZE, &v) && v) {
XCHECKPOINT;
f-> font. size = ( v < 10) ? 1.0 : ( v / 10.0);
}
else
f-> font. size = ( f-> font. height - f-> font. internalLeading) * 72.0 / f-> font. height;
}
}
f-> flags. size =
true
;
f-> font. resolution = f-> font. yDeviceRes * 0x10000 + f-> font. xDeviceRes;
f-> flags. ascent =
true
;
f-> font. ascent = f-> font. height - s-> max_bounds. descent;
f-> flags. descent =
true
;
f-> font. descent = s-> max_bounds. descent;
f-> font. defaultChar = s-> default_char;
f-> font. firstChar = s-> min_byte1 * 256 + s-> min_char_or_byte2;
f-> font. lastChar = s-> max_byte1 * 256 + s-> max_char_or_byte2;
f-> font. direction = 0;
f-> font. externalLeading =
abs
( s-> max_bounds. ascent - s-> ascent) +
abs
( s-> max_bounds. descent - s-> descent);
bzero(&f->font.is_utf8,
sizeof
(f->font.is_utf8));
bzero(&f->font.undef,
sizeof
(f->font.undef));
if
( f-> font. width == 0 || !f-> flags. width) {
if
( f-> vecname && font-> width > 0) {
f-> font. width = font-> width;
Fdebug(
"font: width = copy as is %d"
, f->font.width);
}
else
if
( XGetFontProperty( s, FXA_AVERAGE_WIDTH, &v) && v) {
XCHECKPOINT;
f-> font. width = (v + 5) / 10;
Fdebug(
"font: width = FXA_AVERAGE_WIDTH %d(%d)"
, f->font.width, v);
}
else
{
f-> font. width = s-> max_bounds. width;
Fdebug(
"font: width = max_width %d"
, f->font.width);
}
}
f-> flags. width =
true
;
if
( !f-> flags. maximalWidth) {
f-> flags. maximalWidth =
true
;
if
( s-> per_char) {
int
kl = 0, kr = 255, k;
int
rl = 0, rr = 255, r, d;
f-> font. maximalWidth = 0;
if
( rl < s-> min_byte1) rl = s-> min_byte1;
if
( rr > s-> max_byte1) rr = s-> max_byte1;
if
( kl < s-> min_char_or_byte2) kl = s-> min_char_or_byte2;
if
( kr > s-> max_char_or_byte2) kr = s-> max_char_or_byte2;
d = kr - kl + 1;
for
( r = rl; r <= rr; r++)
for
( k = kl; k <= kr; k++) {
int
x = s-> per_char[( r - s-> min_byte1) * d + k - s-> min_char_or_byte2]. width;
if
( f-> font. maximalWidth < x)
f-> font. maximalWidth = x;
}
}
else
{
f-> font. width = f-> font. maximalWidth = s-> max_bounds. width;
Fdebug(
"font: force width = max_width %d"
, f->font.width);
}
}
of-> flags. sloppy =
false
;
}
if
( !kf )
return
true
;
*font = f-> font;
Fdebug(
"font cache match: %dx%d(%g)%s.%s/%s %s"
, DEBUG_FONT((*font)), _F_DEBUG_STYLE(font->style), _F_DEBUG_PITCH(font->pitch));
kf-> id = s-> fid;
kf-> fs = s;
kf-> flags = f-> flags;
return
true
;
}
#define QUERYDIFF_BY_SIZE (-1)
#define QUERYDIFF_BY_HEIGHT (-2)
static
double
query_diff( PFontInfo fi, PFont f,
char
* lcname,
int
selector)
{
double
diff = 0.0;
int
enc_match = 0, name_match = 0;
if
( fi-> flags. encoding && f-> encoding[0]) {
if
(
strcmp
( f-> encoding, fi-> font. encoding) != 0)
diff += 16000.0;
else
enc_match = 1;
}
if
( guts. locale[0] && !f-> encoding[0] && fi-> flags. encoding) {
if
(
strcmp
( fi-> font. encoding, guts. locale) != 0)
diff += 50;
}
if
( fi-> flags. pitch) {
if
( f-> pitch == fpDefault && fi-> font. pitch == fpFixed) {
diff += 1.0;
}
else
if
( f-> pitch == fpFixed && fi-> font. pitch == fpVariable) {
diff += 16000.0;
}
else
if
( f-> pitch == fpVariable && fi-> font. pitch == fpFixed) {
diff += 16000.0;
}
}
else
if
( f-> pitch != fpDefault) {
diff += 10000.0;
}
if
( fi-> flags. name && stricmp( lcname, fi-> font. name) == 0) {
diff += 0.0;
name_match = 1;
}
else
if
( fi-> flags. family && stricmp( lcname, fi-> font. family) == 0) {
diff += 1000.0;
}
else
if
( fi-> flags. family && strcasestr( fi-> font. family, lcname)) {
diff += 2000.0;
}
else
if
( !fi-> flags. family) {
diff += 8000.0;
}
else
if
( fi-> flags. name && strcasestr( fi-> font. name, lcname)) {
diff += 7000.0;
}
else
{
diff += 10000.0;
if
( fi-> flags. funky && !enc_match) diff += 10000.0;
}
if
( !name_match && !fi-> flags. known ) diff += 2.0;
if
( fi-> font. vector > fvBitmap) {
if
( fi-> flags. bad_vector) {
diff += 20.0;
}
}
else
{
int
a, b;
switch
( selector) {
case
QUERYDIFF_BY_SIZE:
a = fi-> font. size + .5;
b = f-> size;
break
;
case
QUERYDIFF_BY_HEIGHT:
a = fi-> font. height;
b = f-> height;
break
;
default
:
a = fi-> font. height;
b = fi-> flags. sloppy ? selector : f-> height;
break
;
}
if
( a > b) {
if
( have_vector_fonts) diff += 1000000.0;
diff += 600.0;
diff += 150.0 * (a - b);
}
else
if
( a < b) {
if
( have_vector_fonts) diff += 1000000.0;
diff += 150.0 * ( b - a);
}
}
if
( f-> width) {
if
( fi-> font. vector > fvBitmap ) {
if
( fi-> flags. bad_vector) {
diff += 20.0;
}
}
else
{
if
( fi-> font. width > f-> width) {
if
( have_vector_fonts) diff += 1000000.0;
diff += 200.0;
diff += 50.0 * (fi-> font. width - f-> width);
}
else
if
( fi-> font. width < f-> width) {
if
( have_vector_fonts) diff += 1000000.0;
diff += 50.0 * (f-> width - fi-> font. width);
}
}
}
if
( fi-> flags. xDeviceRes && fi-> flags. yDeviceRes) {
diff += 30.0 * (
int
)
fabs
( 0.5 +
(
float
)( 100.0 * guts. resolution. y / guts. resolution. x) -
(
float
)( 100.0 * fi-> font. yDeviceRes / fi-> font. xDeviceRes));
}
if
( fi-> flags. yDeviceRes) {
diff += 1.0 *
abs
( guts. resolution. y - fi-> font. yDeviceRes);
}
if
( fi-> flags. xDeviceRes) {
diff += 1.0 *
abs
( guts. resolution. x - fi-> font. xDeviceRes);
}
if
( fi-> flags. style && ( f-> style & ~(fsUnderlined|fsOutline|fsStruckOut))== fi-> font. style) {
diff += 0.0;
}
else
if
( !fi-> flags. style) {
diff += 2000.0;
}
else
{
if
(( f-> style & fsThin) != ( fi-> font. style & fsThin))
diff += 1500.0;
if
(( f-> style & fsBold) != ( fi-> font. style & fsBold))
diff += 3000.0;
if
(( f-> style & fsItalic) != ( fi-> font. style & fsItalic))
diff += 3000.0;
}
return
diff;
}
PCachedFont
prima_corefont_match(PFont match, Bool by_size, PCachedFont kf)
{
PFontInfo info = guts. font_info;
int
i, n = guts. n_fonts, index, lastIndex;
int
query_type = by_size ? QUERYDIFF_BY_SIZE : QUERYDIFF_BY_HEIGHT;
double
minDiff;
char
lcname[ 256];
HeightGuessStack hgs;
if
(n == 0)
return
NULL;
if
(
strcmp
( match-> name,
"Default"
) == 0)
strcpy
( match-> name,
"helvetica"
);
if
( by_size) {
Fdebug(
"font reqS:%g(h=%d)x%d.%s.%s %s"
, match-> size, match-> height, match->width, _F_DEBUG_STYLE(match-> style), _F_DEBUG_PITCH(match-> pitch), match-> name, match-> encoding);
}
else
{
Fdebug(
"font reqH:%d(s=%g)x%d.%s.%s %s"
, match-> height, match-> size, match->width, _F_DEBUG_STYLE(match-> style), _F_DEBUG_PITCH(match-> pitch), match-> name, match-> encoding);
}
if
( !hash_fetch( encodings, match-> encoding,
strlen
( match-> encoding)))
match-> encoding[0] = 0;
if
( !by_size)
prima_font_init_try_height( &hgs, match-> height, match-> height);
str_lwr( lcname, match-> name);
AGAIN:
index = lastIndex = -1;
minDiff = INT_MAX;
for
( i = 0; i < n; i++) {
double
diff;
if
( info[i]. flags. disabled)
continue
;
diff = query_diff( info + i, match, lcname, query_type);
if
( diff < minDiff) {
lastIndex = index;
index = i;
minDiff = diff;
}
if
( diff < 1)
break
;
}
if
(index < 0) {
Fdebug(
"font: no more fonts to match, bail out"
);
return
NULL;
}
i = index;
Fdebug(
"font: #%d (diff=%g): %s"
, i, minDiff, info[i].xname);
Fdebug(
"font: pick:%d(%g)x%d.%s.%s %s/%s %s.%s"
, info[i].font. height, info[i].font. size, info[i].font. width, _F_DEBUG_STYLE(info[i].font. style), _F_DEBUG_PITCH(info[i].font. pitch), info[i].font. name, info[i].font. encoding, info[i].flags.sloppy?
"sloppy"
:
""
, info[i].vecname?
"vector"
:
""
);
if
( !by_size && info[ i]. flags. sloppy && !info[ i]. vecname) {
if
(!detail_font_info( info + i, match, NULL, by_size)) {
Fdebug(
"font: bad one, try again"
);
goto
AGAIN;
}
if
( minDiff < query_diff( info + i, match, lcname, by_size)) {
int
h = prima_font_try_height( &hgs, info[i]. font. height);
if
( h > 0) {
Fdebug(
"font: try again with new height %d"
, h);
query_type = h;
goto
AGAIN;
}
}
}
if
(!detail_font_info( info + index, match, kf, by_size)) {
Fdebug(
"font: bad match, try again"
);
goto
AGAIN;
}
return
kf;
}
static
PRotatedFont
find_or_allocate_rotated_font_entry( PCachedFont f, Fixed *fm, Fixed *im, Matrix cm)
{
int
i, rbox_x[4], rbox_y[4], box_x[4], box_y[4], box[4];
XGCValues xgv;
PRotatedFont r = NULL, *pr = &f-> rotated;
while
(*pr) {
if
(
memcmp
( (*pr)-> matrix, fm,
sizeof
(Fixed)*4) == 0) {
r = *pr;
break
;
}
pr = ( PRotatedFont *) &((*pr)-> next);
}
r = *pr =
malloc
(
sizeof
( RotatedFont));
if
( !r) {
warn(
"Not enough memory"
);
return
NULL;
}
bzero( r,
sizeof
( RotatedFont));
r-> first1 = f-> fs-> min_byte1;
r-> first2 = f-> fs-> min_char_or_byte2;
i = ( f-> fs-> max_char_or_byte2 > 255 ? 255 : f-> fs-> max_char_or_byte2)
- r-> first2 + 1;
if
( i < 0) i = 0;
r-> width = i;
r-> height = f-> fs-> max_byte1 - f-> fs-> min_byte1 + 1;
r-> length = r-> width * r-> height;
r-> defaultChar1 = f-> fs-> default_char >> 8;
r-> defaultChar2 = f-> fs-> default_char & 0xff;
if
( r-> defaultChar1 < r-> first1 || r-> defaultChar1 >= r-> first1 + r-> height ||
r-> defaultChar2 < r-> first2 || r-> defaultChar2 >= r-> first2 + r-> width)
r-> defaultChar1 = r-> defaultChar2 = -1;
if
( r-> length > 0) {
if
( !( r-> map =
malloc
( r-> length *
sizeof
(
void
*)))) {
*pr = NULL;
free
( r);
warn(
"Not enough memory"
);
return
NULL;
}
bzero( r-> map, r-> length *
sizeof
(
void
*));
}
memcpy
(r->matrix, fm,
sizeof
(Fixed) * 4);
memcpy
(r->inverse, im,
sizeof
(Fixed) * 4);
box_x[0] = box_y[0] = box_x[1] = box_y[3] = 0;
r-> orgBox. x = box_x[2] = box_x[3] = f-> fs-> max_bounds. width;
r-> orgBox. y = box_y[1] = box_y[2] = f-> fs-> max_bounds. ascent + f-> fs-> max_bounds. descent;
for
( i = 0; i < 4; i++) {
rbox_x[i] = box_x[i];
rbox_y[i] = box_y[i];
prima_matrix_apply_int_to_int(cm, &rbox_x[i], &rbox_y[i]);
box[i] = 0;
}
for
( i = 0; i < 4; i++) {
if
( rbox_x[i] < box[0]) box[0] = rbox_x[i];
if
( rbox_y[i] < box[1]) box[1] = rbox_y[i];
if
( rbox_x[i] > box[2]) box[2] = rbox_x[i];
if
( rbox_y[i] > box[3]) box[3] = rbox_y[i];
}
r-> dimension. x = box[2] - box[0] + 1;
r-> dimension. y = box[3] - box[1] + 1;
r-> shift. x = box[0];
r-> shift. y = box[1];
r-> lineSize = (( r-> orgBox. x + 31) / 32) * 4;
r-> arenaSize = r-> lineSize * r-> orgBox. y;
if
( !( r-> arena_bits =
malloc
( r-> arenaSize)))
goto
FAILED;
r-> arena = XCreatePixmap( DISP, guts. root, r-> orgBox.x, r-> orgBox. y, 1);
if
( !r-> arena) {
free
( r-> arena_bits);
FAILED:
*pr = NULL;
free
( r-> map);
free
( r);
warn(
"Cannot create pixmap"
);
return
NULL;
}
XCHECKPOINT;
r-> arena_gc = XCreateGC( DISP, r-> arena, 0, &xgv);
XCHECKPOINT;
XSetFont( DISP, r-> arena_gc, f-> id);
XCHECKPOINT;
XSetBackground( DISP, r-> arena_gc, 0);
return
r;
}
static
PRotatedFont
find_or_allocate_straight_font_entry( PCachedFont f)
{
Matrix cm;
Fixed mx[4];
prima_matrix_set_identity(cm);
mx[0].l = mx[3].l = 1 * UINT16_PRECISION;
mx[1].l = mx[2].l = 0;
return
find_or_allocate_rotated_font_entry(f, mx, mx, cm);
}
static
PrimaXImage *
render_bitmap_glyph( PCachedFont f, PRotatedFont r, XChar2b index, Bool wide)
{
XCharStruct *cs;
XImage *ximage;
PrimaXImage *px;
cs = f-> fs-> per_char ?
f-> fs-> per_char +
( index. byte1 - f-> fs-> min_byte1) * r-> width +
index. byte2 - f-> fs-> min_char_or_byte2 :
&(f-> fs-> min_bounds);
XSetForeground( DISP, r-> arena_gc, 0);
XFillRectangle( DISP, r-> arena, r-> arena_gc, 0, 0, r-> orgBox. x, r-> orgBox .y);
XSetForeground( DISP, r-> arena_gc, 1);
if
(wide)
XDrawString16( DISP, r-> arena, r-> arena_gc,
( cs-> lbearing < 0) ? -cs-> lbearing : 0,
r-> orgBox. y - f-> fs-> max_bounds. descent,
&index, 1);
else
XDrawString( DISP, r-> arena, r-> arena_gc,
( cs-> lbearing < 0) ? -cs-> lbearing : 0,
r-> orgBox. y - f-> fs-> max_bounds. descent,
(
const
char
*)&index. byte2, 1);
XCHECKPOINT;
if
( !( ximage = XGetImage( DISP, r-> arena, 0, 0, r-> orgBox. x, r-> orgBox. y, 1, XYPixmap))) {
warn(
"Can't get image %dx%d"
, r-> orgBox.x, r-> orgBox.y);
return
NULL;
}
XCHECKPOINT;
prima_copy_1bit_ximage( r-> arena_bits, ximage,
false
);
XDestroyImage( ximage);
if
( !( px = prima_prepare_ximage( r-> dimension. x, r-> dimension. y, CACHE_BITMAP))) {
warn(
"Can't get image %dx%d"
, r-> orgBox.x, r-> orgBox.y);
return
NULL;
}
return
px;
}
static
Bool
validate_xchar2b( PRotatedFont r, XChar2b *index)
{
if
(
index-> byte1 < r-> first1 || index-> byte1 >= r-> first1 + r-> height ||
index-> byte2 < r-> first2 || index-> byte2 >= r-> first2 + r-> width
) {
if
( r-> defaultChar1 < 0 || r-> defaultChar2 < 0)
return
false
;
index-> byte1 = ( unsigned
char
) r-> defaultChar1;
index-> byte2 = ( unsigned
char
) r-> defaultChar2;
}
return
true
;
}
Bool
prima_update_rotated_fonts( PCachedFont f,
const
char
* text,
int
len, Bool wide, NPoint trig_cache, Matrix matrix, PRotatedFont * result,
Bool * ok_to_not_rotate)
{
Fixed fm[4], im[4];
Matrix cm;
PRotatedFont r;
int
i;
{
int
i;
Matrix m1, inv;
double
d, ad, bc;
prima_matrix_set_identity(m1);
m1[0] = trig_cache.y;
m1[1] = trig_cache.x;
m1[2] = -trig_cache.x;
m1[3] = trig_cache.y;
if
( prima_matrix_is_identity(matrix)) {
COPY_MATRIX(m1, cm);
}
else
{
Matrix m2;
COPY_MATRIX_WITHOUT_TRANSLATION( matrix, m2 );
prima_matrix_multiply( m1, m2, cm);
}
ad = cm[0] * cm[3];
bc = cm[1] * cm[2];
if
( ad - bc == 0.0 )
return
false
;
d = ad - bc;
for
( i = 0; i < 4; i++) {
double
m =
floor
( cm[i] * 1000.0 ) / 1000.0;
if
( m < -8192.0 ) m = -8192.0;
if
( m > 8192.0 ) m = 8192.0;
fm[i].l = m * UINT16_PRECISION;
inv[i] = cm[i] / d;
if
( inv[i] < -8192.0 ) inv[i] = -8192.0;
if
( inv[i] > 8192.0 ) inv[i] = 8192.0;
}
im[0].l = inv[3] * UINT16_PRECISION;
im[1].l = -inv[1] * UINT16_PRECISION;
im[2].l = -inv[2] * UINT16_PRECISION;
im[3].l = inv[0] * UINT16_PRECISION;
}
if
( prima_matrix_is_translated_only(matrix) && trig_cache.x == 0.0 && trig_cache.y == 1.0) {
if
( ok_to_not_rotate) *ok_to_not_rotate =
true
;
return
false
;
}
if
( ok_to_not_rotate) *ok_to_not_rotate =
false
;
if
( !( r = find_or_allocate_rotated_font_entry(f, fm, im, cm)))
return
false
;
for
( i = 0; i < len; i++) {
XChar2b index;
PrimaXImage * px;
Byte * ndata;
unsigned
int
glyph_id;
index. byte1 = wide ? (( XChar2b*) text + i)-> byte1 : 0;
index. byte2 = wide ? (( XChar2b*) text + i)-> byte2 : *((unsigned
char
*)text + i);
if
( !validate_xchar2b( r, &index))
continue
;
if
( r-> map[( index. byte1 - r-> first1) * r-> width + index. byte2 - r-> first2])
continue
;
if
( !( px = render_bitmap_glyph( f, r, index, wide )))
return
false
;
ndata = ( Byte*) px-> data_alias;
bzero( ndata, px-> bytes_per_line_alias * r-> dimension. y);
{
int
x, y, fast = r-> orgBox. y * r-> orgBox. x > 600;
Fixed lx, ly;
Byte * dst = ndata + px-> bytes_per_line_alias * ( r-> dimension. y - 1);
for
( y = r-> shift. y; y < r-> shift. y + r-> dimension. y; y++) {
lx. l = r-> shift. x * r-> inverse[0]. l + y * r-> inverse[2]. l;
ly. l = r-> shift. x * r-> inverse[1]. l + y * r-> inverse[3]. l + UINT16_PRECISION/2;
if
( fast) {
lx. l += UINT16_PRECISION/2;
for
( x = 0; x < r-> dimension. x; x++) {
if
(
ly. i. i >= 0 && ly. i. i < r-> orgBox. y &&
lx. i. i >= 0 && lx. i. i < r-> orgBox. x
) {
Byte * src = r-> arena_bits + r-> lineSize * ly. i. i;
if
( src[ lx . i. i >> 3] & ( 1 << ( 7 - ( lx . i. i & 7))))
dst[ x >> 3] |= 1 << ( 7 - ( x & 7));
}
lx. l += r-> inverse[0]. l;
ly. l += r-> inverse[1]. l;
}
}
else
{
for
( x = 0; x < r-> dimension. x; x++) {
if
( ly. i. i >= 0 && ly. i. i < r-> orgBox. y && lx. i. i >= 0 && lx. i. i < r-> orgBox. x) {
long
pv;
Byte * src = r-> arena_bits + r-> lineSize * ly. i. i;
pv = 0;
if
( src[ lx . i. i >> 3] & ( 1 << ( 7 - ( lx . i. i & 7))))
pv += ( UINT16_PRECISION - lx. i. f);
if
( lx. i. i < r-> orgBox. x - 1) {
if
( src[( lx. i. i + 1) >> 3] & ( 1 << ( 7 - (( lx. i. i + 1) & 7))))
pv += lx. i. f;
}
else
{
if
( src[ lx . i. i >> 3] & ( 1 << ( 7 - ( lx . i. i & 7))))
pv += UINT16_PRECISION/2;
}
if
( pv >= UINT16_PRECISION/2)
dst[ x >> 3] |= 1 << ( 7 - ( x & 7));
}
lx. l += r-> inverse[0]. l;
ly. l += r-> inverse[1]. l;
}
}
dst -= px-> bytes_per_line_alias;
}
}
if
( guts. bit_order != MSBFirst)
prima_mirror_bytes( ndata, r-> dimension.y * px-> bytes_per_line_alias);
glyph_id = ( index. byte1 - r-> first1) * r-> width + index. byte2 - r-> first2;
r-> map[glyph_id] = px;
guts.rotated_font_cache_size += r-> arenaSize;
if
( guts.rotated_font_cache_size > MAX_ROTATED_FONT_CACHE_SIZE )
cleanup_rotated_font_cache( r, glyph_id );
}
if
( result)
*result = r;
return
true
;
}
PrimaXImage*
prepare_straight_glyph(PCachedFont f, PRotatedFont r, XChar2b index)
{
PrimaXImage *px;
Byte *src, *dst;
unsigned
int
i, src_stride, dst_stride, ylim, glyph_id;
if
( !validate_xchar2b( r, &index))
return
NULL;
if
(( px = r-> map[( index. byte1 - r-> first1) * r-> width + index. byte2 - r-> first2]) != NULL)
return
px;
if
( !( px = render_bitmap_glyph( f, r, index,
true
)))
return
NULL;
src_stride = r->lineSize;
dst_stride = px->bytes_per_line_alias;
src = r->arena_bits + src_stride * (r->orgBox.y - 1);
dst = (Byte*) px-> data_alias;
ylim = r->shift.y + r->dimension.y;
for
( i = r->shift.y; i < ylim; i++, src -= src_stride, dst += dst_stride) {
memcpy
(dst, src, dst_stride);
if
( guts. bit_order != MSBFirst)
prima_mirror_bytes( dst, dst_stride);
}
glyph_id = ( index. byte1 - r-> first1) * r-> width + index. byte2 - r-> first2;
r-> map[glyph_id] = px;
guts.rotated_font_cache_size += r-> arenaSize;
if
( guts.rotated_font_cache_size > MAX_ROTATED_FONT_CACHE_SIZE )
cleanup_rotated_font_cache( r, glyph_id );
return
px;
}
XCharStruct *
prima_char_struct( XFontStruct * xs,
void
* c, Bool wide)
{
XCharStruct * cs;
int
d = xs-> max_char_or_byte2 - xs-> min_char_or_byte2 + 1;
int
index1 = wide ? (( XChar2b*) c)-> byte1 : 0;
int
index2 = wide ? (( XChar2b*) c)-> byte2 : *((
char
*)c);
int
default_char1 = wide ? ( xs-> default_char >> 8) : 0;
int
default_char2 = xs-> default_char & 0xff;
if
( default_char1 < xs-> min_byte1 ||
default_char1 > xs-> max_byte1)
default_char1 = xs-> min_byte1;
if
( default_char2 < xs-> min_char_or_byte2 ||
default_char2 > xs-> max_char_or_byte2)
default_char2 = xs-> min_char_or_byte2;
if
( index1 < xs-> min_byte1 ||
index1 > xs-> max_byte1) {
index1 = default_char1;
index2 = default_char2;
}
if
( index2 < xs-> min_char_or_byte2 ||
index2 > xs-> max_char_or_byte2) {
index1 = default_char1;
index2 = default_char2;
}
cs = xs-> per_char ?
xs-> per_char +
( index1 - xs-> min_byte1) * d +
( index2 - xs-> min_char_or_byte2) :
&(xs-> min_bounds);
return
cs;
}
Point
prima_corefont_get_text_overhangs( XFontStruct *fs,
const
char
*text,
int
len,
int
flags)
{
Point ret;
if
( len > 0) {
XCharStruct * cs;
cs = prima_char_struct( fs, (
void
*) text, flags & (toUTF8 | toGlyphs));
ret. x = ( cs-> lbearing < 0) ? - cs-> lbearing : 0;
text += (len - 1) * ((flags & (toUTF8 | toGlyphs)) ? 2 : 1);
cs = prima_char_struct( fs, (
void
*) text, flags & (toUTF8 | toGlyphs));
ret. y = (( cs-> width - cs-> rbearing) < 0) ? cs-> rbearing - cs-> width : 0;
}
else
ret. x = ret. y = 0;
return
ret;
}
Byte*
prima_corefont_get_glyph_bitmap( Handle self, uint16_t index, Bool mono, PPoint offset, PPoint size,
int
*advance)
{
DEFXX;
PRotatedFont r;
XCharStruct *cs;
XChar2b ch;
Bool straight =
false
;
int
i, px;
Fixed rx, ry;
Byte *ret, *src, *dst;
int
src_stride, dst_stride, bytes;
XImage *xi;
ch.byte1 = index >> 8;
ch.byte2 = index & 0xff;
if
( !prima_update_rotated_fonts( XX-> font,
(
const
char
*)&ch, 1,
true
,
CDrawable( self)-> trig_cache(self),
MY_MATRIX,
&r, &straight
)) {
if
( !straight )
return
NULL;
if
( !( r = find_or_allocate_straight_font_entry(XX->font)))
return
NULL;
if
( !prepare_straight_glyph(XX->font, r, ch))
return
NULL;
}
if
( !validate_xchar2b( r, &ch))
return
NULL;
cs = XX-> font-> fs-> per_char ?
XX-> font-> fs-> per_char +
( ch. byte1 - XX-> font-> fs-> min_byte1) * r-> width +
ch. byte2 - XX-> font-> fs-> min_char_or_byte2 :
&(XX-> font-> fs-> min_bounds);
if
( r-> map[(ch. byte1 - r-> first1) * r-> width + ch. byte2 - r-> first2] == NULL)
return
NULL;
xi = r-> map[(ch. byte1 - r-> first1) * r-> width + ch. byte2 - r-> first2]-> image;
px = ( cs-> lbearing < 0) ? -cs-> lbearing : 0;
rx. l = px * r-> matrix[0]. l + UINT16_PRECISION/2;
ry. l = px * r-> matrix[1]. l + UINT16_PRECISION/2;
size-> x = r-> dimension. x;
size-> y = r-> dimension. y;
offset-> x = rx. i. i - r-> shift. x;
offset-> y = ry. i. i - r-> shift. y - XX-> font-> font. descent;
if
(advance) *advance = cs-> width;
src_stride = xi-> bytes_per_line;
dst_stride = (( size->x * (mono ? 1 : 8) + 31) / 32) * 4;
bytes = ( src_stride < dst_stride ) ? src_stride : dst_stride;
for
(
i = size-> y - 1, src = ((Byte*) xi-> data) + (size-> y - 1) * src_stride;
i >= 0;
i++, src -= src_stride
) {
register
unsigned
int
j = bytes;
register
Byte *r = src;
while
( j--)
if
( *(r++) != 0 )
goto
STOP1;
size->y--;
offset->y++;
}
STOP1:
for
( i = 0, src = (Byte*) xi->data; i < size->y; i++, src += src_stride) {
register
unsigned
int
j = bytes;
register
Byte *r = src;
while
( j--)
if
( *(r++) != 0 )
goto
STOP2;
size->y--;
}
STOP2:
if
( size->y <= 0 ) {
size->x = size->y = offset->x = offset->y = 0;
return
malloc
(0);
}
if
( !( ret =
malloc
(dst_stride * size->y)))
return
NULL;
dst = ret + dst_stride * (size->y - 1);
for
(
i = 0;
i < size->y;
i++, src += src_stride, dst -= dst_stride
) {
if
( guts.bit_order == MSBFirst) {
if
( mono )
memcpy
(dst, src, bytes);
else
bc_mono_byte( src, dst, size->x);
}
else
{
register
Byte *d = dst, *s = src, *mirrored_bits = prima_mirror_bits();
if
( mono ) {
register
unsigned
int
j = bytes;
while
(j--) *d++ = mirrored_bits[*s++];
}
else
{
Byte buf[128], *s = src, *d = dst;
unsigned
int
j = bytes;
while
( j > 0 ) {
register
Byte *b = buf;
register
unsigned
int
n = (j >
sizeof
(buf)) ?
sizeof
(buf) : j;
unsigned
int
m = n;
while
(n--) *b++ = mirrored_bits[*s++];
bc_mono_byte( b, d, m );
d += m;
j -= m;
}
}
}
}
return
ret;
}
static
PFont
spec_fonts(
int
*retCount)
{
int
i, count = guts. n_fonts;
PFontInfo info = guts. font_info;
PFont fmtx = NULL;
List list;
PHash hash = NULL;
list_create( &list, 256, 256);
*retCount = 0;
if
( !( hash = hash_create())) {
list_destroy( &list);
return
NULL;
}
for
( i = 0; i < count; i++) {
int
len;
PFont fm;
if
( info[ i]. flags. disabled)
continue
;
len =
strlen
( info[ i].font.name);
fm = hash_fetch( hash, info[ i].font.name, len);
if
( fm) {
char
** enc = (
char
**) fm-> encoding;
unsigned
char
* shift = (unsigned
char
*)enc +
sizeof
(
char
*) - 1;
if
( *shift + 2 < 256 /
sizeof
(
char
*)) {
int
j, exists = 0;
for
( j = 1; j <= *shift; j++) {
if
(
strcmp
( enc[j], info[i].xname + info[i].info_offset) == 0) {
exists = 1;
break
;
}
}
if
( exists)
continue
;
*(enc + ++(*shift)) = info[i].xname + info[i].info_offset;
}
continue
;
}
if
( !( fm = ( PFont)
malloc
(
sizeof
( Font)))) {
if
( hash) hash_destroy( hash,
false
);
list_delete_all( &list,
true
);
list_destroy( &list);
return
NULL;
}
*fm = info[i]. font;
{
char
** enc = (
char
**) fm-> encoding;
unsigned
char
* shift = (unsigned
char
*)enc +
sizeof
(
char
*) - 1;
memset
( fm-> encoding, 0, 256);
*(enc + ++(*shift)) = info[i].xname + info[i].info_offset;
hash_store( hash, info[ i].font.name,
strlen
( info[ i].font.name), fm);
}
list_add( &list, ( Handle) fm);
}
if
( hash) hash_destroy( hash,
false
);
if
( list. count == 0)
goto
Nothing;
fmtx = ( PFont)
malloc
( list. count *
sizeof
( Font));
if
( !fmtx) {
list_delete_all( &list,
true
);
list_destroy( &list);
return
NULL;
}
*retCount = list. count;
for
( i = 0; i < list. count; i++)
memcpy
( fmtx + i, (
void
*) list. items[ i],
sizeof
( Font));
list_delete_all( &list,
true
);
Nothing:
list_destroy( &list);
return
fmtx;
}
PFont
prima_corefont_fonts( Handle self,
const
char
*facename,
const
char
* encoding,
int
*retCount)
{
int
i, count = guts. n_fonts;
PFontInfo info = guts. font_info;
PFontInfo * table;
int
n_table;
PFont fmtx;
if
( !facename && !encoding)
return
spec_fonts( retCount);
*retCount = 0;
n_table = 0;
table =
malloc
( count *
sizeof
( PFontInfo));
if
( !table && count > 0)
return
NULL;
if
( facename == NULL) {
PHash hash = hash_create();
for
( i = 0; i < count; i++) {
int
len;
if
( info[ i]. flags. disabled)
continue
;
len =
strlen
( info[ i].font.name);
if
( hash_fetch( hash, info[ i].font.name, len) ||
strcmp
( info[ i].xname + info[ i].info_offset, encoding) != 0)
continue
;
hash_store( hash, info[ i].font.name, len, (
void
*)1);
table[ n_table++] = info + i;
}
hash_destroy( hash,
false
);
*retCount = n_table;
}
else
{
for
( i = 0; i < count; i++) {
if
( info[ i]. flags. disabled)
continue
;
if
(
( stricmp( info[ i].font.name, facename) == 0) &&
(
!encoding ||
(
strcmp
( info[ i].xname + info[ i].info_offset, encoding) == 0)
)
) {
table[ n_table++] = info + i;
}
}
*retCount = n_table;
}
fmtx =
malloc
( n_table *
sizeof
( Font));
bzero( fmtx, n_table *
sizeof
( Font));
if
( !fmtx && n_table > 0) {
*retCount = 0;
free
( table);
return
NULL;
}
for
( i = 0; i < n_table; i++) {
fmtx[i] = table[i]-> font;
}
free
( table);
return
fmtx;
}