[vte/wip/l2-21235: 4/7] minifont: Implement separated block sextants
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte/wip/l2-21235: 4/7] minifont: Implement separated block sextants
- Date: Thu, 7 Apr 2022 14:50:22 +0000 (UTC)
commit 9289f526ffd07308e4686ef2b853a286029cb06f
Author: Christian Persch <chpe src gnome org>
Date: Thu Apr 7 16:44:09 2022 +0200
minifont: Implement separated block sextants
src/minifont.cc | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 132 insertions(+), 10 deletions(-)
---
diff --git a/src/minifont.cc b/src/minifont.cc
index b26a67d1..fb106430 100644
--- a/src/minifont.cc
+++ b/src/minifont.cc
@@ -125,6 +125,43 @@ quadrant(cairo_t* cr,
cairo_fill(cr);
}
+inline void
+sextant(cairo_t* cr,
+ uint8_t value,
+ int x,
+ int y,
+ int width,
+ int height) noexcept
+{
+ if (width < 2 || height < 3)
+ [[unlikely]] return; // nothing to draw
+
+ auto const width_half = width / 2;
+ auto const height_third = height / 3;
+ auto const extra_height = height % 3 ? 1 : 0;
+
+ auto row = [&](uint8_t v,
+ int y0,
+ int h) noexcept
+ {
+ if (v & 0b01u)
+ cairo_rectangle(cr, x, y0, width_half, h);
+ if (v & 0b10u)
+ cairo_rectangle(cr, x + width_half, y0, width - width_half, h);
+ };
+
+ cairo_set_line_width(cr, 0);
+
+ // If height isn't divisibly by 3, distribute the extra pixels to
+ // the middle first, then the bottom.
+
+ int const yd[4] = {0, height_third, height_third * 2 + extra_height, height};
+ row(value, y, yd[1] - yd[0]);
+ row(value >> 2, y + yd[1], yd[2] - yd[1]);
+ row(value >> 4, y + yd[2], yd[3] - yd[2]);
+ cairo_fill(cr);
+}
+
static void
polygon(cairo_t* cr,
double x,
@@ -231,6 +268,92 @@ create_quadrant_separation_pattern(int width,
return pattern;
}
+inline vte::Freeable<cairo_pattern_t>
+create_sextant_separation_pattern(int width,
+ int height,
+ int line_thickness)
+{
+ auto surface = vte::take_freeable(cairo_image_surface_create(CAIRO_FORMAT_A1, width, height));
+ // or CAIRO_FORMAT_A8, whichever is better/faster?
+
+ auto cr = vte::take_freeable(cairo_create(surface.get()));
+
+ /* It's not quite clear how the separated mosaics should be drawn.
+ *
+ * ITU-T T.101 Annex C, C.2.1.2, and Annex D, D.5.4, show the separation
+ * being done by blanking a line on the left and bottom parts only of each
+ * of the 3x2 blocks.
+ * The minitel specification STUM 1B, Schéma 2.7 also shows them drawn that
+ * way.
+ *
+ * On the other hand, ETS 300 706 §15.7.1, Table 47, shows the separation
+ * being done by blanking a line around all four sides of each of the
+ * 3x2 blocks.
+ * That is also how ITU-T T.100 §5.4.2.1, Figure 6, shows the separation.
+ *
+ * Each of these has its own drawbacks. The T.101 way makes the 3x2 blocks
+ * asymmetric, leaving differing amount of lit pixels for the smooth mosaics
+ * comparing a mosaic with its corresponding vertically mirrored mosaic. It
+ * keeps more lit pixels overall, which make it more suitable for low-resolution
+ * display, which is probably why minitel uses that.
+ * The ETS 300 706 way keeps symmetry, but removes even more lit pixels.
+ *
+ * Here we implement the T.101 way.
+ */
+
+ /* FIXMEchpe: Check that this fulfills [T.101 Appendix IV]:
+ * "All separated and contiguous mosaics shall be uniquely presented for character
+ * field sizes greater than or equal to dx = 6/256, dy = 8/256 [see D.8.3.3, item 7)]."
+ */
+
+ /* First, fill completely with transparent pixels */
+ cairo_set_source_rgba(cr.get(), 0., 0., 0., 0.);
+ cairo_rectangle(cr.get(), 0, 0, width, height);
+ cairo_fill(cr.get());
+
+ /* Now, fill the reduced blocks with opaque pixels */
+
+ auto const pel = line_thickness; /* see T.101 D.5.3.2.2.6 for definition of 'logical pel' */
+
+ cairo_set_line_width(cr.get(), 0);
+
+ // If height isn't divisibly by 3, distribute the extra pixels to
+ // the middle first, then the bottom.
+
+ if (width > 2 * pel && height > 3 * pel) [[likely]] {
+
+ auto const width_half = width / 2;
+ auto const height_third = height / 3;
+ auto const extra_height = height % 3 ? 1 : 0;
+
+ // Just like in sextant() above,
+ // if height isn't divisibly by 3, distribute the extra pixels to
+ // the middle first, then the bottom.
+
+ int const y[] = {0, height_third, height_third * 2 + extra_height, height};
+ int const x[] = { 0, width_half, width };
+ // FIXMEchpe: or use 2 * width_half instead of width, so that for width odd,
+ // the extra row of pixels is unlit, and the lit blocks have equal width?
+
+ cairo_set_source_rgba(cr.get(), 0., 0., 0., 1.);
+
+ for (auto yi = 0; yi < 3; ++yi) {
+ for (auto xi = 0; xi < 2; xi++) {
+ cairo_rectangle(cr.get(), x[xi] + pel, y[yi], x[xi+1] - x[xi] - pel, y[yi+1]
- y[yi] - pel);
+ }
+ }
+ }
+
+ cairo_fill(cr.get());
+
+ auto pattern = vte::take_freeable(cairo_pattern_create_for_surface(surface.get()));
+
+ cairo_pattern_set_extend(pattern.get(), CAIRO_EXTEND_REPEAT);
+ cairo_pattern_set_filter(pattern.get(), CAIRO_FILTER_NEAREST);
+
+ return pattern;
+}
+
#include "box_drawing.h"
namespace vte::view {
@@ -751,16 +874,7 @@ Minifont::draw_graphic(DrawingContext const& context,
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;
- }
- }
+ sextant(cr, bitmap, x, y, width, height);
break;
}
@@ -1203,6 +1317,14 @@ Minifont::draw_graphic(DrawingContext const& context,
break;
}
+ case 0x1ce51 ... 0x1ce8f: { /* separated block sextant-* */
+ cairo_push_group(cr);
+ sextant(cr, c - 0x1ce50, x, y, width, height);
+ cairo_pop_group_to_source(cr);
+ cairo_mask(cr, create_sextant_separation_pattern(width, height, light_line_width).get());
+ break;
+ }
+
default:
cairo_set_source_rgba (cr, 1., 0., 1., 1.);
cairo_rectangle(cr, x, y, width, height);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]