#include #include "wconfig.h" #include "WINGsP.h" #include #include #include #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; }