[vte/wip/mosaic: 2/8] draw: Implement separated mosaic graphics



commit 9b52b277ac9b43553c4f8f867e08ce76925a8710
Author: Christian Persch <chpe src gnome org>
Date:   Thu Nov 14 23:09:22 2019 +0100

    draw: Implement separated mosaic graphics
    
    https://gitlab.gnome.org/GNOME/vte/issues/189

 src/attr.hh       |  10 ++++-
 src/cell.hh       |   3 +-
 src/parser-sgr.hh |   2 +
 src/vte.cc        |   4 +-
 src/vtedraw.cc    | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/vtedraw.hh    |   2 +
 src/vteseq.cc     |   6 +++
 7 files changed, 128 insertions(+), 8 deletions(-)
---
diff --git a/src/attr.hh b/src/attr.hh
index 20d82bf1..646d86d9 100644
--- a/src/attr.hh
+++ b/src/attr.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2018 Christian Persch
+ * Copyright © 2018, 2019 Christian Persch
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -85,6 +85,11 @@
 #define VTE_ATTR_INVISIBLE_MASK        (VTE_ATTR_MASK(VTE_ATTR_INVISIBLE_SHIFT, VTE_ATTR_INVISIBLE_BITS))
 #define VTE_ATTR_INVISIBLE             (1U << VTE_ATTR_INVISIBLE_SHIFT)
 
+#define VTE_ATTR_SEPARATED_MOSAIC_SHIFT (VTE_ATTR_INVISIBLE_SHIFT + VTE_ATTR_INVISIBLE_BITS)
+#define VTE_ATTR_SEPARATED_MOSAIC_BITS  (1)
+#define VTE_ATTR_SEPARATED_MOSAIC_MASK  (VTE_ATTR_MASK(VTE_ATTR_SEPARATED_MOSAIC_SHIFT, 
VTE_ATTR_SEPARATED_MOSAIC_BITS))
+#define VTE_ATTR_SEPARATED_MOSAIC       (1U << VTE_ATTR_SEPARATED_MOSAIC_SHIFT)
+
 /* Used internally only */
 #define VTE_ATTR_BOXED_SHIFT           (31)
 #define VTE_ATTR_BOXED_BITS            (1)
@@ -99,7 +104,8 @@
                                         VTE_ATTR_OVERLINE_MASK | \
                                         VTE_ATTR_REVERSE_MASK | \
                                         VTE_ATTR_BLINK_MASK | \
-                                        VTE_ATTR_INVISIBLE_MASK)
+                                        VTE_ATTR_INVISIBLE_MASK | \
+                                        VTE_ATTR_SEPARATED_MOSAIC_MASK)
 
 #define VTE_ATTR_NONE                  (0U)
 #define VTE_ATTR_DEFAULT               (VTE_ATTR_COLUMNS(1))
diff --git a/src/cell.hh b/src/cell.hh
index 06960862..a1c6cebb 100644
--- a/src/cell.hh
+++ b/src/cell.hh
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002 Red Hat, Inc.
- * Copyright © 2018 Christian Persch
+ * Copyright © 2018, 2019 Christian Persch
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -146,6 +146,7 @@ typedef struct _VTE_GNUC_PACKED VteCellAttr {
         CELL_ATTR_BOOL(blink, BLINK)
         CELL_ATTR_BOOL(dim, DIM)
         CELL_ATTR_BOOL(invisible, INVISIBLE)
+        CELL_ATTR_BOOL(separated_mosaic, SEPARATED_MOSAIC)
         /* ATTR_BOOL(boxed, BOXED) */
 } VteCellAttr;
 static_assert(sizeof (VteCellAttr) == 16, "VteCellAttr has wrong size");
diff --git a/src/parser-sgr.hh b/src/parser-sgr.hh
index c12e5ade..afa15266 100644
--- a/src/parser-sgr.hh
+++ b/src/parser-sgr.hh
@@ -40,6 +40,7 @@ SGR(SET, BACK_LEGACY_END, 47)
 SGR(SET, BACK_SPEC, 48)
 SGR(SET, OVERLINE, 53)
 SGR(SET, DECO_SPEC, 58)
+SGR(SET, SEPARATED_MOSAIC, 71)
 SGR(SET, FORE_LEGACY_BRIGHT_START, 90)
 SGR(SET, FORE_LEGACY_BRIGHT_END, 97)
 SGR(SET, BACK_LEGACY_BRIGHT_START, 100)
@@ -56,6 +57,7 @@ SGR(RESET, FORE, 39)
 SGR(RESET, BACK, 49)
 SGR(RESET, OVERLINE, 55)
 SGR(RESET, DECO, 59)
+SGR(RESET, SEPARATED_MOSAIC, 72)
 
 NGR(SET, FONT_FIRST, 10)
 NGR(SET, FONT_LAST, 19)
