scroll.c (4616B)
1 int 2 utf8nextchar(const char *str, int len, int i, int inc) 3 { 4 int n; 5 6 for (n = i + inc; n + inc >= 0 && n + inc <= len 7 && (str[n] & 0xc0) == 0x80; n += inc) 8 ; 9 return n; 10 } 11 12 int 13 drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align) 14 { 15 int ty; 16 unsigned int ew; 17 XftDraw *d = NULL; 18 Fnt *usedfont, *curfont, *nextfont; 19 size_t len; 20 int utf8strlen, utf8charlen, render = x || y || w || h; 21 long utf8codepoint = 0; 22 const char *utf8str; 23 FcCharSet *fccharset; 24 FcPattern *fcpattern; 25 FcPattern *match; 26 XftResult result; 27 int charexists = 0; 28 int utf8err = 0; 29 int i, n; 30 31 if (!drw || (render && !drw->scheme) || !text || !drw->fonts || textlen <= 0 32 || (align != AlignL && align != AlignR)) 33 return 0; 34 35 if (!render) { 36 w = ~w; 37 } else { 38 XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel); 39 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); 40 #if ALPHA_PATCH 41 d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap); 42 #else 43 d = XftDrawCreate(drw->dpy, drw->drawable, 44 DefaultVisual(drw->dpy, drw->screen), 45 DefaultColormap(drw->dpy, drw->screen)); 46 #endif // ALPHA_PATCH 47 } 48 49 #if BIDI_PATCH 50 apply_fribidi(text); 51 text = fribidi_text; 52 #endif // BIDI_PATCH 53 54 usedfont = drw->fonts; 55 i = align == AlignL ? 0 : textlen; 56 x = align == AlignL ? x : x + w; 57 while (1) { 58 utf8strlen = 0; 59 nextfont = NULL; 60 /* if (align == AlignL) */ 61 utf8str = text + i; 62 63 while ((align == AlignL && i < textlen) || (align == AlignR && i > 0)) { 64 if (align == AlignL) { 65 utf8charlen = utf8decode(text + i, &utf8codepoint, &utf8err); 66 if (!utf8charlen) { 67 textlen = i; 68 break; 69 } 70 } else { 71 n = utf8nextchar(text, textlen, i, -1); 72 utf8charlen = utf8decode(text + n, &utf8codepoint, &utf8err); 73 if (!utf8charlen) { 74 textlen -= i; 75 text += i; 76 i = 0; 77 break; 78 } 79 } 80 for (curfont = drw->fonts; curfont; curfont = curfont->next) { 81 charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); 82 if (charexists) { 83 if (curfont == usedfont) { 84 utf8strlen += utf8charlen; 85 i += align == AlignL ? utf8charlen : -utf8charlen; 86 } else { 87 nextfont = curfont; 88 } 89 break; 90 } 91 } 92 93 if (!charexists || nextfont) 94 break; 95 else 96 charexists = 0; 97 } 98 99 if (align == AlignR) 100 utf8str = text + i; 101 102 if (utf8strlen) { 103 drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); 104 /* shorten text if necessary */ 105 if (align == AlignL) { 106 for (len = utf8strlen; len && ew > w; ) { 107 len = utf8nextchar(utf8str, len, len, -1); 108 drw_font_getexts(usedfont, utf8str, len, &ew, NULL); 109 } 110 } else { 111 for (len = utf8strlen; len && ew > w; ) { 112 n = utf8nextchar(utf8str, len, 0, +1); 113 utf8str += n; 114 len -= n; 115 drw_font_getexts(usedfont, utf8str, len, &ew, NULL); 116 } 117 } 118 119 if (len) { 120 if (render) { 121 ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; 122 XftDrawStringUtf8(d, &drw->scheme[ColFg], 123 usedfont->xfont, align == AlignL ? x : x - ew, ty, (XftChar8 *)utf8str, len); 124 } 125 x += align == AlignL ? ew : -ew; 126 w -= ew; 127 } 128 if (len < utf8strlen) 129 break; 130 } 131 132 if ((align == AlignR && i <= 0) || (align == AlignL && i >= textlen)) { 133 break; 134 } else if (nextfont) { 135 charexists = 0; 136 usedfont = nextfont; 137 } else { 138 /* Regardless of whether or not a fallback font is found, the 139 * character must be drawn. */ 140 charexists = 1; 141 142 fccharset = FcCharSetCreate(); 143 FcCharSetAddChar(fccharset, utf8codepoint); 144 145 if (!drw->fonts->pattern) { 146 /* Refer to the comment in xfont_create for more information. */ 147 die("the first font in the cache must be loaded from a font string."); 148 } 149 150 fcpattern = FcPatternDuplicate(drw->fonts->pattern); 151 FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); 152 FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); 153 154 FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); 155 FcDefaultSubstitute(fcpattern); 156 match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); 157 158 FcCharSetDestroy(fccharset); 159 FcPatternDestroy(fcpattern); 160 161 if (match) { 162 usedfont = xfont_create(drw, NULL, match); 163 if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { 164 for (curfont = drw->fonts; curfont->next; curfont = curfont->next) 165 ; /* NOP */ 166 curfont->next = usedfont; 167 } else { 168 xfont_free(usedfont); 169 usedfont = drw->fonts; 170 } 171 } 172 } 173 } 174 if (d) 175 XftDrawDestroy(d); 176 177 return x; 178 }