376 lines
8.7 KiB
C
376 lines
8.7 KiB
C
|
|
#include <stdlib.h>
|
|
|
|
#include "wconfig.h"
|
|
|
|
#include "WINGsP.h"
|
|
|
|
#include <wraster.h>
|
|
#include <assert.h>
|
|
|
|
#include <fontconfig/fontconfig.h>
|
|
|
|
#define DEFAULT_FONT "sans serif:pixelsize=12"
|
|
|
|
#define DEFAULT_SIZE WINGsConfiguration.defaultFontSize
|
|
|
|
/*
|
|
* Parse an X-style XLFD ("-foundry-family-...-pixelsize-...-...") into
|
|
* a fontconfig pattern. We used to call XftXlfdParse here; that pulls
|
|
* libXft and therefore libX11 into the shared font dispatcher, which
|
|
* is unacceptable for Wayland-only builds.
|
|
*
|
|
* The legacy XLFD format is fixed: 14 dash-separated fields.
|
|
* -foundry-family-weight-slant-setwidth-addstyle-pixelsize-pointsize
|
|
* -resolutionx-resolutiony-spacing-averagewidth-charsetregistry
|
|
* -charsetencoding
|
|
*
|
|
* We extract the family (field 2), pixelsize (field 7), weight (field 3),
|
|
* and slant (field 4). Anything we don't understand is dropped. This
|
|
* matches the practical use of XLFD names in legacy WINGs config files.
|
|
*/
|
|
FcPattern *W_ParseXLFDToFcPattern(const char *xlfd)
|
|
{
|
|
FcPattern *pattern = FcPatternCreate();
|
|
const char *p = xlfd;
|
|
int field = 0;
|
|
char buf[128];
|
|
size_t buflen;
|
|
|
|
if (!pattern) return NULL;
|
|
|
|
if (*p == '-') p++;
|
|
while (*p) {
|
|
buflen = 0;
|
|
while (*p && *p != '-' && buflen + 1 < sizeof(buf))
|
|
buf[buflen++] = *p++;
|
|
buf[buflen] = '\0';
|
|
if (*p == '-') p++;
|
|
|
|
switch (field) {
|
|
case 1: /* family */
|
|
if (buf[0] && buf[0] != '*')
|
|
FcPatternAddString(pattern, FC_FAMILY, (FcChar8 *)buf);
|
|
break;
|
|
case 2: /* weight */
|
|
if (strcasecmp(buf, "bold") == 0)
|
|
FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *)"bold");
|
|
break;
|
|
case 3: /* slant */
|
|
if (buf[0] == 'i' || buf[0] == 'I')
|
|
FcPatternAddString(pattern, FC_SLANT, (FcChar8 *)"italic");
|
|
else if (buf[0] == 'o' || buf[0] == 'O')
|
|
FcPatternAddString(pattern, FC_SLANT, (FcChar8 *)"oblique");
|
|
break;
|
|
case 6: /* pixelsize */
|
|
if (buf[0] && buf[0] != '*') {
|
|
int size = atoi(buf);
|
|
if (size > 0)
|
|
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)size);
|
|
}
|
|
break;
|
|
}
|
|
field++;
|
|
}
|
|
|
|
if (field < 2) {
|
|
/* Wasn't really an XLFD — bail. */
|
|
FcPatternDestroy(pattern);
|
|
return FcNameParse((FcChar8 *)DEFAULT_FONT);
|
|
}
|
|
return pattern;
|
|
}
|
|
|
|
static FcPattern *xlfdToFcPattern(const char *xlfd)
|
|
{
|
|
return W_ParseXLFDToFcPattern(xlfd);
|
|
}
|
|
|
|
static char *xlfdToFcName(const char *xlfd)
|
|
{
|
|
FcPattern *pattern;
|
|
char *fname;
|
|
|
|
pattern = xlfdToFcPattern(xlfd);
|
|
fname = (char *)FcNameUnparse(pattern);
|
|
FcPatternDestroy(pattern);
|
|
|
|
return fname;
|
|
}
|
|
|
|
static Bool hasProperty(FcPattern * pattern, const char *property)
|
|
{
|
|
FcValue val;
|
|
|
|
if (FcPatternGet(pattern, property, 0, &val) == FcResultMatch) {
|
|
return True;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
static Bool hasPropertyWithStringValue(FcPattern * pattern, const char *object, const char *value)
|
|
{
|
|
FcChar8 *str;
|
|
int id;
|
|
|
|
if (!value || value[0] == 0)
|
|
return True;
|
|
|
|
id = 0;
|
|
while (FcPatternGetString(pattern, object, id, &str) == FcResultMatch) {
|
|
if (strcasecmp(value, (char *)str) == 0) {
|
|
return True;
|
|
}
|
|
id++;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
static char *makeFontOfSize(const char *font, int size, const char *fallback)
|
|
{
|
|
FcPattern *pattern;
|
|
char *result;
|
|
|
|
if (font[0] == '-') {
|
|
pattern = xlfdToFcPattern(font);
|
|
} else {
|
|
pattern = FcNameParse((const FcChar8 *) font);
|
|
}
|
|
|
|
if (size > 0) {
|
|
FcPatternDel(pattern, FC_PIXEL_SIZE);
|
|
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)size);
|
|
} else if (size == 0 && !hasProperty(pattern, "size") && !hasProperty(pattern, FC_PIXEL_SIZE)) {
|
|
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)DEFAULT_SIZE);
|
|
}
|
|
|
|
if (fallback && !hasPropertyWithStringValue(pattern, FC_FAMILY, fallback)) {
|
|
FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) fallback);
|
|
}
|
|
|
|
result = (char *)FcNameUnparse(pattern);
|
|
FcPatternDestroy(pattern);
|
|
|
|
return result;
|
|
}
|
|
|
|
WMFont *WMCreateFont(WMScreen * scrPtr, const char *fontName)
|
|
{
|
|
WMFont *font;
|
|
char *fname;
|
|
int height = 0, y = 0;
|
|
|
|
if (fontName[0] == '-') {
|
|
fname = xlfdToFcName(fontName);
|
|
} else {
|
|
fname = wstrdup(fontName);
|
|
}
|
|
|
|
if (!WINGsConfiguration.antialiasedText && !strstr(fname, ":antialias=")) {
|
|
fname = wstrappend(fname, ":antialias=false");
|
|
}
|
|
|
|
font = WMHashGet(scrPtr->fontCache, fname);
|
|
if (font) {
|
|
WMRetainFont(font);
|
|
wfree(fname);
|
|
return font;
|
|
}
|
|
|
|
font = wmalloc(sizeof(WMFont));
|
|
|
|
font->screen = scrPtr;
|
|
font->backend = scrPtr->fontBackend;
|
|
|
|
font->handle = scrPtr->fontBackend->font_open(scrPtr->fontBackendCtx, fname, &height, &y);
|
|
if (!font->handle) {
|
|
wfree(font);
|
|
wfree(fname);
|
|
return NULL;
|
|
}
|
|
|
|
font->height = (short)height;
|
|
font->y = (short)y;
|
|
font->refCount = 1;
|
|
font->name = fname;
|
|
|
|
assert(WMHashInsert(scrPtr->fontCache, font->name, font) == NULL);
|
|
|
|
return font;
|
|
}
|
|
|
|
WMFont *WMRetainFont(WMFont * font)
|
|
{
|
|
wassertrv(font != NULL, NULL);
|
|
|
|
font->refCount++;
|
|
|
|
return font;
|
|
}
|
|
|
|
void WMReleaseFont(WMFont * font)
|
|
{
|
|
wassertr(font != NULL);
|
|
|
|
font->refCount--;
|
|
if (font->refCount < 1) {
|
|
font->backend->font_close(font->screen->fontBackendCtx, font->handle);
|
|
if (font->name) {
|
|
WMHashRemove(font->screen->fontCache, font->name);
|
|
wfree(font->name);
|
|
}
|
|
wfree(font);
|
|
}
|
|
}
|
|
|
|
Bool WMIsAntialiasingEnabled(WMScreen * scrPtr)
|
|
{
|
|
return scrPtr->antialiasedText;
|
|
}
|
|
|
|
unsigned int WMFontHeight(WMFont * font)
|
|
{
|
|
wassertrv(font != NULL, 0);
|
|
|
|
return font->height;
|
|
}
|
|
|
|
char *WMGetFontName(WMFont * font)
|
|
{
|
|
wassertrv(font != NULL, NULL);
|
|
|
|
return font->name;
|
|
}
|
|
|
|
void WMGetScaleBaseFromSystemFont(WMScreen *scrPtr, int *alphabetWidth, int *fontHeight)
|
|
{
|
|
WMFont *font;
|
|
|
|
font = WMDefaultSystemFont(scrPtr);
|
|
*alphabetWidth = WMWidthOfString(font, "abcdefghijklmnopqrstuvwxyz", 26);
|
|
*fontHeight = WMFontHeight(font);
|
|
WMReleaseFont(font);
|
|
}
|
|
|
|
WMFont *WMDefaultSystemFont(WMScreen * scrPtr)
|
|
{
|
|
return WMRetainFont(scrPtr->normalFont);
|
|
}
|
|
|
|
WMFont *WMDefaultBoldSystemFont(WMScreen * scrPtr)
|
|
{
|
|
return WMRetainFont(scrPtr->boldFont);
|
|
}
|
|
|
|
WMFont *WMSystemFontOfSize(WMScreen * scrPtr, int size)
|
|
{
|
|
WMFont *font;
|
|
char *fontSpec;
|
|
|
|
fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, NULL);
|
|
|
|
font = WMCreateFont(scrPtr, fontSpec);
|
|
|
|
if (!font) {
|
|
wwarning(_("could not load font: %s."), fontSpec);
|
|
}
|
|
|
|
wfree(fontSpec);
|
|
|
|
return font;
|
|
}
|
|
|
|
WMFont *WMBoldSystemFontOfSize(WMScreen * scrPtr, int size)
|
|
{
|
|
WMFont *font;
|
|
char *fontSpec;
|
|
|
|
fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, NULL);
|
|
|
|
font = WMCreateFont(scrPtr, fontSpec);
|
|
|
|
if (!font) {
|
|
wwarning(_("could not load font: %s."), fontSpec);
|
|
}
|
|
|
|
wfree(fontSpec);
|
|
|
|
return font;
|
|
}
|
|
|
|
int WMWidthOfString(WMFont * font, const char *text, int length)
|
|
{
|
|
wassertrv(font != NULL && text != NULL, 0);
|
|
|
|
return font->backend->text_width(font->handle, text, length);
|
|
}
|
|
|
|
void WMDrawString(WMScreen *scr, WMDrawable d, WMColor *color, WMFont *font,
|
|
int x, int y, const char *text, int length)
|
|
{
|
|
wassertr(font != NULL);
|
|
|
|
font->backend->draw_string(scr->fontBackendCtx, font->handle, d,
|
|
x, y,
|
|
color->color.red, color->color.green,
|
|
color->color.blue, color->alpha,
|
|
W_PIXEL(color),
|
|
text, length);
|
|
}
|
|
|
|
void WMDrawImageString(WMScreen *scr, WMDrawable d, WMColor *color, WMColor *background,
|
|
WMFont *font, int x, int y, const char *text, int length)
|
|
{
|
|
wassertr(font != NULL);
|
|
|
|
font->backend->draw_image_string(scr->fontBackendCtx, font->handle, d,
|
|
x, y,
|
|
color->color.red, color->color.green,
|
|
color->color.blue, color->alpha, W_PIXEL(color),
|
|
background->color.red, background->color.green,
|
|
background->color.blue, background->alpha, W_PIXEL(background),
|
|
WMWidthOfString(font, text, length), font->height,
|
|
text, length);
|
|
}
|
|
|
|
WMFont *WMCopyFontWithStyle(WMScreen * scrPtr, WMFont * font, WMFontStyle style)
|
|
{
|
|
FcPattern *pattern;
|
|
WMFont *copy;
|
|
char *name;
|
|
|
|
if (!font)
|
|
return NULL;
|
|
|
|
pattern = FcNameParse((FcChar8 *) WMGetFontName(font));
|
|
switch (style) {
|
|
case WFSNormal:
|
|
FcPatternDel(pattern, FC_WEIGHT);
|
|
FcPatternDel(pattern, FC_SLANT);
|
|
break;
|
|
case WFSBold:
|
|
FcPatternDel(pattern, FC_WEIGHT);
|
|
FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *) "bold");
|
|
break;
|
|
case WFSItalic:
|
|
FcPatternDel(pattern, FC_SLANT);
|
|
FcPatternAddString(pattern, FC_SLANT, (FcChar8 *) "italic");
|
|
break;
|
|
case WFSBoldItalic:
|
|
FcPatternDel(pattern, FC_WEIGHT);
|
|
FcPatternDel(pattern, FC_SLANT);
|
|
FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *) "bold");
|
|
FcPatternAddString(pattern, FC_SLANT, (FcChar8 *) "italic");
|
|
break;
|
|
}
|
|
|
|
name = (char *)FcNameUnparse(pattern);
|
|
copy = WMCreateFont(scrPtr, name);
|
|
FcPatternDestroy(pattern);
|
|
wfree(name);
|
|
|
|
return copy;
|
|
}
|