/*
* 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 Lesser General Public License
* along with this library. If not, see .
*/
#include "config.h"
#include
#include "cairo-glue.hh"
#include "drawing-cairo.hh"
#include "minifont.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(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);
}
inline void
quadrant(cairo_t* cr,
uint8_t value,
int x,
int y,
int width,
int height) noexcept
{
auto const width_half = std::max(width / 2, 1);
auto const height_half = std::max(height / 2, 1);
cairo_set_line_width(cr, 0);
if (value & 0b0001u)
cairo_rectangle(cr, x, y, width_half, height_half);
if (value & 0b0010u)
cairo_rectangle(cr, x + width_half, y, width - width_half, height_half);
if (value & 0b0100u)
cairo_rectangle(cr, x, y + height_half, width_half, height - height_half);
if (value & 0b1000u)
cairo_rectangle(cr, x + width_half, y + height_half, width - width_half, height - height_half);
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);
}
inline void
octant(cairo_t* cr,
uint8_t value,
int x,
int y,
int width,
int height) noexcept
{
if (width < 2 || height < 4)
[[unlikely]] return; // nothing to draw
auto const width_half = width / 2;
auto const height_quarter = height / 4;
auto const extra_height = height % 4;
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 4, distribute the extra pixels to
// the 3rd row first, then the 2nd, then the 4th.
// FIXME: make sure this connects correctly with the one-eights
// as well as the quarter blocks.
int const heights[4] = {
height_quarter,
height_quarter + (extra_height > 2 ? 1 : 0),
height_quarter + (extra_height ? 1 : 0),
height_quarter + (extra_height > 1 ? 1 : 0)
};
for (auto i = 0; i < 4; ++i) {
row(value, y, heights[i]);
value >>= 2;
y += heights[i];
}
cairo_fill(cr);
}
inline constexpr int
scanline_y(int value,
int height,
int line_width) noexcept
{
/* There are 9 scanlines, but only the odd scanlines (1, 3, 5, 7,
* and 9) are actually in unicode.
* To get the space assigned to each scanline, we divide the
* height by 9 and distribute the remainder space in this order:
* scanline 5, 4, 7, 2, 6, 3, 8, 1.
* This ensures that the remainder is added first to the bottom
* half towards the centre, and that the spacing between the odd
* scanlines are at most 1px different.
*
* Since scanline 5 is unified with U+2500 BOX DRAWINGS LIGHT HORIZONTAL,
* the other scanlines are aligned so that scanline 5 coincides with
* U+2500, that is, has y position upper_half - light_line_width / 2.
*/
// FIMXE: this doesn't work for height < 9. Since we only need the odd
// scanlines, we can make this work fine for height = 5..8, but for
// heights < 5, need to still at least align 1 to top, 5 to middle, and
// 9 to bottom
auto const h = height / 9;
auto const r = height % 9;
auto y = height / 2 - line_width / 2 + (value - 5) * h;
auto extra = [&r](int v) constexpr noexcept -> auto { return r >= v ? 1 : 0; };
switch (value) {
case 1: y -= extra(8); [[fallthrough]];
case 2: y -= extra(4); [[fallthrough]];
case 3: y -= extra(6); [[fallthrough]];
case 4: y -= extra(2); [[fallthrough]];
case 5: break;
case 9: y += extra(7); [[fallthrough]];
case 8: y += extra(3); [[fallthrough]];
case 7: y += extra(5); [[fallthrough]];
case 6: y += extra(1); break;
default: __builtin_unreachable(); break;
}
return y;
}
inline void
scanline(cairo_t* cr,
int value,
int x,
int y,
int width,
int height,
int line_width) noexcept
{
cairo_rectangle(cr,
x,
y + scanline_y(value, height, line_width),
width,
line_width);
cairo_fill(cr);
}
inline void
circle_segment(cairo_t* cr,
int x,
int y,
int width,
int height,
int line_width,
int dx,
int dy,
int r) noexcept
{
// The naive way to draw the ellipse would lead to non-uniform stroke
// width. To make the stroke width uniform, restore the transformation
// before stroking. See https://www.cairographics.org/cookbook/ellipses/
cairo_rectangle(cr, x, y, width, height);
cairo_clip(cr);
auto matrix = cairo_matrix_t{};
cairo_get_matrix(cr, &matrix);
cairo_translate(cr, x + dx * width, y + dy * height);
cairo_scale(cr, 1., double(height) / double(width));
cairo_new_path(cr);
cairo_arc(cr,
0., 0., // centre
r * width - line_width, // radius
0., // start angle
2. * M_PI); // end angle
cairo_set_matrix(cr, &matrix);
cairo_set_line_width(cr, line_width);
cairo_stroke(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);
}
/* Create separated mosaic patterns.
* Transparent pixels will not be drawn; opaque pixels will draw that part of the
* mosaic onto the target surface.
*/
inline vte::Freeable
create_quadrant_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 quadrants should be drawn.
*
* The L2/21-235 Sources document shows the separation being drawn as
* blanking a line on the left and top parts of each 2x2 block.
*
* Here, we blank a line on the left and *bottom* of each 2x2 block,
* for consistency with how we draw the separated sextants / mosaics,
* see below.
*/
/* 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 the separated sextants below */
cairo_set_source_rgba(cr.get(), 0., 0., 0., 1.);
if (width > 2 * pel && height > 2 * pel) {
auto const width_half = width / 2;
auto const height_half = height / 2;
int const y[3] = { 0, height_half, height };
int const x[3] = { 0, width_half, width };
// FIXMEchpe: or use 2 * width_half instead of width, so that for width odd,
// the extra row of pixels is unlit, and the lit blocks have equal width?
// and similar for height?
for (auto yi = 0; yi < 2; ++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;
}
inline vte::Freeable
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 {
/* 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) {
case 0x23b8: /* LEFT VERTICAL BOX LINE */
cairo_rectangle(cr,
x, y,
light_line_width, height);
cairo_fill(cr);
break;
case 0x23b9: /* RIGHT VERTICAL BOX LINE */
cairo_rectangle(cr,
x + width - light_line_width, y,
light_line_width, height);
cairo_fill(cr);
break;
case 0x23ba: /* HORIZONTAL SCAN LINE-1 */
scanline(cr, 1, x, y, width, height, light_line_width);
break;
case 0x23bb: /* HORIZONTAL SCAN LINE-3 */
scanline(cr, 3, x, y, width, height, light_line_width);
break;
/* Note: HORIZONTAL SCAN LINE-5 is unified with U+2500 BOX DRAWINGS LIGHT HORIZONTAL */
case 0x23bc: /* HORIZONTAL SCAN LINE-7 */
scanline(cr, 7, x, y, width, height, light_line_width);
break;
case 0x23bd: /* HORIZONTAL SCAN LINE-9 */
scanline(cr, 9, x, y, width, height, light_line_width);
break;
/* 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++;
sextant(cr, bitmap, x, y, width, height);
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;
}
case 0x1cc21 ... 0x1cc2f: { /* separated block quadrant-* */
cairo_push_group(cr);
quadrant(cr, c - 0x1cc10, x, y, width, height);
cairo_pop_group_to_source(cr);
cairo_mask(cr, create_quadrant_separation_pattern(width, height, light_line_width).get());
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;
}
case 0x1cd00 ... 0x1cde5: { /* block octant-* */
static constinit uint8_t const octant_value [] = {
0b0000'0100, /* U+1CD00 BLOCK OCTANT-3 */
0b0000'0110, /* U+1CD01 BLOCK OCTANT-23 */
0b0000'0111, /* U+1CD02 BLOCK OCTANT-123 */
0b0000'1000, /* U+1CD03 BLOCK OCTANT-4 */
0b0000'1001, /* U+1CD04 BLOCK OCTANT-14 */
0b0000'1011, /* U+1CD05 BLOCK OCTANT-124 */
0b0000'1100, /* U+1CD06 BLOCK OCTANT-34 */
0b0000'1101, /* U+1CD07 BLOCK OCTANT-134 */
0b0000'1110, /* U+1CD08 BLOCK OCTANT-234 */
0b0001'0000, /* U+1CD09 BLOCK OCTANT-5 */
0b0001'0001, /* U+1CD0A BLOCK OCTANT-15 */
0b0001'0010, /* U+1CD0B BLOCK OCTANT-25 */
0b0001'0011, /* U+1CD0C BLOCK OCTANT-125 */
0b0001'0101, /* U+1CD0D BLOCK OCTANT-135 */
0b0001'0110, /* U+1CD0E BLOCK OCTANT-235 */
0b0001'0111, /* U+1CD0F BLOCK OCTANT-1235 */
0b0001'1000, /* U+1CD10 BLOCK OCTANT-45 */
0b0001'1001, /* U+1CD11 BLOCK OCTANT-145 */
0b0001'1010, /* U+1CD12 BLOCK OCTANT-245 */
0b0001'1011, /* U+1CD13 BLOCK OCTANT-1245 */
0b0001'1100, /* U+1CD14 BLOCK OCTANT-345 */
0b0001'1101, /* U+1CD15 BLOCK OCTANT-1345 */
0b0001'1110, /* U+1CD16 BLOCK OCTANT-2345 */
0b0001'1111, /* U+1CD17 BLOCK OCTANT-12345 */
0b0010'0000, /* U+1CD18 BLOCK OCTANT-6 */
0b0010'0001, /* U+1CD19 BLOCK OCTANT-16 */
0b0010'0010, /* U+1CD1A BLOCK OCTANT-26 */
0b0010'0011, /* U+1CD1B BLOCK OCTANT-126 */
0b0010'0100, /* U+1CD1C BLOCK OCTANT-36 */
0b0010'0101, /* U+1CD1D BLOCK OCTANT-136 */
0b0010'0110, /* U+1CD1E BLOCK OCTANT-236 */
0b0010'0111, /* U+1CD1F BLOCK OCTANT-1236 */
0b0010'1001, /* U+1CD20 BLOCK OCTANT-146 */
0b0010'1010, /* U+1CD21 BLOCK OCTANT-246 */
0b0010'1011, /* U+1CD22 BLOCK OCTANT-1246 */
0b0010'1100, /* U+1CD23 BLOCK OCTANT-346 */
0b0010'1101, /* U+1CD24 BLOCK OCTANT-1346 */
0b0010'1110, /* U+1CD25 BLOCK OCTANT-2346 */
0b0010'1111, /* U+1CD26 BLOCK OCTANT-12346 */
0b0011'0000, /* U+1CD27 BLOCK OCTANT-56 */
0b0011'0001, /* U+1CD28 BLOCK OCTANT-156 */
0b0011'0010, /* U+1CD29 BLOCK OCTANT-256 */
0b0011'0011, /* U+1CD2A BLOCK OCTANT-1256 */
0b0011'0100, /* U+1CD2B BLOCK OCTANT-356 */
0b0011'0101, /* U+1CD2C BLOCK OCTANT-1356 */
0b0011'0110, /* U+1CD2D BLOCK OCTANT-2356 */
0b0011'0111, /* U+1CD2E BLOCK OCTANT-12356 */
0b0011'1000, /* U+1CD2F BLOCK OCTANT-456 */
0b0011'1001, /* U+1CD30 BLOCK OCTANT-1456 */
0b0011'1010, /* U+1CD31 BLOCK OCTANT-2456 */
0b0011'1011, /* U+1CD32 BLOCK OCTANT-12456 */
0b0011'1100, /* U+1CD33 BLOCK OCTANT-3456 */
0b0011'1101, /* U+1CD34 BLOCK OCTANT-13456 */
0b0011'1110, /* U+1CD35 BLOCK OCTANT-23456 */
0b0100'0001, /* U+1CD36 BLOCK OCTANT-17 */
0b0100'0010, /* U+1CD37 BLOCK OCTANT-27 */
0b0100'0011, /* U+1CD38 BLOCK OCTANT-127 */
0b0100'0100, /* U+1CD39 BLOCK OCTANT-37 */
0b0100'0101, /* U+1CD3A BLOCK OCTANT-137 */
0b0100'0110, /* U+1CD3B BLOCK OCTANT-237 */
0b0100'0111, /* U+1CD3C BLOCK OCTANT-1237 */
0b0100'1000, /* U+1CD3D BLOCK OCTANT-47 */
0b0100'1001, /* U+1CD3E BLOCK OCTANT-147 */
0b0100'1010, /* U+1CD3F BLOCK OCTANT-247 */
0b0100'1011, /* U+1CD40 BLOCK OCTANT-1247 */
0b0100'1100, /* U+1CD41 BLOCK OCTANT-347 */
0b0100'1101, /* U+1CD42 BLOCK OCTANT-1347 */
0b0100'1110, /* U+1CD43 BLOCK OCTANT-2347 */
0b0100'1111, /* U+1CD44 BLOCK OCTANT-12347 */
0b0101'0001, /* U+1CD45 BLOCK OCTANT-157 */
0b0101'0010, /* U+1CD46 BLOCK OCTANT-257 */
0b0101'0011, /* U+1CD47 BLOCK OCTANT-1257 */
0b0101'0100, /* U+1CD48 BLOCK OCTANT-357 */
0b0101'0110, /* U+1CD49 BLOCK OCTANT-2357 */
0b0101'0111, /* U+1CD4A BLOCK OCTANT-12357 */
0b0101'1000, /* U+1CD4B BLOCK OCTANT-457 */
0b0101'1001, /* U+1CD4C BLOCK OCTANT-1457 */
0b0101'1011, /* U+1CD4D BLOCK OCTANT-12457 */
0b0101'1100, /* U+1CD4E BLOCK OCTANT-3457 */
0b0101'1101, /* U+1CD4F BLOCK OCTANT-13457 */
0b0101'1110, /* U+1CD50 BLOCK OCTANT-23457 */
0b0110'0000, /* U+1CD51 BLOCK OCTANT-67 */
0b0110'0001, /* U+1CD52 BLOCK OCTANT-167 */
0b0110'0010, /* U+1CD53 BLOCK OCTANT-267 */
0b0110'0011, /* U+1CD54 BLOCK OCTANT-1267 */
0b0110'0100, /* U+1CD55 BLOCK OCTANT-367 */
0b0110'0101, /* U+1CD56 BLOCK OCTANT-1367 */
0b0110'0110, /* U+1CD57 BLOCK OCTANT-2367 */
0b0110'0111, /* U+1CD58 BLOCK OCTANT-12367 */
0b0110'1000, /* U+1CD59 BLOCK OCTANT-467 */
0b0110'1001, /* U+1CD5A BLOCK OCTANT-1467 */
0b0110'1010, /* U+1CD5B BLOCK OCTANT-2467 */
0b0110'1011, /* U+1CD5C BLOCK OCTANT-12467 */
0b0110'1100, /* U+1CD5D BLOCK OCTANT-3467 */
0b0110'1101, /* U+1CD5E BLOCK OCTANT-13467 */
0b0110'1110, /* U+1CD5F BLOCK OCTANT-23467 */
0b0110'1111, /* U+1CD60 BLOCK OCTANT-123467 */
0b0111'0000, /* U+1CD61 BLOCK OCTANT-567 */
0b0111'0001, /* U+1CD62 BLOCK OCTANT-1567 */
0b0111'0010, /* U+1CD63 BLOCK OCTANT-2567 */
0b0111'0011, /* U+1CD64 BLOCK OCTANT-12567 */
0b0111'0100, /* U+1CD65 BLOCK OCTANT-3567 */
0b0111'0101, /* U+1CD66 BLOCK OCTANT-13567 */
0b0111'0110, /* U+1CD67 BLOCK OCTANT-23567 */
0b0111'0111, /* U+1CD68 BLOCK OCTANT-123567 */
0b0111'1000, /* U+1CD69 BLOCK OCTANT-4567 */
0b0111'1001, /* U+1CD6A BLOCK OCTANT-14567 */
0b0111'1010, /* U+1CD6B BLOCK OCTANT-24567 */
0b0111'1011, /* U+1CD6C BLOCK OCTANT-124567 */
0b0111'1100, /* U+1CD6D BLOCK OCTANT-34567 */
0b0111'1101, /* U+1CD6E BLOCK OCTANT-134567 */
0b0111'1110, /* U+1CD6F BLOCK OCTANT-234567 */
0b0111'1111, /* U+1CD70 BLOCK OCTANT-1234567 */
0b1000'0001, /* U+1CD71 BLOCK OCTANT-18 */
0b1000'0010, /* U+1CD72 BLOCK OCTANT-28 */
0b1000'0011, /* U+1CD73 BLOCK OCTANT-128 */
0b1000'0100, /* U+1CD74 BLOCK OCTANT-38 */
0b1000'0101, /* U+1CD75 BLOCK OCTANT-138 */
0b1000'0110, /* U+1CD76 BLOCK OCTANT-238 */
0b1000'0111, /* U+1CD77 BLOCK OCTANT-1238 */
0b1000'1000, /* U+1CD78 BLOCK OCTANT-48 */
0b1000'1001, /* U+1CD79 BLOCK OCTANT-148 */
0b1000'1010, /* U+1CD7A BLOCK OCTANT-248 */
0b1000'1011, /* U+1CD7B BLOCK OCTANT-1248 */
0b1000'1100, /* U+1CD7C BLOCK OCTANT-348 */
0b1000'1101, /* U+1CD7D BLOCK OCTANT-1348 */
0b1000'1110, /* U+1CD7E BLOCK OCTANT-2348 */
0b1000'1111, /* U+1CD7F BLOCK OCTANT-12348 */
0b1001'0000, /* U+1CD80 BLOCK OCTANT-58 */
0b1001'0001, /* U+1CD81 BLOCK OCTANT-158 */
0b1001'0010, /* U+1CD82 BLOCK OCTANT-258 */
0b1001'0011, /* U+1CD83 BLOCK OCTANT-1258 */
0b1001'0100, /* U+1CD84 BLOCK OCTANT-358 */
0b1001'0101, /* U+1CD85 BLOCK OCTANT-1358 */
0b1001'0110, /* U+1CD86 BLOCK OCTANT-2358 */
0b1001'0111, /* U+1CD87 BLOCK OCTANT-12358 */
0b1001'1000, /* U+1CD88 BLOCK OCTANT-458 */
0b1001'1001, /* U+1CD89 BLOCK OCTANT-1458 */
0b1001'1010, /* U+1CD8A BLOCK OCTANT-2458 */
0b1001'1011, /* U+1CD8B BLOCK OCTANT-12458 */
0b1001'1100, /* U+1CD8C BLOCK OCTANT-3458 */
0b1001'1101, /* U+1CD8D BLOCK OCTANT-13458 */
0b1001'1110, /* U+1CD8E BLOCK OCTANT-23458 */
0b1001'1111, /* U+1CD8F BLOCK OCTANT-123458 */
0b1010'0001, /* U+1CD90 BLOCK OCTANT-168 */
0b1010'0010, /* U+1CD91 BLOCK OCTANT-268 */
0b1010'0011, /* U+1CD92 BLOCK OCTANT-1268 */
0b1010'0100, /* U+1CD93 BLOCK OCTANT-368 */
0b1010'0110, /* U+1CD94 BLOCK OCTANT-2368 */
0b1010'0111, /* U+1CD95 BLOCK OCTANT-12368 */
0b1010'1000, /* U+1CD96 BLOCK OCTANT-468 */
0b1010'1001, /* U+1CD97 BLOCK OCTANT-1468 */
0b1010'1011, /* U+1CD98 BLOCK OCTANT-12468 */
0b1010'1100, /* U+1CD99 BLOCK OCTANT-3468 */
0b1010'1101, /* U+1CD9A BLOCK OCTANT-13468 */
0b1010'1110, /* U+1CD9B BLOCK OCTANT-23468 */
0b1011'0000, /* U+1CD9C BLOCK OCTANT-568 */
0b1011'0001, /* U+1CD9D BLOCK OCTANT-1568 */
0b1011'0010, /* U+1CD9E BLOCK OCTANT-2568 */
0b1011'0011, /* U+1CD9F BLOCK OCTANT-12568 */
0b1011'0100, /* U+1CDA0 BLOCK OCTANT-3568 */
0b1011'0101, /* U+1CDA1 BLOCK OCTANT-13568 */
0b1011'0110, /* U+1CDA2 BLOCK OCTANT-23568 */
0b1011'0111, /* U+1CDA3 BLOCK OCTANT-123568 */
0b1011'1000, /* U+1CDA4 BLOCK OCTANT-4568 */
0b1011'1001, /* U+1CDA5 BLOCK OCTANT-14568 */
0b1011'1010, /* U+1CDA6 BLOCK OCTANT-24568 */
0b1011'1011, /* U+1CDA7 BLOCK OCTANT-124568 */
0b1011'1100, /* U+1CDA8 BLOCK OCTANT-34568 */
0b1011'1101, /* U+1CDA9 BLOCK OCTANT-134568 */
0b1011'1110, /* U+1CDAA BLOCK OCTANT-234568 */
0b1011'1111, /* U+1CDAB BLOCK OCTANT-1234568 */
0b1100'0001, /* U+1CDAC BLOCK OCTANT-178 */
0b1100'0010, /* U+1CDAD BLOCK OCTANT-278 */
0b1100'0011, /* U+1CDAE BLOCK OCTANT-1278 */
0b1100'0100, /* U+1CDAF BLOCK OCTANT-378 */
0b1100'0101, /* U+1CDB0 BLOCK OCTANT-1378 */
0b1100'0110, /* U+1CDB1 BLOCK OCTANT-2378 */
0b1100'0111, /* U+1CDB2 BLOCK OCTANT-12378 */
0b1100'1000, /* U+1CDB3 BLOCK OCTANT-478 */
0b1100'1001, /* U+1CDB4 BLOCK OCTANT-1478 */
0b1100'1010, /* U+1CDB5 BLOCK OCTANT-2478 */
0b1100'1011, /* U+1CDB6 BLOCK OCTANT-12478 */
0b1100'1100, /* U+1CDB7 BLOCK OCTANT-3478 */
0b1100'1101, /* U+1CDB8 BLOCK OCTANT-13478 */
0b1100'1110, /* U+1CDB9 BLOCK OCTANT-23478 */
0b1100'1111, /* U+1CDBA BLOCK OCTANT-123478 */
0b1101'0000, /* U+1CDBB BLOCK OCTANT-578 */
0b1101'0001, /* U+1CDBC BLOCK OCTANT-1578 */
0b1101'0010, /* U+1CDBD BLOCK OCTANT-2578 */
0b1101'0011, /* U+1CDBE BLOCK OCTANT-12578 */
0b1101'0100, /* U+1CDBF BLOCK OCTANT-3578 */
0b1101'0101, /* U+1CDC0 BLOCK OCTANT-13578 */
0b1101'0110, /* U+1CDC1 BLOCK OCTANT-23578 */
0b1101'0111, /* U+1CDC2 BLOCK OCTANT-123578 */
0b1101'1000, /* U+1CDC3 BLOCK OCTANT-4578 */
0b1101'1001, /* U+1CDC4 BLOCK OCTANT-14578 */
0b1101'1010, /* U+1CDC5 BLOCK OCTANT-24578 */
0b1101'1011, /* U+1CDC6 BLOCK OCTANT-124578 */
0b1101'1100, /* U+1CDC7 BLOCK OCTANT-34578 */
0b1101'1101, /* U+1CDC8 BLOCK OCTANT-134578 */
0b1101'1110, /* U+1CDC9 BLOCK OCTANT-234578 */
0b1101'1111, /* U+1CDCA BLOCK OCTANT-1234578 */
0b1110'0000, /* U+1CDCB BLOCK OCTANT-678 */
0b1110'0001, /* U+1CDCC BLOCK OCTANT-1678 */
0b1110'0010, /* U+1CDCD BLOCK OCTANT-2678 */
0b1110'0011, /* U+1CDCE BLOCK OCTANT-12678 */
0b1110'0100, /* U+1CDCF BLOCK OCTANT-3678 */
0b1110'0101, /* U+1CDD0 BLOCK OCTANT-13678 */
0b1110'0110, /* U+1CDD1 BLOCK OCTANT-23678 */
0b1110'0111, /* U+1CDD2 BLOCK OCTANT-123678 */
0b1110'1000, /* U+1CDD3 BLOCK OCTANT-4678 */
0b1110'1001, /* U+1CDD4 BLOCK OCTANT-14678 */
0b1110'1010, /* U+1CDD5 BLOCK OCTANT-24678 */
0b1110'1011, /* U+1CDD6 BLOCK OCTANT-124678 */
0b1110'1100, /* U+1CDD7 BLOCK OCTANT-34678 */
0b1110'1101, /* U+1CDD8 BLOCK OCTANT-134678 */
0b1110'1110, /* U+1CDD9 BLOCK OCTANT-234678 */
0b1110'1111, /* U+1CDDA BLOCK OCTANT-1234678 */
0b1111'0001, /* U+1CDDB BLOCK OCTANT-15678 */
0b1111'0010, /* U+1CDDC BLOCK OCTANT-25678 */
0b1111'0011, /* U+1CDDD BLOCK OCTANT-125678 */
0b1111'0100, /* U+1CDDE BLOCK OCTANT-35678 */
0b1111'0110, /* U+1CDDF BLOCK OCTANT-235678 */
0b1111'0111, /* U+1CDE0 BLOCK OCTANT-1235678 */
0b1111'1000, /* U+1CDE1 BLOCK OCTANT-45678 */
0b1111'1001, /* U+1CDE2 BLOCK OCTANT-145678 */
0b1111'1011, /* U+1CDE3 BLOCK OCTANT-1245678 */
0b1111'1101, /* U+1CDE4 BLOCK OCTANT-1345678 */
0b1111'1110, /* U+1CDE5 BLOCK OCTANT-2345678 */
};
octant(cr, octant_value[c - 0x1cd00], x, y, width, height);
break;
}
case 0x1cea0: /* U+1CEA0 RIGHT HALF LOWER ONE QUARTER BLOCK */
octant(cr, 0b1000'0000, x, y, width, height);
break;
case 0x1cea3: /* U+1CEA3 LEFT HALF LOWER ONE QUARTER BLOCK */
octant(cr, 0b0100'0000, x, y, width, height);
break;
case 0x1cea8: /* U+1CEA8 LEFT HALF UPPER ONE QUARTER BLOCK */
octant(cr, 0b0000'0001, x, y, width, height);
break;
case 0x1ceab: /* U+1CEAB RIGHT HALF UPPER ONE QUARTER BLOCK */
octant(cr, 0b0000'0010, x, y, width, height);
break;
case 0x1fbe6 ... 0x1fbe7: {
static constinit uint8_t const octant_value[] = {
0b0001'0100, /* U+1FBE6 MIDDLE LEFT ONE QUARTER BLOCK */
0b0010'1000, /* U+1FBE7 MIDDLE RIGHT ONE QUARTER BLOCK */
};
octant(cr, octant_value[c - 0x1fbe6], x, y, width, height);
break;
}
case 0x1cc1b: /* BOX DRAWING LIGHT HORIZONTAL AND UPPER RIGHT */
case 0x1cc1c: /* BOX DRAWING LIGHT HORIZONTAL AND LOWER RIGHT */ {
/* Apparently these have no LEFT counterparts; note that
* U+11CC1D..E below are *not* them!
*/
auto const top = (c == 0x1cc1b);
cairo_rectangle(cr,
x, y + upper_half - light_line_width / 2,
width, light_line_width);
cairo_rectangle(cr,
x + width - light_line_width,
y + (top ? 0 : upper_half - light_line_width / 2),
light_line_width,
(top ? upper_half : height - upper_half) + light_line_width / 2);
cairo_fill(cr);
break;
}
case 0x1cc1d: /* BOX DRAWING LIGHT TOP AND UPPER LEFT */
case 0x1cc1e: /* BOX DRAWING LIGHT BOTTOM AND LOWER LEFT */ {
auto const top = (c == 0x1cc1d);
auto const ys = scanline_y(top ? 1 : 9, height, light_line_width);
cairo_rectangle(cr, x, y + ys, width, light_line_width);
cairo_rectangle(cr, x, y + (top ? ys : upper_half),
light_line_width,
top ? upper_half - ys : ys - upper_half + light_line_width);
cairo_fill(cr);
break;
}
case 0x1ce16: /* BOX DRAWING LIGHT VERTICAL AND TOP RIGHT */
case 0x1ce17: /* BOX DRAWING LIGHT VERTICAL AND BOTTOM RIGHT */
case 0x1ce18: /* BOX DRAWING LIGHT VERTICAL AND TOP LEFT */
case 0x1ce19: /* BOX DRAWING LIGHT VERTICAL AND BOTTOM LEFT */ {
auto const top = (c & 1) == 0;
auto const left = (c >= 0x1ce18);
auto const sy = scanline_y(top ? 1 : 9, height, light_line_width);
if (top)
cairo_rectangle(cr,
x + left_half - light_line_width / 2,
y + sy,
light_line_width,
height - sy);
else
cairo_rectangle(cr,
x + left_half - light_line_width / 2,
y,
light_line_width,
sy + light_line_width);
cairo_fill(cr);
if (left)
cairo_rectangle(cr,
x, y + sy,
left_half + light_line_width / 2,
light_line_width);
else
cairo_rectangle(cr,
x + left_half - light_line_width / 2, y + sy,
width - left_half + light_line_width / 2,
light_line_width);
cairo_fill(cr);
break;
}
case 0x1cc30 ... 0x1cc34: // UPPER LEFT TWELFTH CIRCLE … UPPER MIDDLE LEFT TWELFTH CIRCLE
case 0x1cc37: // UPPER MIDDLE RIGHT TWELFTH CIRCLE
case 0x1cc38: // LOWER MIDDLE LEFT TWELFTH CIRCLE
case 0x1cc3b ... 0x1cc3f: { // LOWER MIDDLE RIGHT TWELFTH CIRCLE … LOWER RIGHT TWELFTH CIRCLE
// These characters are the 12 segments of a circle inscribed into
// a 4x4 cell square, in this order: 0x1cc30 +
// 0 1 2 3
// 4 7
// 8 b
// c d e f
//
// The problem here is that in our usual 1:2 cell aspect,
// this is a very excentric ellipse, not a circle.
auto const v = int(c - 0x1cc30);
circle_segment(cr, x, y, width, height, light_line_width,
2 - (v & 0x3), 2 - (v >> 2), 2);
break;
}
case 0x1cc35: // UPPER LEFT QUARTER CIRCLE
case 0x1cc36: // UPPER RIGHT QUARTER CIRCLE
case 0x1cc39: // LOWER LEFT QUARTER CIRCLE
case 0x1cc3a: { // LOWER RIGHT QUARTER CIRCLE
// These characters are the 4 segments of a circle inscribed into
// a 2x23 cell square, in this order: 0x1cc30 +
// 5 6
// 9 a
//
// The problem here is that in our usual 1:2 cell aspect,
// this is a very excentric ellipse, not a circle.
auto const v = int(c - 0x1cc30);
circle_segment(cr, x, y, width, height, light_line_width,
2 - (v & 0x3), 2 - (v >> 2), 1);
break;
}
default:
cairo_set_source_rgba (cr, 1., 0., 1., 1.);
cairo_rectangle(cr, x, y, width, height);
cairo_fill(cr);
break;
// g_assert_not_reached();
}
cairo_restore(cr);
}
} // namespace vte::view