/* * Copyright 2022 Olaf Wintermann * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "nfont.h" /* font list functions */ NFont *FontCreate(Display *dp, FcPattern *pattern) { if(!pattern) { return NULL; } FcResult result; pattern = FcPatternDuplicate(pattern); FcPattern *match = XftFontMatch(dp, DefaultScreen(dp), pattern, &result); double sz = 0; result = FcPatternGetDouble (pattern, FC_SIZE, 0, &sz); if(result != FcResultMatch) { FcPatternGetDouble (match, FC_SIZE, 0, &sz); } XftFont *defaultFont = XftFontOpenPattern(dp, match); if(!defaultFont) { FcPatternDestroy(match); return NULL; } NFont *font = malloc(sizeof(NFont)); font->display = dp; font->pattern = pattern; font->fail = NULL; font->size = sz; font->ref = 1; NFontList *list = malloc(sizeof(NFontList)); list->font = defaultFont; list->next = NULL; font->fonts = list; return font; } NFont *FontFromName(Display *dp, const char *name) { FcPattern *pattern = FcNameParse((FcChar8*)name); if(!pattern) { return NULL; } NFont *font = FontCreate(dp, pattern); FcPatternDestroy(pattern); return font; } XftFont *FontListAddFontForChar(NFont *f, FcChar32 c) { /* charset for char c */ FcCharSet *charset = FcCharSetCreate(); FcValue value; value.type = FcTypeCharSet; value.u.c = charset; FcCharSetAddChar(charset, c); if(!FcCharSetHasChar(charset, c)) { FcCharSetDestroy(charset); return f->fonts->font; } /* font lookup based on the NFont pattern */ FcPattern *pattern = FcPatternDuplicate(f->pattern); FcPatternAdd(pattern, FC_CHARSET, value, 0); FcResult result; FcPattern *match = XftFontMatch ( f->display, DefaultScreen(f->display), pattern, &result); if(!match) { FcPatternDestroy(pattern); FontAddFail(f, charset); return f->fonts->font; } XftFont *newFont = XftFontOpenPattern(f->display, match); if(!newFont || !FcCharSetHasChar(newFont->charset, c)) { FcPatternDestroy(pattern); FcPatternDestroy(match); if(newFont) { XftFontClose(f->display, newFont); } FontAddFail(f, charset); return f->fonts->font; } FcCharSetDestroy(charset); NFontList *newElm = malloc(sizeof(NFontList)); newElm->font = newFont; newElm->next = NULL; NFontList *elm = f->fonts; NFontList *last = NULL; while(elm) { last = elm; elm = elm->next; } last->next = newElm; return newFont; } XftFont *FindFont(NFont *f, FcChar32 c) { if(c < 128) { return f->fonts->font; } /* make sure the char is not in the fail list, because we don't * want to retry font lookups */ NCharSetList *fail = f->fail; while(fail) { if(FcCharSetHasChar(fail->charset, c)) { return f->fonts->font; } fail = fail->next; } /* find a font that has this char */ NFontList *elm = f->fonts; while(elm) { if(FcCharSetHasChar(elm->font->charset, c)) { return elm->font; } elm = elm->next; } /* open a new font for this char */ return FontListAddFontForChar(f, c); } XftFont *FontDefault(NFont *f) { return f->fonts->font; } void FontAddFail(NFont *f, FcCharSet *c) { NCharSetList *elm = f->fail; NCharSetList *last = elm; while(elm) { last = elm; elm = elm->next; } NCharSetList *newElm = malloc(sizeof(NCharSetList)); newElm->charset = c; newElm->next = NULL; if(last) { last->next = newElm; } else { f->fail = newElm; } } void FontDestroy(NFont *f) { NCharSetList *c = f->fail; NCharSetList *nc; while(c) { FcCharSetDestroy(c->charset); nc = c->next; free(c); c = nc; } NFontList *l = f->fonts; NFontList *nl; while(l) { XftFontClose(f->display, l->font); nl = l->next; free(nl); l = nl; } FcPatternDestroy(f->pattern); free(f); } NFont *FontRef(NFont *font) { font->ref++; return font; } void FontUnref(NFont *font) { if(--font->ref == 0) { FontDestroy(font); } }