X-Git-Url: https://develop.uap-core.de/gitweb/uwplayer.git/blobdiff_plain/1e4681c09375d0a2aece4ebdcd4a3d5badee5fc6..5b86e784ed60d047c8d34dec15b35f62cfb1f8f8:/application/nfont.c diff --git a/application/nfont.c b/application/nfont.c new file mode 100644 index 0000000..bf677a0 --- /dev/null +++ b/application/nfont.c @@ -0,0 +1,215 @@ +/* + * 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); + } +} \ No newline at end of file