diff --git a/README.md b/README.md index 1c5cc166..1840a0b0 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ This README is being written.
*Note that today's entry may be updated later today.* +* **25 May 2016** + * uiDrawTextLayout attributes are now specified in units of *graphemes* on all platforms. This means characters as seen from a user's perspective, not Unicode codepoints or UTF-8 bytes. So a long string of combining marker codepoints after one codepoint would still count as one grapheme. + * **24 May 2016** * As promised, `uiCombobox` is now split into `uiCombobox` for non-editable comboboxes and `uiEditableCombobox` for editable comboboxes. Mind the function changes as well :) * There is a new function `uiMainStep()`, which runs one iteration of the main loop. It takes a single boolean argument, indicating whether to wait for an event to occur or not. It returns true if an event was processed (or if no event is available if you don't want to wait) and false if the event loop was told to stop (for instance, `uiQuit()` was called). diff --git a/unix/drawtext.c b/unix/drawtext.c index 192e1327..a9b856fe 100644 --- a/unix/drawtext.c +++ b/unix/drawtext.c @@ -173,7 +173,7 @@ void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metri // note: PangoCairoLayouts are tied to a given cairo_t, so we can't store one in this device-independent structure struct uiDrawTextLayout { char *s; - PangoGlyphString *glyphString; + ptrdiff_t *graphemes; PangoFont *defaultFont; double width; PangoAttrList *attrs; @@ -187,7 +187,7 @@ uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultF layout = uiNew(uiDrawTextLayout); layout->s = g_strdup(text); context = mkGenericPangoCairoContext(); - layout->glyphString = graphemes(layout->s, context); + layout->graphemes = graphemes(layout->s, context); g_object_unref(context); layout->defaultFont = defaultFont->f; g_object_ref(layout->defaultFont); // retain a copy @@ -200,7 +200,7 @@ void uiDrawFreeTextLayout(uiDrawTextLayout *layout) { pango_attr_list_unref(layout->attrs); g_object_unref(layout->defaultFont); - pango_glyph_string_free(layout->glyphString); + uiFree(layout->graphemes); g_free(layout->s); uiFree(layout); } @@ -267,8 +267,8 @@ void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout) static void addAttr(uiDrawTextLayout *layout, PangoAttribute *attr, intmax_t startChar, intmax_t endChar) { - attr->start_index = layout->glyphString->log_clusters[startChar]; - attr->end_index = layout->glyphString->log_clusters[endChar]; + attr->start_index = layout->graphemes[startChar]; + attr->end_index = layout->graphemes[endChar]; pango_attr_list_insert(layout->attrs, attr); // pango_attr_list_insert() takes attr; we don't free it } diff --git a/unix/graphemes.c b/unix/graphemes.c index a4cf0cc5..6d101a92 100644 --- a/unix/graphemes.c +++ b/unix/graphemes.c @@ -1,41 +1,31 @@ // 25 may 2016 #include "uipriv_unix.H" -// TODO this breaks for non-BMP characters? - -struct gparam { - const char *text; - PangoGlyphString *glyphString; -}; - -static void runItem(gpointer it, gpointer data) +ptrdiff_t *graphemes(const char *text, PangoContext *context) { - PangoItem *item = (PangoItem *) it; - struct gparam *gparam = (struct gparam *) data; - - pango_shape(gparam->text + item->offset, - item->length, - &(item->analysis), - gparam->glyphString); - pango_item_free(item); -} - -PangoGlyphString *graphemes(const char *text, PangoContext *context) -{ - size_t len; - GList *list; - struct gparam gparam; + size_t len, lenchars; + PangoLogAttr *logattrs; + ptrdiff_t *out; + ptrdiff_t *op; + size_t i; len = strlen(text); - list = pango_itemize(context, - text, 0, len, - NULL, NULL); + lenchars = g_utf8_strlen(text, -1); + logattrs = (PangoLogAttr *) uiAlloc((lenchars + 1) * sizeof (PangoLogAttr), "PangoLogAttr[]"); + pango_get_log_attrs(text, len, + -1, NULL, + logattrs, lenchars + 1); - gparam.text = text; - gparam.glyphString = pango_glyph_string_new(); + // should be more than enough + out = (ptrdiff_t *) uiAlloc((lenchars + 2) * sizeof (ptrdiff_t), "ptrdiff_t[]"); + op = out; + for (i = 0; i < lenchars; i++) + if (logattrs[i].is_cursor_position != 0) + // TODO optimize this + *op++ = g_utf8_offset_to_pointer(text, i) - text; + // and do the last one + *op++ = len; - g_list_foreach(list, runItem, &gparam); - - g_list_free(list); - return gparam.glyphString; + uiFree(logattrs); + return out; } diff --git a/unix/uipriv_unix.h b/unix/uipriv_unix.h index f85874be..cd89e869 100644 --- a/unix/uipriv_unix.h +++ b/unix/uipriv_unix.h @@ -49,4 +49,4 @@ extern uiDrawTextFont *mkTextFont(PangoFont *f, gboolean add); extern PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc); // graphemes.c -extern PangoGlyphString *graphemes(const char *text, PangoContext *context); +extern ptrdiff_t *graphemes(const char *text, PangoContext *context);