diff --git a/src/vte.cc b/src/vte.cc
index 54e8a587..2dbf0f7f 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -8558,6 +8558,7 @@ Terminal::draw_cells(struct _vte_draw_text_request *items,
 
         _vte_draw_text(m_draw,
                        items, n,
+                       attr,
                        &fg, VTE_DRAW_OPAQUE,
                        _vte_draw_get_style(attr & VTE_ATTR_BOLD,
                                            attr & VTE_ATTR_ITALIC));
@@ -9064,7 +9065,8 @@ Terminal::draw_rows(VteScreen *screen_,
                                                        VTE_ATTR_STRIKETHROUGH_MASK |
                                                        VTE_ATTR_OVERLINE_MASK |
                                                        VTE_ATTR_BLINK_MASK |
-                                                       VTE_ATTR_INVISIBLE_MASK)) ||  // FIXME or just simply 
"attr != nattr"?
+                                                       VTE_ATTR_INVISIBLE_MASK |
+                                                       VTE_ATTR_SEPARATED_MOSAIC_MASK)) ||  // FIXME or just 
simply "attr != nattr"?
                                     fore != nfore ||
                                     back != nback ||
                                     deco != ndeco ||
diff --git a/src/vtedraw.cc b/src/vtedraw.cc
index f60ee412..ea9bdf84 100644
--- a/src/vtedraw.cc
+++ b/src/vtedraw.cc
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2003,2008 Red Hat, Inc.
+ * Copyright © 2019 Christian Persch
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,6 +27,7 @@
 #include <glib.h>
 #include <gtk/gtk.h>
 
+#include "attr.hh"
 #include "bidi.hh"
 #include "vtedraw.hh"
 #include "vtedefines.hh"
@@ -1031,12 +1033,91 @@ _vte_draw_get_char_edges (struct _vte_draw *draw, vteunistr c, int columns, guin
                 *right = l + w;
 }
 
+#ifdef WITH_UNICODE_NEXT
+
+static bool
+_vte_draw_is_separable_mosaic(vteunistr c)
+{
+        // FIXMEchpe check from T.101 which characters should be separable
+        return ((c >= 0x1fb00 && c <= 0x1fb9f)||
+                (c >= 0x25e2 && c <= 0x25e5) ||
+                (c >= 0x2580 && c <= 0x259f));
+}
+
+/* Create separated mosaic pattern.
+ * Transparent pixels will not be drawn; opaque pixels will draw that part of the
+ * mosaic onto the target surface.
+ */
+static cairo_pattern_t*
+create_mosaic_separation_pattern(int width,
+                                 int height,
+                                 int line_thickness)
+{
+        auto surface = cairo_image_surface_create(CAIRO_FORMAT_A1, width, height);
+        // or CAIRO_FORMAT_A8, whichever is better/faster?
+
+        auto cr = cairo_create(surface);
+
+        /* ITU-T T.101 Annex C, C.2.1.2, and Annex D, D.5.4, show and describe how the
+         * separated mosaics should be drawn.
+         */
+
+        /* FIXMEchpe: Check that this fulfills [T.101 Appendix IV]:
+         * "All separated and contiguous mosaics shall be uniquely presented for character
+         * field sizes greater than or equal to dx = 6/256, dy = 8/256 [see D.8.3.3, item 7)]."
+         */
+
+        /* First, fill completely with transparent pixels */
+        cairo_set_source_rgba(cr, 0., 0., 0., 0.);
+        cairo_rectangle(cr, 0, 0, width, height);
+        cairo_fill(cr);
+
+        /* Now, fill the reduced blocks with opaque pixels */
+
+        auto const pel = line_thickness; /* see T.101 D.5.3.2.2.6 for definition of 'logical pel' */
+
+        if (width > 2 * pel && height > 3 * pel) {
+
+                auto const width_half = width / 2;
+                auto const height_thirds = height / 3;
+                auto const remaining_height = height - 3 * height_thirds;
+
+                int const y[4] = { 0, height_thirds, 2 * height_thirds + (remaining_height ? 1 : 0), height 
};
+                int const x[3] = { 0, width_half, width };
+                // FIXMEchpe: or use 2 * width_half instead of width, so that for width odd,
+                // the extra row of pixels is unlit, and the lit blocks have equal width?
+
+                cairo_set_source_rgba(cr, 0., 0., 0., 1.);
+                for (auto yi = 0; yi < 3; ++yi) {
+                        for (auto xi = 0; xi < 2; xi++) {
+                                cairo_rectangle(cr, x[xi] + pel, y[yi], x[xi+1] - x[xi] - pel, y[yi+1] - 
y[yi] - pel);
+                                cairo_fill(cr);
+                        }
+                }
+        }
+
+        cairo_destroy(cr);
+
+        auto pattern = cairo_pattern_create_for_surface(surface);
+        cairo_surface_destroy(surface);
+
+        cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+        cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
+
+        return pattern;
+}
+
+#endif /* WITH_UNICODE_NEXT */
+
 #include "box_drawing.h"
 
 /* Draw the graphic representation of a line-drawing or special graphics
  * character. */
 static void
