summaryrefslogtreecommitdiffstats
path: root/utils/xftwrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/xftwrap.c')
-rw-r--r--utils/xftwrap.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/utils/xftwrap.c b/utils/xftwrap.c
new file mode 100644
index 0000000..e880407
--- /dev/null
+++ b/utils/xftwrap.c
@@ -0,0 +1,206 @@
+/* xftwrap.c --- XftDrawStringUtf8 with multi-line strings.
+ * xscreensaver, Copyright © 2021 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "utils.h"
+#include "xft.h"
+#include "xftwrap.h"
+
+#undef MAX
+#undef MIN
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+
+#ifdef DEBUG
+static void
+LOG(const char *ss, const char *s, int n)
+{
+ int i;
+ fprintf(stderr,"####%s [", ss);
+ for (i = 0; i < n; i++) fprintf(stderr, "%c", s[i]);
+ fprintf(stderr,"]\n");
+}
+#else
+# define LOG(ss,s,n) /**/
+#endif
+
+
+/* Returns a new string word-wrapped to fit in the width in pixels.
+ */
+char *
+xft_word_wrap (Display *dpy, XftFont *font, const char *str, int pixels)
+{
+ const char *in = str;
+ char *ret = (char *) malloc (strlen(in) + 2);
+ char *out = ret;
+ const char *line_out = out;
+ char *word_out = 0;
+ while (1)
+ {
+ if (*in == ' ' || *in == '\t' ||
+ *in == '\r' || *in == '\n' ||
+ *in == 0)
+ {
+ Bool done = (*in == 0); /* To wrap the *last* word. */
+ XGlyphInfo overall;
+ Bool nl = (*in == '\r' || *in == '\n');
+
+ if (nl) in++;
+ while (*in == ' ' || *in == '\t') in++;
+ in--;
+
+ XftTextExtentsUtf8 (dpy, font,
+ (FcChar8 *) line_out,
+ out - line_out,
+ &overall);
+ if (overall.width - overall.x >= pixels &&
+ word_out)
+ {
+ word_out[0] = '\n';
+ line_out = word_out + 1;
+ word_out = 0;
+ if (done) break;
+ *out++ = *in;
+ }
+ else
+ {
+ if (done) break;
+ word_out = out;
+ *out++ = *in;
+ if (nl)
+ {
+ line_out = out + 1;
+ word_out = 0;
+ }
+ }
+
+ if (done) break;
+ }
+ else
+ {
+ *out++ = *in;
+ }
+ in++;
+ }
+
+ *out = 0;
+
+ return ret;
+}
+
+
+/* Like XftTextExtentsUtf8, but handles multi-line strings.
+ XGlyphInfo will contain the bounding box that encloses all of the text.
+ Return value is the number of lines in the text, >= 1.
+ */
+int
+XftTextExtentsUtf8_multi (Display *dpy, XftFont *font,
+ const FcChar8 *str, int len, XGlyphInfo *overall)
+{
+ int i, start = 0;
+ int lines = 0;
+ int line_y = 0;
+ for (i = 0; i <= len; i++)
+ {
+ if (i == len || str[i] == '\r' || str[i] == '\n')
+ {
+ XGlyphInfo gi;
+ XftTextExtentsUtf8 (dpy, font,
+ str + start,
+ i - start,
+ &gi);
+ if (lines == 0)
+ *overall = gi;
+ else
+ {
+ /* Find the union of the two bounding boxes, placed at their
+ respective origins. */
+ int ox1, oy1, ox2, oy2; /* bbox of 'overall' */
+ int nx1, ny1, nx2, ny2; /* bbox of 'gi' */
+ int ux1, uy1, ux2, uy2; /* union */
+
+ ox1 = overall->x;
+ oy1 = overall->y;
+ ox2 = ox1 + overall->width;
+ oy2 = oy1 + overall->height;
+
+ line_y += font->ascent + font->descent; /* advance origin */
+
+ nx1 = gi.x;
+ ny1 = gi.y + line_y;
+ nx2 = nx1 + gi.width;
+ ny2 = ny1 + gi.height + line_y;
+
+ ux1 = MIN (ox1, nx1); /* upper left */
+ uy1 = MIN (oy1, ny1);
+ ux2 = MAX (ox2, nx2); /* bottom right */
+ uy2 = MAX (oy2, ny2);
+
+ overall->x = ux1;
+ overall->y = uy1;
+ overall->width = ux2 - ux1;
+ overall->height = uy2 - uy1;
+ }
+ lines++;
+ start = i+1;
+ }
+ }
+
+ return lines;
+}
+
+
+/* Like XftDrawStringUtf8, but handles multi-line strings.
+ Alignment is 1, 0 or -1 for left, center, right.
+ */
+void
+XftDrawStringUtf8_multi (XftDraw *xftdraw, const XftColor *color,
+ XftFont *font, int x, int y, const FcChar8 *str,
+ int len,
+ int alignment)
+{
+ Display *dpy = XftDrawDisplay (xftdraw);
+ int i, start = 0;
+ int lines = 0;
+ XGlyphInfo overall;
+ if (len == 0) return;
+
+ XftTextExtentsUtf8_multi (dpy, font, str, len, &overall);
+
+ for (i = 0; i <= len; i++)
+ {
+ if (i == len || str[i] == '\r' || str[i] == '\n')
+ {
+ XGlyphInfo gi;
+ int x2 = x;
+ XftTextExtentsUtf8 (dpy, font, str + start, i - start, &gi);
+ switch (alignment) {
+ case 1: break;
+ case 0: x2 += (overall.width - gi.width) / 2; break;
+ case -1: x2 += (overall.width - gi.width); break;
+ default: abort(); break;
+ }
+
+ XftDrawStringUtf8 (xftdraw, color, font, x2, y,
+ str + start,
+ i - start);
+ y += font->ascent + font->descent;
+ lines++;
+ start = i+1;
+ }
+ }
+}
+