[vte] draw: Move custom drawing code into its own class



commit 507ac2860eb575520ba3628457342161556e4a8b
Author: Christian Persch <chpe src gnome org>
Date:   Mon Jun 1 22:48:43 2020 +0200

    draw: Move custom drawing code into its own class

 src/meson.build |    2 +
 src/minifont.cc | 1113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/minifont.hh |   61 +++
 src/vtedraw.cc  | 1100 +-----------------------------------------------------
 src/vtedraw.hh  |    8 +
 5 files changed, 1188 insertions(+), 1096 deletions(-)
---
diff --git a/src/meson.build b/src/meson.build
index 6cd1b67a..e778cc49 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -109,6 +109,8 @@ libvte_common_sources = debug_sources + glib_glue_sources + libc_glue_sources +
   'gobject-glue.hh',
   'keymap.cc',
   'keymap.h',
+  'minifont.cc',
+  'minifont.hh',
   'missing.cc',
   'missing.hh',
   'reaper.cc',
diff --git a/src/minifont.cc b/src/minifont.cc
new file mode 100644
index 00000000..889fd261
--- /dev/null
+++ b/src/minifont.cc
@@ -0,0 +1,1113 @@
+/*
+ * Copyright (C) 2003,2008 Red Hat, Inc.
+ * Copyright © 2019, 2020 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <cmath>
+
+#include <cairo.h>
+
+#include "minifont.hh"
+#include "vtedraw.hh"
+
+/* pixman data must have stride 0 mod 4 */
+static unsigned char const hatching_pattern_lr_data[16] = {
+        0xff, 0x00, 0x00, 0x00,
+        0x00, 0xff, 0x00, 0x00,
+        0x00, 0x00, 0xff, 0x00,
+        0x00, 0x00, 0x00, 0xff,
+};
+static unsigned char const hatching_pattern_rl_data[16] = {
+        0x00, 0x00, 0x00, 0xff,
+        0x00, 0x00, 0xff, 0x00,
+        0x00, 0xff, 0x00, 0x00,
+        0xff, 0x00, 0x00, 0x00,
+};
+static unsigned char const checkerboard_pattern_data[16] = {
+        0xff, 0xff, 0x00, 0x00,
+        0xff, 0xff, 0x00, 0x00,
+        0x00, 0x00, 0xff, 0xff,
+        0x00, 0x00, 0xff, 0xff,
+};
+static unsigned char const checkerboard_reverse_pattern_data[16] = {
+        0x00, 0x00, 0xff, 0xff,
+        0x00, 0x00, 0xff, 0xff,
+        0xff, 0xff, 0x00, 0x00,
+        0xff, 0xff, 0x00, 0x00,
+};
+
+#define DEFINE_STATIC_PATTERN_FUNC(name,data,width,height,stride) \
+static cairo_pattern_t* \
+name(void) \
+{ \
+        static cairo_pattern_t* pattern = nullptr; \
+\
+        if (pattern == nullptr) { \
+                auto surface = cairo_image_surface_create_for_data(const_cast<unsigned char*>(data), \
+                                                                   CAIRO_FORMAT_A8, \
+                                                                   width, \
+                                                                   height, \
+                                                                   stride); \
+                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; \
+}
+
+DEFINE_STATIC_PATTERN_FUNC(create_hatching_pattern_lr, hatching_pattern_lr_data, 4, 4, 4)
+DEFINE_STATIC_PATTERN_FUNC(create_hatching_pattern_rl, hatching_pattern_rl_data, 4, 4, 4)
+DEFINE_STATIC_PATTERN_FUNC(create_checkerboard_pattern, checkerboard_pattern_data, 4, 4, 4)
+DEFINE_STATIC_PATTERN_FUNC(create_checkerboard_reverse_pattern, checkerboard_reverse_pattern_data, 4, 4, 4)
+
+#undef DEFINE_STATIC_PATTERN_FUNC
+
+static void
+rectangle(cairo_t* cr,
+          double x,
+          double y,
+          double w,
+          double h,
+          int xdenom,
+          int ydenom,
+          int xb1,
+          int yb1,
+          int xb2,
+          int yb2)
+{
+        int const x1 = (w) * (xb1) / (xdenom);
+        int const y1 = (h) * (yb1) / (ydenom);
+        int const x2 = (w) * (xb2) / (xdenom);
+        int const y2 = (h) * (yb2) / (ydenom);
+        cairo_rectangle ((cr), (x) + x1, (y) + y1, MAX(x2 - x1, 1), MAX(y2 - y1, 1));
+        cairo_fill (cr);
+}
+
+static void
+polygon(cairo_t* cr,
+        double x,
+        double y,
+        double w,
+        double h,
+        int xdenom,
+        int ydenom,
+        int8_t const* cc)
+{
+        int x1 = (w) * (cc[0]) / (xdenom);
+        int y1 = (h) * (cc[1]) / (ydenom);
+        cairo_move_to ((cr), (x) + x1, (y) + y1);
+        int i = 2;
+        while (cc[i] != -1) {
+                x1 = (w) * (cc[i]) / (xdenom);
+                y1 = (h) * (cc[i + 1]) / (ydenom);
+                cairo_line_to ((cr), (x) + x1, (y) + y1);
+                i += 2;
+        }
+        cairo_fill (cr);
+}
+
+static void
+pattern(cairo_t* cr,
+        cairo_pattern_t* pattern,
+        double x,
+        double y,
+        double width,
+        double height)
+{
+        cairo_push_group(cr);
+        cairo_rectangle(cr, x, y, width, height);
+        cairo_fill(cr);
+        cairo_pop_group_to_source(cr);
+        cairo_mask(cr, pattern);
+}
+
+#include "box_drawing.h"
+
+namespace vte::view {
+
+/* Draw the graphic representation of a line-drawing or special graphics
+ * character. */
+void
+Minifont::draw_graphic(DrawingContext const& context,
+                       vteunistr c,
+                       uint32_t const attr,
+                       vte::color::rgb const* fg,
+                       int x,
+                       int y,
+                       int font_width,
+                       int columns,
+                       int font_height)
+{
+        gint width, height, xcenter, xright, ycenter, ybottom;
+        int upper_half, left_half;
+        int light_line_width, heavy_line_width;
+        double adjust;
+        auto cr = context.cairo();
+
+        cairo_save (cr);
+
+        width = context.cell_width() * columns;
+        height = context.cell_height();
+        upper_half = height / 2;
+        left_half = width / 2;
+
+        /* Exclude the spacing for line width computation. */
+        light_line_width = font_width / 5;
+        light_line_width = MAX (light_line_width, 1);
+
+        if (c >= 0x2550 && c <= 0x256c) {
+                heavy_line_width = 3 * light_line_width;
+        } else {
+                heavy_line_width = light_line_width + 2;
+        }
+
+        xcenter = x + left_half;
+        ycenter = y + upper_half;
+        xright = x + width;
+        ybottom = y + height;
+
+        switch (c) {
+
+        /* Box Drawing */
+        case 0x1fbaf: /* box drawings light horizontal with vertical stroke */
+                rectangle(cr, x + left_half - light_line_width / 2, y,
+                          light_line_width, height, 1, 3, 0, 1, 1, 2);
+                c = 0x2500;
+                [[fallthrough]];
+        case 0x2500: /* box drawings light horizontal */
+        case 0x2501: /* box drawings heavy horizontal */
+        case 0x2502: /* box drawings light vertical */
+        case 0x2503: /* box drawings heavy vertical */
+        case 0x250c: /* box drawings light down and right */
+        case 0x250d: /* box drawings down light and right heavy */
+        case 0x250e: /* box drawings down heavy and right light */
+        case 0x250f: /* box drawings heavy down and right */
+        case 0x2510: /* box drawings light down and left */
+        case 0x2511: /* box drawings down light and left heavy */
+        case 0x2512: /* box drawings down heavy and left light */
+        case 0x2513: /* box drawings heavy down and left */
+        case 0x2514: /* box drawings light up and right */
+        case 0x2515: /* box drawings up light and right heavy */
+        case 0x2516: /* box drawings up heavy and right light */
+        case 0x2517: /* box drawings heavy up and right */
+        case 0x2518: /* box drawings light up and left */
+        case 0x2519: /* box drawings up light and left heavy */
+        case 0x251a: /* box drawings up heavy and left light */
+        case 0x251b: /* box drawings heavy up and left */
+        case 0x251c: /* box drawings light vertical and right */
+        case 0x251d: /* box drawings vertical light and right heavy */
+        case 0x251e: /* box drawings up heavy and right down light */
+        case 0x251f: /* box drawings down heavy and right up light */
+        case 0x2520: /* box drawings vertical heavy and right light */
+        case 0x2521: /* box drawings down light and right up heavy */
+        case 0x2522: /* box drawings up light and right down heavy */
+        case 0x2523: /* box drawings heavy vertical and right */
+        case 0x2524: /* box drawings light vertical and left */
+        case 0x2525: /* box drawings vertical light and left heavy */
+        case 0x2526: /* box drawings up heavy and left down light */
+        case 0x2527: /* box drawings down heavy and left up light */
+        case 0x2528: /* box drawings vertical heavy and left light */
+        case 0x2529: /* box drawings down light and left up heavy */
+        case 0x252a: /* box drawings up light and left down heavy */
+        case 0x252b: /* box drawings heavy vertical and left */
+        case 0x252c: /* box drawings light down and horizontal */
+        case 0x252d: /* box drawings left heavy and right down light */
+        case 0x252e: /* box drawings right heavy and left down light */
+        case 0x252f: /* box drawings down light and horizontal heavy */
+        case 0x2530: /* box drawings down heavy and horizontal light */
+        case 0x2531: /* box drawings right light and left down heavy */
+        case 0x2532: /* box drawings left light and right down heavy */
+        case 0x2533: /* box drawings heavy down and horizontal */
+        case 0x2534: /* box drawings light up and horizontal */
+        case 0x2535: /* box drawings left heavy and right up light */
+        case 0x2536: /* box drawings right heavy and left up light */
+        case 0x2537: /* box drawings up light and horizontal heavy */
+        case 0x2538: /* box drawings up heavy and horizontal light */
+        case 0x2539: /* box drawings right light and left up heavy */
+        case 0x253a: /* box drawings left light and right up heavy */
+        case 0x253b: /* box drawings heavy up and horizontal */
+        case 0x253c: /* box drawings light vertical and horizontal */
+        case 0x253d: /* box drawings left heavy and right vertical light */
+        case 0x253e: /* box drawings right heavy and left vertical light */
+        case 0x253f: /* box drawings vertical light and horizontal heavy */
+        case 0x2540: /* box drawings up heavy and down horizontal light */
+        case 0x2541: /* box drawings down heavy and up horizontal light */
+        case 0x2542: /* box drawings vertical heavy and horizontal light */
+        case 0x2543: /* box drawings left up heavy and right down light */
+        case 0x2544: /* box drawings right up heavy and left down light */
+        case 0x2545: /* box drawings left down heavy and right up light */
+        case 0x2546: /* box drawings right down heavy and left up light */
+        case 0x2547: /* box drawings down light and up horizontal heavy */
+        case 0x2548: /* box drawings up light and down horizontal heavy */
+        case 0x2549: /* box drawings right light and left vertical heavy */
+        case 0x254a: /* box drawings left light and right vertical heavy */
+        case 0x254b: /* box drawings heavy vertical and horizontal */
+        case 0x2550: /* box drawings double horizontal */
+        case 0x2551: /* box drawings double vertical */
+        case 0x2552: /* box drawings down single and right double */
+        case 0x2553: /* box drawings down double and right single */
+        case 0x2554: /* box drawings double down and right */
+        case 0x2555: /* box drawings down single and left double */
+        case 0x2556: /* box drawings down double and left single */
+        case 0x2557: /* box drawings double down and left */
+        case 0x2558: /* box drawings up single and right double */
+        case 0x2559: /* box drawings up double and right single */
+        case 0x255a: /* box drawings double up and right */
+        case 0x255b: /* box drawings up single and left double */
+        case 0x255c: /* box drawings up double and left single */
+        case 0x255d: /* box drawings double up and left */
+        case 0x255e: /* box drawings vertical single and right double */
+        case 0x255f: /* box drawings vertical double and right single */
+        case 0x2560: /* box drawings double vertical and right */
+        case 0x2561: /* box drawings vertical single and left double */
+        case 0x2562: /* box drawings vertical double and left single */
+        case 0x2563: /* box drawings double vertical and left */
+        case 0x2564: /* box drawings down single and horizontal double */
+        case 0x2565: /* box drawings down double and horizontal single */
+        case 0x2566: /* box drawings double down and horizontal */
+        case 0x2567: /* box drawings up single and horizontal double */
+        case 0x2568: /* box drawings up double and horizontal single */
+        case 0x2569: /* box drawings double up and horizontal */
+        case 0x256a: /* box drawings vertical single and horizontal double */
+        case 0x256b: /* box drawings vertical double and horizontal single */
+        case 0x256c: /* box drawings double vertical and horizontal */
+        case 0x2574: /* box drawings light left */
+        case 0x2575: /* box drawings light up */
+        case 0x2576: /* box drawings light right */
+        case 0x2577: /* box drawings light down */
+        case 0x2578: /* box drawings heavy left */
+        case 0x2579: /* box drawings heavy up */
+        case 0x257a: /* box drawings heavy right */
+        case 0x257b: /* box drawings heavy down */
+        case 0x257c: /* box drawings light left and heavy right */
+        case 0x257d: /* box drawings light up and heavy down */
+        case 0x257e: /* box drawings heavy left and light right */
+        case 0x257f: /* box drawings heavy up and light down */
+        {
+                guint32 bitmap = _vte_draw_box_drawing_bitmaps[c - 0x2500];
+                int xboundaries[6] = { 0,
+                                       left_half - heavy_line_width / 2,
+                                       left_half - light_line_width / 2,
+                                       left_half - light_line_width / 2 + light_line_width,
+                                       left_half - heavy_line_width / 2 + heavy_line_width,
+                                       width};
+                int yboundaries[6] = { 0,
+                                       upper_half - heavy_line_width / 2,
+                                       upper_half - light_line_width / 2,
+                                       upper_half - light_line_width / 2 + light_line_width,
+                                       upper_half - heavy_line_width / 2 + heavy_line_width,
+                                       height};
+                int xi, yi;
+                cairo_set_line_width(cr, 0);
+                for (yi = 4; yi >= 0; yi--) {
+                        for (xi = 4; xi >= 0; xi--) {
+                                if (bitmap & 1) {
+                                        cairo_rectangle(cr,
+                                                        x + xboundaries[xi],
+                                                        y + yboundaries[yi],
+                                                        xboundaries[xi + 1] - xboundaries[xi],
+                                                        yboundaries[yi + 1] - yboundaries[yi]);
+                                        cairo_fill(cr);
+                                }
+                                bitmap >>= 1;
+                        }
+                }
+                break;
+        }
+
+        case 0x2504: /* box drawings light triple dash horizontal */
+        case 0x2505: /* box drawings heavy triple dash horizontal */
+        case 0x2506: /* box drawings light triple dash vertical */
+        case 0x2507: /* box drawings heavy triple dash vertical */
+        case 0x2508: /* box drawings light quadruple dash horizontal */
+        case 0x2509: /* box drawings heavy quadruple dash horizontal */
+        case 0x250a: /* box drawings light quadruple dash vertical */
+        case 0x250b: /* box drawings heavy quadruple dash vertical */
+        case 0x254c: /* box drawings light double dash horizontal */
+        case 0x254d: /* box drawings heavy double dash horizontal */
+        case 0x254e: /* box drawings light double dash vertical */
+        case 0x254f: /* box drawings heavy double dash vertical */
+        {
+                const guint v = c - 0x2500;
+                int size, line_width;
+
+                size = (v & 2) ? height : width;
+
+                switch (v >> 2) {
+                case 1: /* triple dash */
+                {
+                        double segment = size / 8.;
+                        double dashes[2] = { segment * 2., segment };
+                        cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), 0.);
+                        break;
+                }
+                case 2: /* quadruple dash */
+                {
+                        double segment = size / 11.;
+                        double dashes[2] = { segment * 2., segment };
+                        cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), 0.);
+                        break;
+                }
+                case 19: /* double dash */
+                {
+                        double segment = size / 5.;
+                        double dashes[2] = { segment * 2., segment };
+                        cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), 0.);
+                        break;
+                }
+                }
+
+                line_width = (v & 1) ? heavy_line_width : light_line_width;
+                adjust = (line_width & 1) ? .5 : 0.;
+
+                cairo_set_line_width(cr, line_width);
+                cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+                if (v & 2) {
+                        cairo_move_to(cr, xcenter + adjust, y);
+                        cairo_line_to(cr, xcenter + adjust, y + height);
+                } else {
+                        cairo_move_to(cr, x, ycenter + adjust);
+                        cairo_line_to(cr, x + width, ycenter + adjust);
+                }
+                cairo_stroke(cr);
+                break;
+        }
+
+        case 0x256d: /* box drawings light arc down and right */
+        case 0x256e: /* box drawings light arc down and left */
+        case 0x256f: /* box drawings light arc up and left */
+        case 0x2570: /* box drawings light arc up and right */
+        {
+                const guint v = c - 0x256d;
+                int line_width;
+                int radius;
+
+                cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+
+                line_width = light_line_width;
+                adjust = (line_width & 1) ? .5 : 0.;
+                cairo_set_line_width(cr, line_width);
+
+                radius = (font_width + 2) / 3;
+                radius = MAX(radius, heavy_line_width);
+
+                if (v & 2) {
+                        cairo_move_to(cr, xcenter + adjust, y);
+                        cairo_line_to(cr, xcenter + adjust, ycenter - radius + 2 * adjust);
+                } else {
+                        cairo_move_to(cr, xcenter + adjust, ybottom);
+                        cairo_line_to(cr, xcenter + adjust, ycenter + radius);
+                }
+                cairo_stroke(cr);
+
+                cairo_arc(cr,
+                          (v == 1 || v == 2) ? xcenter - radius + 2 * adjust
+                                             : xcenter + radius,
+                          (v & 2) ? ycenter - radius + 2 * adjust
+                                  : ycenter + radius,
+                          radius - adjust,
+                          (v + 2) * M_PI / 2.0, (v + 3) * M_PI / 2.0);
+                cairo_stroke(cr);
+
+                if (v == 1 || v == 2) {
+                        cairo_move_to(cr, xcenter - radius + 2 * adjust, ycenter + adjust);
+                        cairo_line_to(cr, x, ycenter + adjust);
+                } else {
+                        cairo_move_to(cr, xcenter + radius, ycenter + adjust);
+                        cairo_line_to(cr, xright, ycenter + adjust);
+                }
+
+                cairo_stroke(cr);
+                break;
+        }
+
+        case 0x2571: /* box drawings light diagonal upper right to lower left */
+        case 0x2572: /* box drawings light diagonal upper left to lower right */
+        case 0x2573: /* box drawings light diagonal cross */
+        {
+                auto const dx = (light_line_width + 1) / 2;
+                cairo_rectangle(cr, x - dx, y, width + 2 * dx, height);
+                cairo_clip(cr);
+                cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
+                cairo_set_line_width(cr, light_line_width);
+                if (c != 0x2571) {
+                        cairo_move_to(cr, x, y);
+                        cairo_line_to(cr, xright, ybottom);
+                        cairo_stroke(cr);
+                }
+                if (c != 0x2572) {
+                        cairo_move_to(cr, xright, y);
+                        cairo_line_to(cr, x, ybottom);
+                        cairo_stroke(cr);
+                }
+                break;
+        }
+
+        /* Block Elements */
+        case 0x2580: /* upper half block */
+                rectangle(cr, x, y, width, height, 1, 2,  0, 0,  1, 1);
+                break;
+
+        case 0x2581: /* lower one eighth block */
+        case 0x2582: /* lower one quarter block */
+        case 0x2583: /* lower three eighths block */
+        case 0x2584: /* lower half block */
+        case 0x2585: /* lower five eighths block */
+        case 0x2586: /* lower three quarters block */
+        case 0x2587: /* lower seven eighths block */
+        {
+                const guint v = 0x2588 - c;
+                rectangle(cr, x, y, width, height, 1, 8,  0, v,  1, 8);
+                break;
+        }
+
+        case 0x2588: /* full block */
+        case 0x2589: /* left seven eighths block */
+        case 0x258a: /* left three quarters block */
+        case 0x258b: /* left five eighths block */
+        case 0x258c: /* left half block */
+        case 0x258d: /* left three eighths block */
+        case 0x258e: /* left one quarter block */
+        case 0x258f: /* left one eighth block */
+        {
+                const guint v = 0x2590 - c;
+                rectangle(cr, x, y, width, height, 8, 1,  0, 0,  v, 1);
+                break;
+        }
+
+        case 0x2590: /* right half block */
+                rectangle(cr, x, y, width, height, 2, 1,  1, 0,  2, 1);
+                break;
+
+        case 0x2591: /* light shade */
+        case 0x2592: /* medium shade */
+        case 0x2593: /* dark shade */
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       (c - 0x2590) / 4.);
+                cairo_rectangle(cr, x, y, width, height);
+                cairo_fill (cr);
+                break;
+
+        case 0x2594: /* upper one eighth block */
+        {
+                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, 1);
+                break;
+        }
+
+        case 0x2595: /* right one eighth block */
+        {
+                rectangle(cr, x, y, width, height, 8, 1,  7, 0,  8, 1);
+                break;
+        }
+
+        case 0x2596: /* quadrant lower left */
+                rectangle(cr, x, y, width, height, 2, 2,  0, 1,  1, 2);
+                break;
+
+        case 0x2597: /* quadrant lower right */
+                rectangle(cr, x, y, width, height, 2, 2,  1, 1,  2, 2);
+                break;
+
+        case 0x2598: /* quadrant upper left */
+                rectangle(cr, x, y, width, height, 2, 2,  0, 0,  1, 1);
+                break;
+
+        case 0x2599: /* quadrant upper left and lower left and lower right */
+                rectangle(cr, x, y, width, height, 2, 2,  0, 0,  1, 1);
+                rectangle(cr, x, y, width, height, 2, 2,  0, 1,  2, 2);
+                break;
+
+        case 0x259a: /* quadrant upper left and lower right */
+                rectangle(cr, x, y, width, height, 2, 2,  0, 0,  1, 1);
+                rectangle(cr, x, y, width, height, 2, 2,  1, 1,  2, 2);
+                break;
+
+        case 0x259b: /* quadrant upper left and upper right and lower left */
+                rectangle(cr, x, y, width, height, 2, 2,  0, 0,  2, 1);
+                rectangle(cr, x, y, width, height, 2, 2,  0, 1,  1, 2);
+                break;
+
+        case 0x259c: /* quadrant upper left and upper right and lower right */
+                rectangle(cr, x, y, width, height, 2, 2,  0, 0,  2, 1);
+                rectangle(cr, x, y, width, height, 2, 2,  1, 1,  2, 2);
+                break;
+
+        case 0x259d: /* quadrant upper right */
+                rectangle(cr, x, y, width, height, 2, 2,  1, 0,  2, 1);
+                break;
+
+        case 0x259e: /* quadrant upper right and lower left */
+                rectangle(cr, x, y, width, height, 2, 2,  1, 0,  2, 1);
+                rectangle(cr, x, y, width, height, 2, 2,  0, 1,  1, 2);
+                break;
+
+        case 0x259f: /* quadrant upper right and lower left and lower right */
+                rectangle(cr, x, y, width, height, 2, 2,  1, 0,  2, 1);
+                rectangle(cr, x, y, width, height, 2, 2,  0, 1,  2, 2);
+                break;
+
+        case 0x25e2: /* black lower right triangle */
+        {
+                static int8_t const coords[] = { 0, 1,  1, 0,  1, 1,  -1 };
+                polygon(cr, x, y, width, height, 1, 1, coords);
+                break;
+        }
+
+        case 0x25e3: /* black lower left triangle */
+        {
+                static int8_t const coords[] = { 0, 0,  1, 1,  0, 1,  -1 };
+                polygon(cr, x, y, width, height, 1, 1, coords);
+                break;
+        }
+
+        case 0x25e4: /* black upper left triangle */
+        {
+                static int8_t const coords[] = { 0, 0,  1, 0,  0, 1,  -1 };
+                polygon(cr, x, y, width, height, 1, 1, coords);
+                break;
+        }
+
+        case 0x25e5: /* black upper right triangle */
+        {
+                static int8_t const coords[] = { 0, 0,  1, 0,  1, 1,  -1 };
+                polygon(cr, x, y, width, height, 1, 1, coords);
+                break;
+        }
+
+        case 0x1fb00:
+        case 0x1fb01:
+        case 0x1fb02:
+        case 0x1fb03:
+        case 0x1fb04:
+        case 0x1fb05:
+        case 0x1fb06:
+        case 0x1fb07:
+        case 0x1fb08:
+        case 0x1fb09:
+        case 0x1fb0a:
+        case 0x1fb0b:
+        case 0x1fb0c:
+        case 0x1fb0d:
+        case 0x1fb0e:
+        case 0x1fb0f:
+        case 0x1fb10:
+        case 0x1fb11:
+        case 0x1fb12:
+        case 0x1fb13:
+        case 0x1fb14:
+        case 0x1fb15:
+        case 0x1fb16:
+        case 0x1fb17:
+        case 0x1fb18:
+        case 0x1fb19:
+        case 0x1fb1a:
+        case 0x1fb1b:
+        case 0x1fb1c:
+        case 0x1fb1d:
+        case 0x1fb1e:
+        case 0x1fb1f:
+        case 0x1fb20:
+        case 0x1fb21:
+        case 0x1fb22:
+        case 0x1fb23:
+        case 0x1fb24:
+        case 0x1fb25:
+        case 0x1fb26:
+        case 0x1fb27:
+        case 0x1fb28:
+        case 0x1fb29:
+        case 0x1fb2a:
+        case 0x1fb2b:
+        case 0x1fb2c:
+        case 0x1fb2d:
+        case 0x1fb2e:
+        case 0x1fb2f:
+        case 0x1fb30:
+        case 0x1fb31:
+        case 0x1fb32:
+        case 0x1fb33:
+        case 0x1fb34:
+        case 0x1fb35:
+        case 0x1fb36:
+        case 0x1fb37:
+        case 0x1fb38:
+        case 0x1fb39:
+        case 0x1fb3a:
+        case 0x1fb3b:
+        {
+                guint32 bitmap = c - 0x1fb00 + 1;
+                if (bitmap >= 0x15) bitmap++;
+                if (bitmap >= 0x2a) bitmap++;
+                int xi, yi;
+                cairo_set_line_width(cr, 0);
+                for (yi = 0; yi <= 2; yi++) {
+                        for (xi = 0; xi <= 1; xi++) {
+                                if (bitmap & 1) {
+                                        rectangle(cr, x, y, width, height, 2, 3,  xi, yi, xi + 1,  yi + 1);
+                                }
+                                bitmap >>= 1;
+                        }
+                }
+                break;
+        }
+
+        case 0x1fb3c:
+        case 0x1fb3d:
+        case 0x1fb3e:
+        case 0x1fb3f:
+        case 0x1fb40:
+        case 0x1fb41:
+        case 0x1fb42:
+        case 0x1fb43:
+        case 0x1fb44:
+        case 0x1fb45:
+        case 0x1fb46:
+        case 0x1fb47:
+        case 0x1fb48:
+        case 0x1fb49:
+        case 0x1fb4a:
+        case 0x1fb4b:
+        case 0x1fb4c:
+        case 0x1fb4d:
+        case 0x1fb4e:
+        case 0x1fb4f:
+        case 0x1fb50:
+        case 0x1fb51:
+        case 0x1fb52:
+        case 0x1fb53:
+        case 0x1fb54:
+        case 0x1fb55:
+        case 0x1fb56:
+        case 0x1fb57:
+        case 0x1fb58:
+        case 0x1fb59:
+        case 0x1fb5a:
+        case 0x1fb5b:
+        case 0x1fb5c:
+        case 0x1fb5d:
+        case 0x1fb5e:
+        case 0x1fb5f:
+        case 0x1fb60:
+        case 0x1fb61:
+        case 0x1fb62:
+        case 0x1fb63:
+        case 0x1fb64:
+        case 0x1fb65:
+        case 0x1fb66:
+        case 0x1fb67:
+        {
+                auto const v = c - 0x1fb3c;
+                static int8_t const coords[46][11] = {
+                        { 0, 2,  1, 3,  0, 3,  -1 },                /* 3c */
+                        { 0, 2,  2, 3,  0, 3,  -1 },                /* 3d */
+                        { 0, 1,  1, 3,  0, 3,  -1 },                /* 3e */
+                        { 0, 1,  2, 3,  0, 3,  -1 },                /* 3f */
+                        { 0, 0,  1, 3,  0, 3,  -1 },                /* 40 */
+                        { 0, 1,  1, 0,  2, 0,  2, 3,  0, 3,  -1 },  /* 41 */
+                        { 0, 1,  2, 0,  2, 3,  0, 3,  -1 },         /* 42 */
+                        { 0, 2,  1, 0,  2, 0,  2, 3,  0, 3,  -1 },  /* 43 */
+                        { 0, 2,  2, 0,  2, 3,  0, 3,  -1 },         /* 44 */
+                        { 0, 3,  1, 0,  2, 0,  2, 3,  -1 },         /* 45 */
+                        { 0, 2,  2, 1,  2, 3,  0, 3,  -1 },         /* 46 */
+                        { 1, 3,  2, 2,  2, 3,  -1 },                /* 47 */
+                        { 0, 3,  2, 2,  2, 3,  -1 },                /* 48 */
+                        { 1, 3,  2, 1,  2, 3,  -1 },                /* 49 */
+                        { 0, 3,  2, 1,  2, 3,  -1 },                /* 4a */
+                        { 1, 3,  2, 0,  2, 3,  -1 },                /* 4b */
+                        { 0, 0,  1, 0,  2, 1,  2, 3,  0, 3,  -1 },  /* 4c */
+                        { 0, 0,  2, 1,  2, 3,  0, 3,  -1 },         /* 4d */
+                        { 0, 0,  1, 0,  2, 2,  2, 3,  0, 3,  -1 },  /* 4e */
+                        { 0, 0,  2, 2,  2, 3,  0, 3,  -1 },         /* 4f */
+                        { 0, 0,  1, 0,  2, 3,  0, 3,  -1 },         /* 50 */
+                        { 0, 1,  2, 2,  2, 3,  0, 3,  -1 },         /* 51 */
+                        { 0, 0,  2, 0,  2, 3,  1, 3,  0, 2,  -1 },  /* 52 */
+                        { 0, 0,  2, 0,  2, 3,  0, 2,  -1 },         /* 53 */
+                        { 0, 0,  2, 0,  2, 3,  1, 3,  0, 1,  -1 },  /* 54 */
+                        { 0, 0,  2, 0,  2, 3,  0, 1,  -1 },         /* 55 */
+                        { 0, 0,  2, 0,  2, 3,  1, 3,  -1 },         /* 56 */
+                        { 0, 0,  1, 0,  0, 1,  -1 },                /* 57 */
+                        { 0, 0,  2, 0,  0, 1,  -1 },                /* 58 */
+                        { 0, 0,  1, 0,  0, 2,  -1 },                /* 59 */
+                        { 0, 0,  2, 0,  0, 2,  -1 },                /* 5a */
+                        { 0, 0,  1, 0,  0, 3,  -1 },                /* 5b */
+                        { 0, 0,  2, 0,  2, 1,  0, 2,  -1 },         /* 5c */
+                        { 0, 0,  2, 0,  2, 2,  1, 3,  0, 3,  -1 },  /* 5d */
+                        { 0, 0,  2, 0,  2, 2,  0, 3,  -1 },         /* 5e */
+                        { 0, 0,  2, 0,  2, 1,  1, 3,  0, 3,  -1 },  /* 5f */
+                        { 0, 0,  2, 0,  2, 1,  0, 3,  -1 },         /* 60 */
+                        { 0, 0,  2, 0,  1, 3,  0, 3,  -1 },         /* 61 */
+                        { 1, 0,  2, 0,  2, 1,  -1 },                /* 62 */
+                        { 0, 0,  2, 0,  2, 1,  -1 },                /* 63 */
+                        { 1, 0,  2, 0,  2, 2,  -1 },                /* 64 */
+                        { 0, 0,  2, 0,  2, 2,  -1 },                /* 65 */
+                        { 1, 0,  2, 0,  2, 3,  -1 },                /* 66 */
+                        { 0, 0,  2, 0,  2, 2,  0, 1,  -1 },         /* 67 */
+                };
+                polygon(cr, x, y, width, height, 2, 3, coords[v]);
+                break;
+        }
+
+        case 0x1fb68:
+        case 0x1fb69:
+        case 0x1fb6a:
+        case 0x1fb6b:
+        case 0x1fb6c:
+        case 0x1fb6d:
+        case 0x1fb6e:
+        case 0x1fb6f:
+        {
+                auto const v = c - 0x1fb68;
+                static int8_t const coords[8][11] = {
+                        { 0, 0,  2, 0,  2, 2,  0, 2,  1, 1,  -1 },  /* 68 */
+                        { 0, 0,  1, 1,  2, 0,  2, 2,  0, 2,  -1 },  /* 69 */
+                        { 0, 0,  2, 0,  1, 1,  2, 2,  0, 2,  -1 },  /* 6a */
+                        { 0, 0,  2, 0,  2, 2,  1, 1,  0, 2,  -1 },  /* 6b */
+                        { 0, 0,  1, 1,  0, 2,  -1 },                /* 6c */
+                        { 0, 0,  2, 0,  1, 1,  -1 },                /* 6d */
+                        { 1, 1,  2, 0,  2, 2,  -1 },                /* 6e */
+                        { 1, 1,  2, 2,  0, 2,  -1 },                /* 6f */
+                };
+                polygon(cr, x, y, width, height, 2, 2, coords[v]);
+                break;
+        }
+
+        case 0x1fb70:
+        case 0x1fb71:
+        case 0x1fb72:
+        case 0x1fb73:
+        case 0x1fb74:
+        case 0x1fb75:
+        {
+                auto const v = c - 0x1fb70 + 1;
+                rectangle(cr, x, y, width, height, 8, 1,  v, 0,  v + 1, 1);
+                break;
+        }
+
+        case 0x1fb76:
+        case 0x1fb77:
+        case 0x1fb78:
+        case 0x1fb79:
+        case 0x1fb7a:
+        case 0x1fb7b:
+        {
+                auto const v = c - 0x1fb76 + 1;
+                rectangle(cr, x, y, width, height, 1, 8,  0, v,  1, v + 1);
+                break;
+        }
+
+        case 0x1fb7c:
+                rectangle(cr, x, y, width, height, 1, 8,  0, 7,  1, 8);
+                rectangle(cr, x, y, width, height, 8, 1,  0, 0,  1, 1);
+                break;
+
+        case 0x1fb7d:
+                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, 1);
+                rectangle(cr, x, y, width, height, 8, 1,  0, 0,  1, 1);
+                break;
+
+        case 0x1fb7e:
+                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, 1);
+                rectangle(cr, x, y, width, height, 8, 1,  7, 0,  8, 1);
+                break;
+
+        case 0x1fb7f:
+                rectangle(cr, x, y, width, height, 1, 8,  0, 7,  1, 8);
+                rectangle(cr, x, y, width, height, 8, 1,  7, 0,  8, 1);
+                break;
+
+        case 0x1fb80:
+                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, 1);
+                rectangle(cr, x, y, width, height, 1, 8,  0, 7,  1, 8);
+                break;
+
+        case 0x1fb81:
+                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, 1);
+                rectangle(cr, x, y, width, height, 1, 8,  0, 2,  1, 3);
+                rectangle(cr, x, y, width, height, 1, 8,  0, 4,  1, 5);
+                rectangle(cr, x, y, width, height, 1, 8,  0, 7,  1, 8);
+                break;
+
+        case 0x1fb82:
+        case 0x1fb83:
+        case 0x1fb84:
+        case 0x1fb85:
+        case 0x1fb86:
+        {
+                auto v = c - 0x1fb82 + 2;
+                if (v >= 4) v++;
+                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, v);
+                break;
+        }
+
+        case 0x1fb87:
+        case 0x1fb88:
+        case 0x1fb89:
+        case 0x1fb8a:
+        case 0x1fb8b:
+        {
+                auto v = c - 0x1fb87 + 2;
+                if (v >= 4) v++;
+                rectangle(cr, x, y, width, height, 8, 1,  8 - v, 0,  8, 1);
+                break;
+        }
+
+        case 0x1fb8c:
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                rectangle(cr, x, y, width, height, 2, 1,  0, 0,  1, 1);
+                break;
+
+        case 0x1fb8d:
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                rectangle(cr, x, y, width, height, 2, 1,  1, 0,  2, 1);
+                break;
+
+        case 0x1fb8e:
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                rectangle(cr, x, y, width, height, 1, 2,  0, 0,  1, 1);
+                break;
+
+        case 0x1fb8f:
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                rectangle(cr, x, y, width, height, 1, 2,  0, 1,  1, 2);
+                break;
+
+        case 0x1fb90:
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                rectangle(cr, x, y, width, height, 1, 1,  0, 0,  1, 1);
+                break;
+
+        case 0x1fb91:
+                rectangle(cr, x, y, width, height, 1, 2,  0, 0,  1, 1);
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                rectangle(cr, x, y, width, height, 1, 2,  0, 1,  1, 2);
+                break;
+
+        case 0x1fb92:
+                rectangle(cr, x, y, width, height, 1, 2,  0, 1,  1, 2);
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                rectangle(cr, x, y, width, height, 1, 2,  0, 0,  1, 1);
+                break;
+
+        case 0x1fb93:
+#if 0
+                /* codepoint not assigned */
+                rectangle(cr, x, y, width, height, 2, 1,  0, 0,  1, 1);
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                rectangle(cr, x, y, width, height, 2, 1,  1, 0,  2, 1);
+#endif
+                break;
+
+        case 0x1fb94:
+                rectangle(cr, x, y, width, height, 2, 1,  1, 0,  2, 1);
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                rectangle(cr, x, y, width, height, 2, 1,  0, 0,  1, 1);
+                break;
+
+        case 0x1fb95:
+                pattern(cr, create_checkerboard_pattern(), x, y, width, height);
+                break;
+
+        case 0x1fb96:
+                pattern(cr, create_checkerboard_reverse_pattern(), x, y, width, height);
+                break;
+
+        case 0x1fb97:
+                rectangle(cr, x, y, width, height, 1, 4,  0, 1,  1, 2);
+                rectangle(cr, x, y, width, height, 1, 4,  0, 3,  1, 4);
+                break;
+
+        case 0x1fb98:
+                pattern(cr, create_hatching_pattern_lr(), x, y, width, height);
+                break;
+
+        case 0x1fb99:
+                pattern(cr, create_hatching_pattern_rl(), x, y, width, height);
+                break;
+
+        case 0x1fb9a:
+        {
+                static int8_t const coords[] = { 0, 0,  1, 0,  0, 1,  1, 1,  -1 };
+                polygon(cr, x, y, width, height, 1, 1, coords);
+                break;
+        }
+
+        case 0x1fb9b:
+        {
+                static int8_t coords[] = { 0, 0,  1, 1,  1, 0,  0, 1,  -1 };
+                polygon(cr, x, y, width, height, 1, 1, coords);
+                break;
+        }
+
+        case 0x1fb9c:
+        {
+                static int8_t const coords[] = { 0, 0,  1, 0,  0, 1,  -1 };
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                polygon(cr, x, y, width, height, 1, 1, coords);
+                break;
+        }
+
+        case 0x1fb9d:
+        {
+                static int8_t const coords[] = { 0, 0,  1, 0,  1, 1,  -1 };
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                polygon(cr, x, y, width, height, 1, 1, coords);
+                break;
+        }
+
+        case 0x1fb9e:
+        {
+                static int8_t const coords[] = { 0, 1,  1, 0,  1, 1,  -1 };
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                polygon(cr, x, y, width, height, 1, 1, coords);
+                break;
+        }
+
+        case 0x1fb9f:
+        {
+                static int8_t const coords[] = { 0, 0,  1, 1,  0, 1,  -1 };
+                cairo_set_source_rgba (cr,
+                                       fg->red / 65535.,
+                                       fg->green / 65535.,
+                                       fg->blue / 65535.,
+                                       0.5);
+                polygon(cr, x, y, width, height, 1, 1, coords);
+                break;
+        }
+
+        case 0x1fba0:
+        case 0x1fba1:
+        case 0x1fba2:
+        case 0x1fba3:
+        case 0x1fba4:
+        case 0x1fba5:
+        case 0x1fba6:
+        case 0x1fba7:
+        case 0x1fba8:
+        case 0x1fba9:
+        case 0x1fbaa:
+        case 0x1fbab:
+        case 0x1fbac:
+        case 0x1fbad:
+        case 0x1fbae:
+        {
+                auto const v = c - 0x1fba0;
+                static uint8_t const map[15] = { 0b0001, 0b0010, 0b0100, 0b1000, 0b0101, 0b1010, 0b1100, 
0b0011,
+                                                 0b1001, 0b0110, 0b1110, 0b1101, 0b1011, 0b0111, 0b1111 };
+                cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+                cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+                cairo_set_line_width(cr, light_line_width);
+                adjust = (light_line_width & 1) ? .5 : 0.;
+                double const dx = light_line_width / 2.;
+                double const dy = light_line_width / 2.;
+                if (map[v] & 1) {
+                        /* upper left */
+                        cairo_move_to(cr, x, ycenter + adjust);
+                        cairo_line_to(cr, x + dx, ycenter + adjust);
+                        cairo_line_to(cr, xcenter + adjust, y + dy);
+                        cairo_line_to(cr, xcenter + adjust, y);
+                        cairo_stroke(cr);
+                }
+                if (map[v] & 2) {
+                        /* upper right */
+                        cairo_move_to(cr, xright, ycenter + adjust);
+                        cairo_line_to(cr, xright - dx, ycenter + adjust);
+                        cairo_line_to(cr, xcenter + adjust, y + dy);
+                        cairo_line_to(cr, xcenter + adjust, y);
+                        cairo_stroke(cr);
+                }
+                if (map[v] & 4) {
+                        /* lower left */
+                        cairo_move_to(cr, x, ycenter + adjust);
+                        cairo_line_to(cr, x + dx, ycenter + adjust);
+                        cairo_line_to(cr, xcenter + adjust, ybottom - dy);
+                        cairo_line_to(cr, xcenter + adjust, ybottom);
+                        cairo_stroke(cr);
+                }
+                if (map[v] & 8) {
+                        /* lower right */
+                        cairo_move_to(cr, xright, ycenter + adjust);
+                        cairo_line_to(cr, xright - dx, ycenter + adjust);
+                        cairo_line_to(cr, xcenter + adjust, ybottom - dy);
+                        cairo_line_to(cr, xcenter + adjust, ybottom);
+                        cairo_stroke(cr);
+                }
+                break;
+        }
+
+        default:
+                g_assert_not_reached();
+        }
+
+        cairo_restore(cr);
+}
+
+} // namespace vte::view
diff --git a/src/minifont.hh b/src/minifont.hh
new file mode 100644
index 00000000..f2b65f5f
--- /dev/null
+++ b/src/minifont.hh
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2003,2008 Red Hat, Inc.
+ * Copyright © 2019, 2020 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include "fwd.hh"
+#include "vtetypes.hh"
+#include "vteunistr.h"
+
+namespace vte {
+namespace view {
+
+class Minifont {
+public:
+
+        /* Check if a unicode character is actually a graphic character we draw
+         * ourselves to handle cases where fonts don't have glyphs for them.
+         */
+        static inline constexpr bool
+        unistr_is_local_graphic(vteunistr const c) noexcept
+        {
+                /* Box Drawing & Block Elements */
+                return ((c >=  0x2500 && c <=  0x259f) ||
+                        (c >=  0x25e2 && c <=  0x25e5) ||
+                        (c >= 0x1fb00 && c <= 0x1fbaf));
+        }
+
+        /* Draw the graphic representation of a line-drawing or special graphics
+         * character.
+         */
+        void draw_graphic(DrawingContext const& context,
+                          vteunistr c,
+                          uint32_t const attr,
+                          vte::color::rgb const* fg,
+                          int x,
+                          int y,
+                          int font_width,
+                          int columns,
+                          int font_height);
+
+}; // class Minifont
+
+} // namespace view
+} // namespace vte
diff --git a/src/vtedraw.cc b/src/vtedraw.cc
index b5af3d37..50378dd4 100644
--- a/src/vtedraw.cc
+++ b/src/vtedraw.cc
@@ -232,17 +232,6 @@ DrawingContext::get_text_metrics(int* cell_width,
                 *char_spacing = m_char_spacing;
 }
 