-_vte_draw_terminal_draw_graphic(struct _vte_draw *draw, vteunistr c, vte::color::rgb const* fg,
+_vte_draw_terminal_draw_graphic(struct _vte_draw *draw,
+                                vteunistr c,
+                                uint32_t attr,
+                                vte::color::rgb const* fg,
                                 gint x, gint y,
                                 gint font_width, gint columns, gint font_height)
 {
@@ -1094,6 +1175,12 @@ _vte_draw_terminal_draw_graphic(struct _vte_draw *draw, vteunistr c, vte::color:
         xright = x + width;
         ybottom = y + height;
 
+#ifdef WITH_UNICODE_NEXT
+        auto const separated = vte_attr_get_bool(attr, VTE_ATTR_SEPARATED_MOSAIC_SHIFT) 
&&_vte_draw_is_separable_mosaic(c);
+        if (separated)
+                cairo_push_group(cr);
+#endif
+
         switch (c) {
 
         /* Box Drawing */
@@ -2006,12 +2093,22 @@ _vte_draw_terminal_draw_graphic(struct _vte_draw *draw, vteunistr c, vte::color:
 #undef RECTANGLE
 #undef POLYGON
 
+#ifdef WITH_UNICODE_NEXT
+        if (separated) {
+                cairo_pop_group_to_source(cr);
+                auto pattern = create_mosaic_separation_pattern(width, height, light_line_width);
+                cairo_mask(cr, pattern);
+                cairo_pattern_destroy(pattern);
+        }
+#endif
+
         cairo_restore(cr);
 }
 
 static void
 _vte_draw_text_internal (struct _vte_draw *draw,
                         struct _vte_draw_text_request *requests, gsize n_requests,
+                         uint32_t attr,
                         vte::color::rgb const* color, double alpha, guint style)
 {
        gsize i;
@@ -2034,7 +2131,9 @@ _vte_draw_text_internal (struct _vte_draw *draw,
                 }
 
                 if (_vte_draw_unichar_is_local_graphic(c)) {
-                        _vte_draw_terminal_draw_graphic(draw, c, color,
+                        _vte_draw_terminal_draw_graphic(draw, c,
+                                                        attr,
+                                                        color,
                                                         requests[i].x, requests[i].y,
                                                         font->width, requests[i].columns, font->height);
                         continue;
@@ -2096,6 +2195,7 @@ _vte_draw_text_internal (struct _vte_draw *draw,
 void
 _vte_draw_text (struct _vte_draw *draw,
               struct _vte_draw_text_request *requests, gsize n_requests,
+                uint32_t attr,
               vte::color::rgb const* color, double alpha, guint style)
 {
         g_assert(draw->cr);
@@ -2115,7 +2215,7 @@ _vte_draw_text (struct _vte_draw *draw,
                g_free (str);
        }
 
-       _vte_draw_text_internal (draw, requests, n_requests, color, alpha, style);
+       _vte_draw_text_internal (draw, requests, n_requests, attr, color, alpha, style);
 }
 
 /* The following two functions are unused since commit 154abade902850afb44115cccf8fcac51fc082f0,
@@ -2139,6 +2239,7 @@ _vte_draw_has_char (struct _vte_draw *draw, vteunistr c, guint style)
 gboolean
 _vte_draw_char (struct _vte_draw *draw,
               struct _vte_draw_text_request *request,
+                uint32_t attr,
               vte::color::rgb const* color, double alpha, guint style)
 {
        gboolean has_char;
@@ -2153,7 +2254,7 @@ _vte_draw_char (struct _vte_draw *draw,
 
        has_char =_vte_draw_has_char (draw, request->c, style);
        if (has_char)
-               _vte_draw_text (draw, request, 1, color, alpha, style);
+               _vte_draw_text (draw, request, 1, attr, color, alpha, style);
 
        return has_char;
 }
diff --git a/src/vtedraw.hh b/src/vtedraw.hh
index 0797b564..dc64b84d 100644
--- a/src/vtedraw.hh
+++ b/src/vtedraw.hh
@@ -79,9 +79,11 @@ void _vte_draw_get_char_edges (struct _vte_draw *draw, vteunistr c, int columns,
 
 void _vte_draw_text(struct _vte_draw *draw,
                    struct _vte_draw_text_request *requests, gsize n_requests,
+                    uint32_t attr,
                    vte::color::rgb const* color, double alpha, guint style);
 gboolean _vte_draw_char(struct _vte_draw *draw,
                        struct _vte_draw_text_request *request,
+                        uint32_t attr,
                        vte::color::rgb const* color, double alpha, guint style);
 gboolean _vte_draw_has_char(struct _vte_draw *draw, vteunistr c, guint style);
 
diff --git a/src/vteseq.cc b/src/vteseq.cc
index 10cbfdf8..d5562436 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -7257,6 +7257,12 @@ Terminal::SGR(vte::parser::Sequence const& seq)
                                 m_defaults.attr.set_deco(deco);
                         break;
                 }
+                case VTE_SGR_SET_SEPARATED_MOSAIC:
+                        m_defaults.attr.set_separated_mosaic(true);
+                        break;
+                case VTE_SGR_RESET_SEPARATED_MOSAIC:
+                        m_defaults.attr.set_separated_mosaic(false);
+                        break;
                 case VTE_SGR_RESET_DECO:
                         /* default decoration color, that is, same as the cell's foreground */
                         m_defaults.attr.set_deco(VTE_DEFAULT_FG);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]