-/* Check if a unicode character is actually a graphic character we draw
- * ourselves to handle cases where fonts don't have glyphs for them. */
-static constexpr bool
-unichar_is_local_graphic(vteunistr c) noexcept
-{
-        /* Box Drawing & Block Elements */
-        return ((c >=  0x2500 && c <=  0x259f) ||
-                (c >=  0x25e2 && c <=  0x25e5) ||
-                (c >= 0x1fb00 && c <= 0x1fbaf));
-}
-
 /* Stores the left and right edges of the given glyph, relative to the cell's left edge. */
 void
 DrawingContext::get_char_edges(vteunistr c,
@@ -251,7 +240,7 @@ DrawingContext::get_char_edges(vteunistr c,
                                int& left,
                                int& right)
 {
-        if (G_UNLIKELY(unichar_is_local_graphic (c))) {
+        if (G_UNLIKELY(m_minifont.unistr_is_local_graphic (c))) {
                 left = 0;
                 right = m_cell_width * columns;
                 return;
@@ -286,1088 +275,6 @@ DrawingContext::get_char_edges(vteunistr c,
         right = l + w;
 }
 
-/* pixman data must have stride 0 mod 4 */
-static unsigned char const hatching_pattern_lr_data[16] = {
-        0xff, 0x00, 0x00, 0x00,
-        0x00, 0xff, 0x00, 0x00,
-        0x00, 0x00, 0xff, 0x00,
-        0x00, 0x00, 0x00, 0xff,
-};
-static unsigned char const hatching_pattern_rl_data[16] = {
-        0x00, 0x00, 0x00, 0xff,
-        0x00, 0x00, 0xff, 0x00,
-        0x00, 0xff, 0x00, 0x00,
-        0xff, 0x00, 0x00, 0x00,
-};
-static unsigned char const checkerboard_pattern_data[16] = {
-        0xff, 0xff, 0x00, 0x00,
-        0xff, 0xff, 0x00, 0x00,
-        0x00, 0x00, 0xff, 0xff,
-        0x00, 0x00, 0xff, 0xff,
-};
-static unsigned char const checkerboard_reverse_pattern_data[16] = {
-        0x00, 0x00, 0xff, 0xff,
-        0x00, 0x00, 0xff, 0xff,
-        0xff, 0xff, 0x00, 0x00,
-        0xff, 0xff, 0x00, 0x00,
-};
-
-#define DEFINE_STATIC_PATTERN_FUNC(name,data,width,height,stride) \
-static cairo_pattern_t* \
-name(void) \
-{ \
-        static cairo_pattern_t* pattern = nullptr; \
-\
-        if (pattern == nullptr) { \
-                auto surface = cairo_image_surface_create_for_data(const_cast<unsigned char*>(data), \
-                                                                   CAIRO_FORMAT_A8, \
-                                                                   width, \
-                                                                   height, \
-                                                                   stride); \
-                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; \
-}
-
-DEFINE_STATIC_PATTERN_FUNC(create_hatching_pattern_lr, hatching_pattern_lr_data, 4, 4, 4)
-DEFINE_STATIC_PATTERN_FUNC(create_hatching_pattern_rl, hatching_pattern_rl_data, 4, 4, 4)
-DEFINE_STATIC_PATTERN_FUNC(create_checkerboard_pattern, checkerboard_pattern_data, 4, 4, 4)
-DEFINE_STATIC_PATTERN_FUNC(create_checkerboard_reverse_pattern, checkerboard_reverse_pattern_data, 4, 4, 4)
-
-#undef DEFINE_STATIC_PATTERN_FUNC
-
-static void
-rectangle(cairo_t* cr,
-          double x,
-          double y,
-          double w,
-          double h,
-          int xdenom,
-          int ydenom,
-          int xb1,
-          int yb1,
-          int xb2,
-          int yb2)
-{
-        int const x1 = (w) * (xb1) / (xdenom);
-        int const y1 = (h) * (yb1) / (ydenom);
-        int const x2 = (w) * (xb2) / (xdenom);
-        int const y2 = (h) * (yb2) / (ydenom);
-        cairo_rectangle ((cr), (x) + x1, (y) + y1, MAX(x2 - x1, 1), MAX(y2 - y1, 1));
-        cairo_fill (cr);
-}
-
-static void
-polygon(cairo_t* cr,
-        double x,
-        double y,
-        double w,
-        double h,
-        int xdenom,
-        int ydenom,
-        int8_t const* cc)
-{
-        int x1 = (w) * (cc[0]) / (xdenom);
-        int y1 = (h) * (cc[1]) / (ydenom);
-        cairo_move_to ((cr), (x) + x1, (y) + y1);
-        int i = 2;
-        while (cc[i] != -1) {
-                x1 = (w) * (cc[i]) / (xdenom);
-                y1 = (h) * (cc[i + 1]) / (ydenom);
-                cairo_line_to ((cr), (x) + x1, (y) + y1);
-                i += 2;
-        }
-        cairo_fill (cr);
-}
-
-static void
-pattern(cairo_t* cr,
-        cairo_pattern_t* pattern,
-        double x,
-        double y,
-        double width,
-        double height)
-{
-        cairo_push_group(cr);
-        cairo_rectangle(cr, x, y, width, height);
-        cairo_fill(cr);
-        cairo_pop_group_to_source(cr);
-        cairo_mask(cr, pattern);
-}
-
-#include "box_drawing.h"
-
-/* Draw the graphic representation of a line-drawing or special graphics
- * character. */
-void
-DrawingContext::draw_graphic(vteunistr c,
-                             uint32_t attr,
-                             vte::color::rgb const* fg,
-                             int x,
-                             int y,
-                             int font_width,
-                             int columns,
-                             int font_height)
-{
-        gint width, height, xcenter, xright, ycenter, ybottom;
-        int upper_half, left_half;
-        int light_line_width, heavy_line_width;
-        double adjust;
-        cairo_t *cr = m_cr;
-
-        cairo_save (cr);
-
-        width = m_cell_width * columns;
-        height = m_cell_height;
-        upper_half = height / 2;
-        left_half = width / 2;
-
-        /* Exclude the spacing for line width computation. */
-        light_line_width = font_width / 5;
-        light_line_width = MAX (light_line_width, 1);
-
-        if (c >= 0x2550 && c <= 0x256c) {
-                heavy_line_width = 3 * light_line_width;
-        } else {
-                heavy_line_width = light_line_width + 2;
-        }
-
-        xcenter = x + left_half;
-        ycenter = y + upper_half;
-        xright = x + width;
-        ybottom = y + height;
-
-        switch (c) {
-
-        /* Box Drawing */
-        case 0x1fbaf: /* box drawings light horizontal with vertical stroke */
-                rectangle(cr, x + left_half - light_line_width / 2, y,
-                          light_line_width, height, 1, 3, 0, 1, 1, 2);
-                c = 0x2500;
-                [[fallthrough]];
-        case 0x2500: /* box drawings light horizontal */
-        case 0x2501: /* box drawings heavy horizontal */
-        case 0x2502: /* box drawings light vertical */
-        case 0x2503: /* box drawings heavy vertical */
-        case 0x250c: /* box drawings light down and right */
-        case 0x250d: /* box drawings down light and right heavy */
-        case 0x250e: /* box drawings down heavy and right light */
-        case 0x250f: /* box drawings heavy down and right */
-        case 0x2510: /* box drawings light down and left */
-        case 0x2511: /* box drawings down light and left heavy */
-        case 0x2512: /* box drawings down heavy and left light */
-        case 0x2513: /* box drawings heavy down and left */
-        case 0x2514: /* box drawings light up and right */
-        case 0x2515: /* box drawings up light and right heavy */
-        case 0x2516: /* box drawings up heavy and right light */
-        case 0x2517: /* box drawings heavy up and right */
-        case 0x2518: /* box drawings light up and left */
-        case 0x2519: /* box drawings up light and left heavy */
-        case 0x251a: /* box drawings up heavy and left light */
-        case 0x251b: /* box drawings heavy up and left */
-        case 0x251c: /* box drawings light vertical and right */
-        case 0x251d: /* box drawings vertical light and right heavy */
-        case 0x251e: /* box drawings up heavy and right down light */
-        case 0x251f: /* box drawings down heavy and right up light */
-        case 0x2520: /* box drawings vertical heavy and right light */
-        case 0x2521: /* box drawings down light and right up heavy */
-        case 0x2522: /* box drawings up light and right down heavy */
-        case 0x2523: /* box drawings heavy vertical and right */
-        case 0x2524: /* box drawings light vertical and left */
-        case 0x2525: /* box drawings vertical light and left heavy */
-        case 0x2526: /* box drawings up heavy and left down light */
-        case 0x2527: /* box drawings down heavy and left up light */
-        case 0x2528: /* box drawings vertical heavy and left light */
-        case 0x2529: /* box drawings down light and left up heavy */
-        case 0x252a: /* box drawings up light and left down heavy */
-        case 0x252b: /* box drawings heavy vertical and left */
-        case 0x252c: /* box drawings light down and horizontal */
-        case 0x252d: /* box drawings left heavy and right down light */
-        case 0x252e: /* box drawings right heavy and left down light */
-        case 0x252f: /* box drawings down light and horizontal heavy */
-        case 0x2530: /* box drawings down heavy and horizontal light */
-        case 0x2531: /* box drawings right light and left down heavy */
-        case 0x2532: /* box drawings left light and right down heavy */
-        case 0x2533: /* box drawings heavy down and horizontal */
-        case 0x2534: /* box drawings light up and horizontal */
-        case 0x2535: /* box drawings left heavy and right up light */
-        case 0x2536: /* box drawings right heavy and left up light */
-        case 0x2537: /* box drawings up light and horizontal heavy */
-        case 0x2538: /* box drawings up heavy and horizontal light */
-        case 0x2539: /* box drawings right light and left up heavy */
-        case 0x253a: /* box drawings left light and right up heavy */
-        case 0x253b: /* box drawings heavy up and horizontal */
-        case 0x253c: /* box drawings light vertical and horizontal */
-        case 0x253d: /* box drawings left heavy and right vertical light */
-        case 0x253e: /* box drawings right heavy and left vertical light */
-        case 0x253f: /* box drawings vertical light and horizontal heavy */
-        case 0x2540: /* box drawings up heavy and down horizontal light */
-        case 0x2541: /* box drawings down heavy and up horizontal light */
-        case 0x2542: /* box drawings vertical heavy and horizontal light */
-        case 0x2543: /* box drawings left up heavy and right down light */
-        case 0x2544: /* box drawings right up heavy and left down light */
-        case 0x2545: /* box drawings left down heavy and right up light */
-        case 0x2546: /* box drawings right down heavy and left up light */
-        case 0x2547: /* box drawings down light and up horizontal heavy */
-        case 0x2548: /* box drawings up light and down horizontal heavy */
-        case 0x2549: /* box drawings right light and left vertical heavy */
-        case 0x254a: /* box drawings left light and right vertical heavy */
-        case 0x254b: /* box drawings heavy vertical and horizontal */
-        case 0x2550: /* box drawings double horizontal */
-        case 0x2551: /* box drawings double vertical */
-        case 0x2552: /* box drawings down single and right double */
-        case 0x2553: /* box drawings down double and right single */
-        case 0x2554: /* box drawings double down and right */
-        case 0x2555: /* box drawings down single and left double */
-        case 0x2556: /* box drawings down double and left single */
-        case 0x2557: /* box drawings double down and left */
-        case 0x2558: /* box drawings up single and right double */
-        case 0x2559: /* box drawings up double and right single */
-        case 0x255a: /* box drawings double up and right */
-        case 0x255b: /* box drawings up single and left double */
-        case 0x255c: /* box drawings up double and left single */
-        case 0x255d: /* box drawings double up and left */
-        case 0x255e: /* box drawings vertical single and right double */
-        case 0x255f: /* box drawings vertical double and right single */
-        case 0x2560: /* box drawings double vertical and right */
-        case 0x2561: /* box drawings vertical single and left double */
-        case 0x2562: /* box drawings vertical double and left single */
-        case 0x2563: /* box drawings double vertical and left */
-        case 0x2564: /* box drawings down single and horizontal double */
-        case 0x2565: /* box drawings down double and horizontal single */
-        case 0x2566: /* box drawings double down and horizontal */
-        case 0x2567: /* box drawings up single and horizontal double */
-        case 0x2568: /* box drawings up double and horizontal single */
-        case 0x2569: /* box drawings double up and horizontal */
-        case 0x256a: /* box drawings vertical single and horizontal double */
-        case 0x256b: /* box drawings vertical double and horizontal single */
-        case 0x256c: /* box drawings double vertical and horizontal */
-        case 0x2574: /* box drawings light left */
-        case 0x2575: /* box drawings light up */
-        case 0x2576: /* box drawings light right */
-        case 0x2577: /* box drawings light down */
-        case 0x2578: /* box drawings heavy left */
-        case 0x2579: /* box drawings heavy up */
-        case 0x257a: /* box drawings heavy right */
-        case 0x257b: /* box drawings heavy down */
-        case 0x257c: /* box drawings light left and heavy right */
-        case 0x257d: /* box drawings light up and heavy down */
-        case 0x257e: /* box drawings heavy left and light right */
-        case 0x257f: /* box drawings heavy up and light down */
-        {
-                guint32 bitmap = _vte_draw_box_drawing_bitmaps[c - 0x2500];
-                int xboundaries[6] = { 0,
-                                       left_half - heavy_line_width / 2,
-                                       left_half - light_line_width / 2,
-                                       left_half - light_line_width / 2 + light_line_width,
-                                       left_half - heavy_line_width / 2 + heavy_line_width,
-                                       width};
-                int yboundaries[6] = { 0,
-                                       upper_half - heavy_line_width / 2,
-                                       upper_half - light_line_width / 2,
-                                       upper_half - light_line_width / 2 + light_line_width,
-                                       upper_half - heavy_line_width / 2 + heavy_line_width,
-                                       height};
-                int xi, yi;
-                cairo_set_line_width(cr, 0);
-                for (yi = 4; yi >= 0; yi--) {
-                        for (xi = 4; xi >= 0; xi--) {
-                                if (bitmap & 1) {
-                                        cairo_rectangle(cr,
-                                                        x + xboundaries[xi],
-                                                        y + yboundaries[yi],
-                                                        xboundaries[xi + 1] - xboundaries[xi],
-                                                        yboundaries[yi + 1] - yboundaries[yi]);
-                                        cairo_fill(cr);
-                                }
-                                bitmap >>= 1;
-                        }
-                }
-                break;
-        }
-
-        case 0x2504: /* box drawings light triple dash horizontal */
-        case 0x2505: /* box drawings heavy triple dash horizontal */
-        case 0x2506: /* box drawings light triple dash vertical */
-        case 0x2507: /* box drawings heavy triple dash vertical */
-        case 0x2508: /* box drawings light quadruple dash horizontal */
-        case 0x2509: /* box drawings heavy quadruple dash horizontal */
-        case 0x250a: /* box drawings light quadruple dash vertical */
-        case 0x250b: /* box drawings heavy quadruple dash vertical */
-        case 0x254c: /* box drawings light double dash horizontal */
-        case 0x254d: /* box drawings heavy double dash horizontal */
-        case 0x254e: /* box drawings light double dash vertical */
-        case 0x254f: /* box drawings heavy double dash vertical */
-        {
-                const guint v = c - 0x2500;
-                int size, line_width;
-
-                size = (v & 2) ? height : width;
-
-                switch (v >> 2) {
-                case 1: /* triple dash */
-                {
-                        double segment = size / 8.;
-                        double dashes[2] = { segment * 2., segment };
-                        cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), 0.);
-                        break;
-                }
-                case 2: /* quadruple dash */
-                {
-                        double segment = size / 11.;
-                        double dashes[2] = { segment * 2., segment };
-                        cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), 0.);
-                        break;
-                }
-                case 19: /* double dash */
-                {
-                        double segment = size / 5.;
-                        double dashes[2] = { segment * 2., segment };
-                        cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), 0.);
-                        break;
-                }
-                }
-
-                line_width = (v & 1) ? heavy_line_width : light_line_width;
-                adjust = (line_width & 1) ? .5 : 0.;
-
-                cairo_set_line_width(cr, line_width);
-                cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
-                if (v & 2) {
-                        cairo_move_to(cr, xcenter + adjust, y);
-                        cairo_line_to(cr, xcenter + adjust, y + height);
-                } else {
-                        cairo_move_to(cr, x, ycenter + adjust);
-                        cairo_line_to(cr, x + width, ycenter + adjust);
-                }
-                cairo_stroke(cr);
-                break;
-        }
-
-        case 0x256d: /* box drawings light arc down and right */
-        case 0x256e: /* box drawings light arc down and left */
-        case 0x256f: /* box drawings light arc up and left */
-        case 0x2570: /* box drawings light arc up and right */
-        {
-                const guint v = c - 0x256d;
-                int line_width;
-                int radius;
-
-                cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
-
-                line_width = light_line_width;
-                adjust = (line_width & 1) ? .5 : 0.;
-                cairo_set_line_width(cr, line_width);
-
-                radius = (font_width + 2) / 3;
-                radius = MAX(radius, heavy_line_width);
-
-                if (v & 2) {
-                        cairo_move_to(cr, xcenter + adjust, y);
-                        cairo_line_to(cr, xcenter + adjust, ycenter - radius + 2 * adjust);
-                } else {
-                        cairo_move_to(cr, xcenter + adjust, ybottom);
-                        cairo_line_to(cr, xcenter + adjust, ycenter + radius);
-                }
-                cairo_stroke(cr);
-
-                cairo_arc(cr,
-                          (v == 1 || v == 2) ? xcenter - radius + 2 * adjust
-                                             : xcenter + radius,
-                          (v & 2) ? ycenter - radius + 2 * adjust
-                                  : ycenter + radius,
-                          radius - adjust,
-                          (v + 2) * M_PI / 2.0, (v + 3) * M_PI / 2.0);
-                cairo_stroke(cr);
-
-                if (v == 1 || v == 2) {
-                        cairo_move_to(cr, xcenter - radius + 2 * adjust, ycenter + adjust);
-                        cairo_line_to(cr, x, ycenter + adjust);
-                } else {
-                        cairo_move_to(cr, xcenter + radius, ycenter + adjust);
-                        cairo_line_to(cr, xright, ycenter + adjust);
-                }
-
-                cairo_stroke(cr);
-                break;
-        }
-
-        case 0x2571: /* box drawings light diagonal upper right to lower left */
-        case 0x2572: /* box drawings light diagonal upper left to lower right */
-        case 0x2573: /* box drawings light diagonal cross */
-        {
-                auto const dx = (light_line_width + 1) / 2;
-                cairo_rectangle(cr, x - dx, y, width + 2 * dx, height);
-                cairo_clip(cr);
-                cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
-                cairo_set_line_width(cr, light_line_width);
-                if (c != 0x2571) {
-                        cairo_move_to(cr, x, y);
-                        cairo_line_to(cr, xright, ybottom);
-                        cairo_stroke(cr);
-                }
-                if (c != 0x2572) {
-                        cairo_move_to(cr, xright, y);
-                        cairo_line_to(cr, x, ybottom);
-                        cairo_stroke(cr);
-                }
-                break;
-        }
-
-        /* Block Elements */
-        case 0x2580: /* upper half block */
-                rectangle(cr, x, y, width, height, 1, 2,  0, 0,  1, 1);
-                break;
-
-        case 0x2581: /* lower one eighth block */
-        case 0x2582: /* lower one quarter block */
-        case 0x2583: /* lower three eighths block */
-        case 0x2584: /* lower half block */
-        case 0x2585: /* lower five eighths block */
-        case 0x2586: /* lower three quarters block */
-        case 0x2587: /* lower seven eighths block */
-        {
-                const guint v = 0x2588 - c;
-                rectangle(cr, x, y, width, height, 1, 8,  0, v,  1, 8);
-                break;
-        }
-
-        case 0x2588: /* full block */
-        case 0x2589: /* left seven eighths block */
-        case 0x258a: /* left three quarters block */
-        case 0x258b: /* left five eighths block */
-        case 0x258c: /* left half block */
-        case 0x258d: /* left three eighths block */
-        case 0x258e: /* left one quarter block */
-        case 0x258f: /* left one eighth block */
-        {
-                const guint v = 0x2590 - c;
-                rectangle(cr, x, y, width, height, 8, 1,  0, 0,  v, 1);
-                break;
-        }
-
-        case 0x2590: /* right half block */
-                rectangle(cr, x, y, width, height, 2, 1,  1, 0,  2, 1);
-                break;
-
-        case 0x2591: /* light shade */
-        case 0x2592: /* medium shade */
-        case 0x2593: /* dark shade */
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       (c - 0x2590) / 4.);
-                cairo_rectangle(cr, x, y, width, height);
-                cairo_fill (cr);
-                break;
-
-        case 0x2594: /* upper one eighth block */
-        {
-                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, 1);
-                break;
-        }
-
-        case 0x2595: /* right one eighth block */
-        {
-                rectangle(cr, x, y, width, height, 8, 1,  7, 0,  8, 1);
-                break;
-        }
-
-        case 0x2596: /* quadrant lower left */
-                rectangle(cr, x, y, width, height, 2, 2,  0, 1,  1, 2);
-                break;
-
-        case 0x2597: /* quadrant lower right */
-                rectangle(cr, x, y, width, height, 2, 2,  1, 1,  2, 2);
-                break;
-
-        case 0x2598: /* quadrant upper left */
-                rectangle(cr, x, y, width, height, 2, 2,  0, 0,  1, 1);
-                break;
-
-        case 0x2599: /* quadrant upper left and lower left and lower right */
-                rectangle(cr, x, y, width, height, 2, 2,  0, 0,  1, 1);
-                rectangle(cr, x, y, width, height, 2, 2,  0, 1,  2, 2);
-                break;
-
-        case 0x259a: /* quadrant upper left and lower right */
-                rectangle(cr, x, y, width, height, 2, 2,  0, 0,  1, 1);
-                rectangle(cr, x, y, width, height, 2, 2,  1, 1,  2, 2);
-                break;
-
-        case 0x259b: /* quadrant upper left and upper right and lower left */
-                rectangle(cr, x, y, width, height, 2, 2,  0, 0,  2, 1);
-                rectangle(cr, x, y, width, height, 2, 2,  0, 1,  1, 2);
-                break;
-
-        case 0x259c: /* quadrant upper left and upper right and lower right */
-                rectangle(cr, x, y, width, height, 2, 2,  0, 0,  2, 1);
-                rectangle(cr, x, y, width, height, 2, 2,  1, 1,  2, 2);
-                break;
-
-        case 0x259d: /* quadrant upper right */
-                rectangle(cr, x, y, width, height, 2, 2,  1, 0,  2, 1);
-                break;
-
-        case 0x259e: /* quadrant upper right and lower left */
-                rectangle(cr, x, y, width, height, 2, 2,  1, 0,  2, 1);
-                rectangle(cr, x, y, width, height, 2, 2,  0, 1,  1, 2);
-                break;
-
-        case 0x259f: /* quadrant upper right and lower left and lower right */
-                rectangle(cr, x, y, width, height, 2, 2,  1, 0,  2, 1);
-                rectangle(cr, x, y, width, height, 2, 2,  0, 1,  2, 2);
-                break;
-
-        case 0x25e2: /* black lower right triangle */
-        {
-                static int8_t const coords[] = { 0, 1,  1, 0,  1, 1,  -1 };
-                polygon(cr, x, y, width, height, 1, 1, coords);
-                break;
-        }
-
-        case 0x25e3: /* black lower left triangle */
-        {
-                static int8_t const coords[] = { 0, 0,  1, 1,  0, 1,  -1 };
-                polygon(cr, x, y, width, height, 1, 1, coords);
-                break;
-        }
-
-        case 0x25e4: /* black upper left triangle */
-        {
-                static int8_t const coords[] = { 0, 0,  1, 0,  0, 1,  -1 };
-                polygon(cr, x, y, width, height, 1, 1, coords);
-                break;
-        }
-
-        case 0x25e5: /* black upper right triangle */
-        {
-                static int8_t const coords[] = { 0, 0,  1, 0,  1, 1,  -1 };
-                polygon(cr, x, y, width, height, 1, 1, coords);
-                break;
-        }
-
-        case 0x1fb00:
-        case 0x1fb01:
-        case 0x1fb02:
-        case 0x1fb03:
-        case 0x1fb04:
-        case 0x1fb05:
-        case 0x1fb06:
-        case 0x1fb07:
-        case 0x1fb08:
-        case 0x1fb09:
-        case 0x1fb0a:
-        case 0x1fb0b:
-        case 0x1fb0c:
-        case 0x1fb0d:
-        case 0x1fb0e:
-        case 0x1fb0f:
-        case 0x1fb10:
-        case 0x1fb11:
-        case 0x1fb12:
-        case 0x1fb13:
-        case 0x1fb14:
-        case 0x1fb15:
-        case 0x1fb16:
-        case 0x1fb17:
-        case 0x1fb18:
-        case 0x1fb19:
-        case 0x1fb1a:
-        case 0x1fb1b:
-        case 0x1fb1c:
-        case 0x1fb1d:
-        case 0x1fb1e:
-        case 0x1fb1f:
-        case 0x1fb20:
-        case 0x1fb21:
-        case 0x1fb22:
-        case 0x1fb23:
-        case 0x1fb24:
-        case 0x1fb25:
-        case 0x1fb26:
-        case 0x1fb27:
-        case 0x1fb28:
-        case 0x1fb29:
-        case 0x1fb2a:
-        case 0x1fb2b:
-        case 0x1fb2c:
-        case 0x1fb2d:
-        case 0x1fb2e:
-        case 0x1fb2f:
-        case 0x1fb30:
-        case 0x1fb31:
-        case 0x1fb32:
-        case 0x1fb33:
-        case 0x1fb34:
-        case 0x1fb35:
-        case 0x1fb36:
-        case 0x1fb37:
-        case 0x1fb38:
-        case 0x1fb39:
-        case 0x1fb3a:
-        case 0x1fb3b:
-        {
-                guint32 bitmap = c - 0x1fb00 + 1;
-                if (bitmap >= 0x15) bitmap++;
-                if (bitmap >= 0x2a) bitmap++;
-                int xi, yi;
-                cairo_set_line_width(cr, 0);
-                for (yi = 0; yi <= 2; yi++) {
-                        for (xi = 0; xi <= 1; xi++) {
-                                if (bitmap & 1) {
-                                        rectangle(cr, x, y, width, height, 2, 3,  xi, yi, xi + 1,  yi + 1);
-                                }
-                                bitmap >>= 1;
-                        }
-                }
-                break;
-        }
-
-        case 0x1fb3c:
-        case 0x1fb3d:
-        case 0x1fb3e:
-        case 0x1fb3f:
-        case 0x1fb40:
-        case 0x1fb41:
-        case 0x1fb42:
-        case 0x1fb43:
-        case 0x1fb44:
-        case 0x1fb45:
-        case 0x1fb46:
-        case 0x1fb47:
-        case 0x1fb48:
-        case 0x1fb49:
-        case 0x1fb4a:
-        case 0x1fb4b:
-        case 0x1fb4c:
-        case 0x1fb4d:
-        case 0x1fb4e:
-        case 0x1fb4f:
-        case 0x1fb50:
-        case 0x1fb51:
-        case 0x1fb52:
-        case 0x1fb53:
-        case 0x1fb54:
-        case 0x1fb55:
-        case 0x1fb56:
-        case 0x1fb57:
-        case 0x1fb58:
-        case 0x1fb59:
-        case 0x1fb5a:
-        case 0x1fb5b:
-        case 0x1fb5c:
-        case 0x1fb5d:
-        case 0x1fb5e:
-        case 0x1fb5f:
-        case 0x1fb60:
-        case 0x1fb61:
-        case 0x1fb62:
-        case 0x1fb63:
-        case 0x1fb64:
-        case 0x1fb65:
-        case 0x1fb66:
-        case 0x1fb67:
-        {
-                auto const v = c - 0x1fb3c;
-                static int8_t const coords[46][11] = {
-                        { 0, 2,  1, 3,  0, 3,  -1 },                /* 3c */
-                        { 0, 2,  2, 3,  0, 3,  -1 },                /* 3d */
-                        { 0, 1,  1, 3,  0, 3,  -1 },                /* 3e */
-                        { 0, 1,  2, 3,  0, 3,  -1 },                /* 3f */
-                        { 0, 0,  1, 3,  0, 3,  -1 },                /* 40 */
-                        { 0, 1,  1, 0,  2, 0,  2, 3,  0, 3,  -1 },  /* 41 */
-                        { 0, 1,  2, 0,  2, 3,  0, 3,  -1 },         /* 42 */
-                        { 0, 2,  1, 0,  2, 0,  2, 3,  0, 3,  -1 },  /* 43 */
-                        { 0, 2,  2, 0,  2, 3,  0, 3,  -1 },         /* 44 */
-                        { 0, 3,  1, 0,  2, 0,  2, 3,  -1 },         /* 45 */
-                        { 0, 2,  2, 1,  2, 3,  0, 3,  -1 },         /* 46 */
-                        { 1, 3,  2, 2,  2, 3,  -1 },                /* 47 */
-                        { 0, 3,  2, 2,  2, 3,  -1 },                /* 48 */
-                        { 1, 3,  2, 1,  2, 3,  -1 },                /* 49 */
-                        { 0, 3,  2, 1,  2, 3,  -1 },                /* 4a */
-                        { 1, 3,  2, 0,  2, 3,  -1 },                /* 4b */
-                        { 0, 0,  1, 0,  2, 1,  2, 3,  0, 3,  -1 },  /* 4c */
-                        { 0, 0,  2, 1,  2, 3,  0, 3,  -1 },         /* 4d */
-                        { 0, 0,  1, 0,  2, 2,  2, 3,  0, 3,  -1 },  /* 4e */
-                        { 0, 0,  2, 2,  2, 3,  0, 3,  -1 },         /* 4f */
-                        { 0, 0,  1, 0,  2, 3,  0, 3,  -1 },         /* 50 */
-                        { 0, 1,  2, 2,  2, 3,  0, 3,  -1 },         /* 51 */
-                        { 0, 0,  2, 0,  2, 3,  1, 3,  0, 2,  -1 },  /* 52 */
-                        { 0, 0,  2, 0,  2, 3,  0, 2,  -1 },         /* 53 */
-                        { 0, 0,  2, 0,  2, 3,  1, 3,  0, 1,  -1 },  /* 54 */
-                        { 0, 0,  2, 0,  2, 3,  0, 1,  -1 },         /* 55 */
-                        { 0, 0,  2, 0,  2, 3,  1, 3,  -1 },         /* 56 */
-                        { 0, 0,  1, 0,  0, 1,  -1 },                /* 57 */
-                        { 0, 0,  2, 0,  0, 1,  -1 },                /* 58 */
-                        { 0, 0,  1, 0,  0, 2,  -1 },                /* 59 */
-                        { 0, 0,  2, 0,  0, 2,  -1 },                /* 5a */
-                        { 0, 0,  1, 0,  0, 3,  -1 },                /* 5b */
-                        { 0, 0,  2, 0,  2, 1,  0, 2,  -1 },         /* 5c */
-                        { 0, 0,  2, 0,  2, 2,  1, 3,  0, 3,  -1 },  /* 5d */
-                        { 0, 0,  2, 0,  2, 2,  0, 3,  -1 },         /* 5e */
-                        { 0, 0,  2, 0,  2, 1,  1, 3,  0, 3,  -1 },  /* 5f */
-                        { 0, 0,  2, 0,  2, 1,  0, 3,  -1 },         /* 60 */
-                        { 0, 0,  2, 0,  1, 3,  0, 3,  -1 },         /* 61 */
-                        { 1, 0,  2, 0,  2, 1,  -1 },                /* 62 */
-                        { 0, 0,  2, 0,  2, 1,  -1 },                /* 63 */
-                        { 1, 0,  2, 0,  2, 2,  -1 },                /* 64 */
-                        { 0, 0,  2, 0,  2, 2,  -1 },                /* 65 */
-                        { 1, 0,  2, 0,  2, 3,  -1 },                /* 66 */
-                        { 0, 0,  2, 0,  2, 2,  0, 1,  -1 },         /* 67 */
-                };
-                polygon(cr, x, y, width, height, 2, 3, coords[v]);
-                break;
-        }
-
-        case 0x1fb68:
-        case 0x1fb69:
-        case 0x1fb6a:
-        case 0x1fb6b:
-        case 0x1fb6c:
-        case 0x1fb6d:
-        case 0x1fb6e:
-        case 0x1fb6f:
-        {
-                auto const v = c - 0x1fb68;
-                static int8_t const coords[8][11] = {
-                        { 0, 0,  2, 0,  2, 2,  0, 2,  1, 1,  -1 },  /* 68 */
-                        { 0, 0,  1, 1,  2, 0,  2, 2,  0, 2,  -1 },  /* 69 */
-                        { 0, 0,  2, 0,  1, 1,  2, 2,  0, 2,  -1 },  /* 6a */
-                        { 0, 0,  2, 0,  2, 2,  1, 1,  0, 2,  -1 },  /* 6b */
-                        { 0, 0,  1, 1,  0, 2,  -1 },                /* 6c */
-                        { 0, 0,  2, 0,  1, 1,  -1 },                /* 6d */
-                        { 1, 1,  2, 0,  2, 2,  -1 },                /* 6e */
-                        { 1, 1,  2, 2,  0, 2,  -1 },                /* 6f */
-                };
-                polygon(cr, x, y, width, height, 2, 2, coords[v]);
-                break;
-        }
-
-        case 0x1fb70:
-        case 0x1fb71:
-        case 0x1fb72:
-        case 0x1fb73:
-        case 0x1fb74:
-        case 0x1fb75:
-        {
-                auto const v = c - 0x1fb70 + 1;
-                rectangle(cr, x, y, width, height, 8, 1,  v, 0,  v + 1, 1);
-                break;
-        }
-
-        case 0x1fb76:
-        case 0x1fb77:
-        case 0x1fb78:
-        case 0x1fb79:
-        case 0x1fb7a:
-        case 0x1fb7b:
-        {
-                auto const v = c - 0x1fb76 + 1;
-                rectangle(cr, x, y, width, height, 1, 8,  0, v,  1, v + 1);
-                break;
-        }
-
-        case 0x1fb7c:
-                rectangle(cr, x, y, width, height, 1, 8,  0, 7,  1, 8);
-                rectangle(cr, x, y, width, height, 8, 1,  0, 0,  1, 1);
-                break;
-
-        case 0x1fb7d:
-                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, 1);
-                rectangle(cr, x, y, width, height, 8, 1,  0, 0,  1, 1);
-                break;
-
-        case 0x1fb7e:
-                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, 1);
-                rectangle(cr, x, y, width, height, 8, 1,  7, 0,  8, 1);
-                break;
-
-        case 0x1fb7f:
-                rectangle(cr, x, y, width, height, 1, 8,  0, 7,  1, 8);
-                rectangle(cr, x, y, width, height, 8, 1,  7, 0,  8, 1);
-                break;
-
-        case 0x1fb80:
-                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, 1);
-                rectangle(cr, x, y, width, height, 1, 8,  0, 7,  1, 8);
-                break;
-
-        case 0x1fb81:
-                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, 1);
-                rectangle(cr, x, y, width, height, 1, 8,  0, 2,  1, 3);
-                rectangle(cr, x, y, width, height, 1, 8,  0, 4,  1, 5);
-                rectangle(cr, x, y, width, height, 1, 8,  0, 7,  1, 8);
-                break;
-
-        case 0x1fb82:
-        case 0x1fb83:
-        case 0x1fb84:
-        case 0x1fb85:
-        case 0x1fb86:
-        {
-                auto v = c - 0x1fb82 + 2;
-                if (v >= 4) v++;
-                rectangle(cr, x, y, width, height, 1, 8,  0, 0,  1, v);
-                break;
-        }
-
-        case 0x1fb87:
-        case 0x1fb88:
-        case 0x1fb89:
-        case 0x1fb8a:
-        case 0x1fb8b:
-        {
-                auto v = c - 0x1fb87 + 2;
-                if (v >= 4) v++;
-                rectangle(cr, x, y, width, height, 8, 1,  8 - v, 0,  8, 1);
-                break;
-        }
-
-        case 0x1fb8c:
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                rectangle(cr, x, y, width, height, 2, 1,  0, 0,  1, 1);
-                break;
-
-        case 0x1fb8d:
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                rectangle(cr, x, y, width, height, 2, 1,  1, 0,  2, 1);
-                break;
-
-        case 0x1fb8e:
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                rectangle(cr, x, y, width, height, 1, 2,  0, 0,  1, 1);
-                break;
-
-        case 0x1fb8f:
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                rectangle(cr, x, y, width, height, 1, 2,  0, 1,  1, 2);
-                break;
-
-        case 0x1fb90:
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                rectangle(cr, x, y, width, height, 1, 1,  0, 0,  1, 1);
-                break;
-
-        case 0x1fb91:
-                rectangle(cr, x, y, width, height, 1, 2,  0, 0,  1, 1);
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                rectangle(cr, x, y, width, height, 1, 2,  0, 1,  1, 2);
-                break;
-
-        case 0x1fb92:
-                rectangle(cr, x, y, width, height, 1, 2,  0, 1,  1, 2);
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                rectangle(cr, x, y, width, height, 1, 2,  0, 0,  1, 1);
-                break;
-
-        case 0x1fb93:
-#if 0
-                /* codepoint not assigned */
-                rectangle(cr, x, y, width, height, 2, 1,  0, 0,  1, 1);
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                rectangle(cr, x, y, width, height, 2, 1,  1, 0,  2, 1);
-#endif
-                break;
-
-        case 0x1fb94:
-                rectangle(cr, x, y, width, height, 2, 1,  1, 0,  2, 1);
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                rectangle(cr, x, y, width, height, 2, 1,  0, 0,  1, 1);
-                break;
-
-        case 0x1fb95:
-                pattern(cr, create_checkerboard_pattern(), x, y, width, height);
-                break;
-
-        case 0x1fb96:
-                pattern(cr, create_checkerboard_reverse_pattern(), x, y, width, height);
-                break;
-
-        case 0x1fb97:
-                rectangle(cr, x, y, width, height, 1, 4,  0, 1,  1, 2);
-                rectangle(cr, x, y, width, height, 1, 4,  0, 3,  1, 4);
-                break;
-
-        case 0x1fb98:
-                pattern(cr, create_hatching_pattern_lr(), x, y, width, height);
-                break;
-
-        case 0x1fb99:
-                pattern(cr, create_hatching_pattern_rl(), x, y, width, height);
-                break;
-
-        case 0x1fb9a:
-        {
-                static int8_t const coords[] = { 0, 0,  1, 0,  0, 1,  1, 1,  -1 };
-                polygon(cr, x, y, width, height, 1, 1, coords);
-                break;
-        }
-
-        case 0x1fb9b:
-        {
-                static int8_t coords[] = { 0, 0,  1, 1,  1, 0,  0, 1,  -1 };
-                polygon(cr, x, y, width, height, 1, 1, coords);
-                break;
-        }
-
-        case 0x1fb9c:
-        {
-                static int8_t const coords[] = { 0, 0,  1, 0,  0, 1,  -1 };
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                polygon(cr, x, y, width, height, 1, 1, coords);
-                break;
-        }
-
-        case 0x1fb9d:
-        {
-                static int8_t const coords[] = { 0, 0,  1, 0,  1, 1,  -1 };
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                polygon(cr, x, y, width, height, 1, 1, coords);
-                break;
-        }
-
-        case 0x1fb9e:
-        {
-                static int8_t const coords[] = { 0, 1,  1, 0,  1, 1,  -1 };
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                polygon(cr, x, y, width, height, 1, 1, coords);
-                break;
-        }
-
-        case 0x1fb9f:
-        {
-                static int8_t const coords[] = { 0, 0,  1, 1,  0, 1,  -1 };
-                cairo_set_source_rgba (cr,
-                                       fg->red / 65535.,
-                                       fg->green / 65535.,
-                                       fg->blue / 65535.,
-                                       0.5);
-                polygon(cr, x, y, width, height, 1, 1, coords);
-                break;
-        }
-
-        case 0x1fba0:
-        case 0x1fba1:
-        case 0x1fba2:
-        case 0x1fba3:
-        case 0x1fba4:
-        case 0x1fba5:
-        case 0x1fba6:
-        case 0x1fba7:
-        case 0x1fba8:
-        case 0x1fba9:
-        case 0x1fbaa:
-        case 0x1fbab:
-        case 0x1fbac:
-        case 0x1fbad:
-        case 0x1fbae:
-        {
-                auto const v = c - 0x1fba0;
-                static uint8_t const map[15] = { 0b0001, 0b0010, 0b0100, 0b1000, 0b0101, 0b1010, 0b1100, 
0b0011,
-                                                 0b1001, 0b0110, 0b1110, 0b1101, 0b1011, 0b0111, 0b1111 };
-                cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
-                cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
-                cairo_set_line_width(cr, light_line_width);
-                adjust = (light_line_width & 1) ? .5 : 0.;
-                double const dx = light_line_width / 2.;
-                double const dy = light_line_width / 2.;
-                if (map[v] & 1) {
-                        /* upper left */
-                        cairo_move_to(cr, x, ycenter + adjust);
-                        cairo_line_to(cr, x + dx, ycenter + adjust);
-                        cairo_line_to(cr, xcenter + adjust, y + dy);
-                        cairo_line_to(cr, xcenter + adjust, y);
-                        cairo_stroke(cr);
-                }
-                if (map[v] & 2) {
-                        /* upper right */
-                        cairo_move_to(cr, xright, ycenter + adjust);
-                        cairo_line_to(cr, xright - dx, ycenter + adjust);
-                        cairo_line_to(cr, xcenter + adjust, y + dy);
-                        cairo_line_to(cr, xcenter + adjust, y);
-                        cairo_stroke(cr);
-                }
-                if (map[v] & 4) {
-                        /* lower left */
-                        cairo_move_to(cr, x, ycenter + adjust);
-                        cairo_line_to(cr, x + dx, ycenter + adjust);
-                        cairo_line_to(cr, xcenter + adjust, ybottom - dy);
-                        cairo_line_to(cr, xcenter + adjust, ybottom);
-                        cairo_stroke(cr);
-                }
-                if (map[v] & 8) {
-                        /* lower right */
-                        cairo_move_to(cr, xright, ycenter + adjust);
-                        cairo_line_to(cr, xright - dx, ycenter + adjust);
-                        cairo_line_to(cr, xcenter + adjust, ybottom - dy);
-                        cairo_line_to(cr, xcenter + adjust, ybottom);
-                        cairo_stroke(cr);
-                }
-                break;
-        }
-
-        default:
-                g_assert_not_reached();
-        }
-
-        cairo_restore(cr);
-}
-
 void
 DrawingContext::draw_text_internal(TextRequest* requests,
                                    gsize n_requests,
@@ -1395,8 +302,9 @@ DrawingContext::draw_text_internal(TextRequest* requests,
                         vte_bidi_get_mirror_char (c, requests[i].box_mirror, &c);
                 }
 
-                if (unichar_is_local_graphic(c)) {
-                        draw_graphic(c,
+                if (m_minifont.unistr_is_local_graphic(c)) {
+                        m_minifont.draw_graphic(*this,
+                                                c,
                                                         attr,
                                                         color,
                                                         requests[i].x, requests[i].y,
diff --git a/src/vtedraw.hh b/src/vtedraw.hh
index 2b435b88..f932488d 100644
--- a/src/vtedraw.hh
+++ b/src/vtedraw.hh
@@ -28,6 +28,8 @@
 #include "vteunistr.h"
 #include "vtetypes.hh"
 
+#include "minifont.hh"
+
 #define VTE_DRAW_OPAQUE (1.0)
 
 #define VTE_DRAW_NORMAL 0
@@ -66,6 +68,7 @@ public:
         DrawingContext& operator=(DrawingContext&&) = delete;
 
         void set_cairo(cairo_t* cr) noexcept;
+        auto cairo() const noexcept { return m_cr; }
 
         void clip(cairo_rectangle_int_t const* rect);
         void unclip();
@@ -133,6 +136,9 @@ public:
                             vte::color::rgb const* color,
                             double alpha);
 
+        auto cell_width()  const noexcept { return m_cell_width; }
+        auto cell_height() const noexcept { return m_cell_height; }
+
 private:
         void set_source_color_alpha (vte::color::rgb const* color,
                                      double alpha);
@@ -159,6 +165,8 @@ private:
 
        cairo_t *m_cr{nullptr}; // unowned
 
+        Minifont m_minifont{};
+
         /* Cache the undercurl's rendered look. */
         std::unique_ptr<cairo_surface_t, decltype(&cairo_surface_destroy)> m_undercurl_surface{nullptr, 
nullptr};
 }; // class DrawingContext


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