summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Persch <chpe@src.gnome.org>2022-02-11 19:01:03 +0100
committerChristian Persch <chpe@src.gnome.org>2022-02-11 19:01:03 +0100
commit6d80d3bca78397b2073f61e7954f3ceb45a8cb37 (patch)
tree185858eead5fc28e8a942d856e1d542c2e43617a
parent62da45c67465fe94fd962788729020738292b15f (diff)
downloadvte-6d80d3bca78397b2073f61e7954f3ceb45a8cb37.tar.gz
all: Remove SIXEL support from stable branch
The SIXEL support is not in a releasable state with important and fundamental problems still unsolved. (cherry picked from commit d578bd30b18a0d040305f356a3327fbd011e5451) (cherry picked from commit ba1e05c9ad34d0e48a823ad5a67b96baa166de24)
-rw-r--r--meson.build2
-rw-r--r--meson_options.txt7
-rw-r--r--src/app/app.cc6
-rw-r--r--src/debug.cc1
-rw-r--r--src/debug.h1
-rw-r--r--src/fwd.hh8
-rw-r--r--src/image.cc68
-rw-r--r--src/image.hh102
-rw-r--r--src/meson.build56
-rw-r--r--src/parser-cat.cc327
-rwxr-xr-xsrc/parser-seq.py2
-rw-r--r--src/pty.cc4
-rw-r--r--src/ring.cc225
-rw-r--r--src/ring.hh45
-rw-r--r--src/sixel-context.cc516
-rw-r--r--src/sixel-context.hh663
-rw-r--r--src/sixel-fuzzer.cc763
-rw-r--r--src/sixel-parser.hh669
-rw-r--r--src/sixel-test.cc1597
-rw-r--r--src/vte.cc179
-rw-r--r--src/vtedefines.hh6
-rw-r--r--src/vtegtk.cc26
-rw-r--r--src/vteinternal.hh38
-rw-r--r--src/vteseq.cc223
-rw-r--r--src/widget.hh3
25 files changed, 19 insertions, 5518 deletions
diff --git a/meson.build b/meson.build
index 6c353105..096d4ae1 100644
--- a/meson.build
+++ b/meson.build
@@ -174,7 +174,6 @@ config_h.set('WITH_A11Y', get_option('a11y'))
config_h.set('WITH_FRIBIDI', get_option('fribidi'))
config_h.set('WITH_GNUTLS', get_option('gnutls'))
config_h.set('WITH_ICU', get_option('icu'))
-config_h.set('WITH_SIXEL', get_option('sixel'))
ver = glib_min_req_version.split('.')
config_h.set('GLIB_VERSION_MIN_REQUIRED', '(G_ENCODE_VERSION(' + ver[0] + ',' + ver[1] + '))')
@@ -694,7 +693,6 @@ output += ' GTK+ 4.0: ' + get_option('gtk4').to_string() + '\n'
output += ' ICU: ' + get_option('icu').to_string() + '\n'
output += ' GIR: ' + get_option('gir').to_string() + '\n'
output += ' systemd: ' + systemd_dep.found().to_string() + '\n'
-output += ' SIXEL: ' + get_option('sixel').to_string() + '\n'
output += ' Glade: ' + get_option('glade').to_string() + '\n'
output += ' Vala: ' + get_option('vapi').to_string() + '\n'
output += '\n'
diff --git a/meson_options.txt b/meson_options.txt
index 72c3de5e..0e259910 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -93,13 +93,6 @@ option(
)
option(
- 'sixel',
- type: 'boolean',
- value: false,
- description: 'Enable SIXEL support',
-)
-
-option(
'_systemd',
type: 'boolean',
value: true,
diff --git a/src/app/app.cc b/src/app/app.cc
index 8b1d47ea..581bb165 100644
--- a/src/app/app.cc
+++ b/src/app/app.cc
@@ -73,7 +73,6 @@ public:
gboolean no_scrollbar{false};
gboolean no_shaping{false};
gboolean no_shell{false};
- gboolean no_sixel{false};
gboolean no_systemd_scope{false};
gboolean no_xfill{false};
gboolean no_yfill{false};
@@ -635,8 +634,6 @@ public:
"Disable Arabic shaping", nullptr },
{ "no-shell", 'S', 0, G_OPTION_ARG_NONE, &no_shell,
"Disable spawning a shell inside the terminal", nullptr },
- { "no-sixel", 0, 0, G_OPTION_ARG_NONE, &no_sixel,
- "Disable SIXEL images", nullptr },
{ "no-systemd-scope", 0, 0, G_OPTION_ARG_NONE, &no_systemd_scope,
"Don't use systemd user scope", nullptr },
{ "object-notifications", 'N', 0, G_OPTION_ARG_NONE, &object_notifications,
@@ -651,8 +648,6 @@ public:
"Use pixels as scroll unit", nullptr },
{ "scrollback-lines", 'n', 0, G_OPTION_ARG_INT, &scrollback_lines,
"Specify the number of scrollback-lines (-1 for infinite)", nullptr },
- { "sixel", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &no_sixel,
- "Enable SIXEL images", nullptr },
{ "title", 0, 0, G_OPTION_ARG_STRING, &title, "Set the initial title of the window", "TITLE" },
{ "transparent", 'T', 0, G_OPTION_ARG_INT, &transparency_percent,
"Enable the use of a transparent background", "0..100" },
@@ -2574,7 +2569,6 @@ vteapp_window_constructed(GObject *object)
vte_terminal_set_cursor_shape(window->terminal, options.cursor_shape);
vte_terminal_set_enable_bidi(window->terminal, !options.no_bidi);
vte_terminal_set_enable_shaping(window->terminal, !options.no_shaping);
- vte_terminal_set_enable_sixel(window->terminal, !options.no_sixel);
vte_terminal_set_enable_fallback_scrolling(window->terminal, !options.no_fallback_scrolling);
vte_terminal_set_mouse_autohide(window->terminal, true);
vte_terminal_set_rewrap_on_resize(window->terminal, !options.no_rewrap);
diff --git a/src/debug.cc b/src/debug.cc
index 4185a57a..cda5d47b 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -60,7 +60,6 @@ _vte_debug_init(void)
{ "bidi", VTE_DEBUG_BIDI },
{ "conversion", VTE_DEBUG_CONVERSION },
{ "exceptions", VTE_DEBUG_EXCEPTIONS },
- { "image", VTE_DEBUG_IMAGE },
};
_vte_debug_flags = g_parse_debug_string (g_getenv("VTE_DEBUG"),
diff --git a/src/debug.h b/src/debug.h
index da1d51d8..11429645 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -67,7 +67,6 @@ typedef enum : unsigned {
VTE_DEBUG_BIDI = 1u << 28,
VTE_DEBUG_CONVERSION = 1u << 29,
VTE_DEBUG_EXCEPTIONS = 1u << 30,
- VTE_DEBUG_IMAGE = 1u << 31,
} VteDebugFlags;
void _vte_debug_init(void);
diff --git a/src/fwd.hh b/src/fwd.hh
index 58e2208b..b6b2e1f7 100644
--- a/src/fwd.hh
+++ b/src/fwd.hh
@@ -36,14 +36,6 @@ class Widget;
} // namespace platform
-namespace sixel {
-
-class Context;
-class Parser;
-class Sequence;
-
-} // namespace sixel
-
namespace view {
class FontInfo;
diff --git a/src/image.cc b/src/image.cc
deleted file mode 100644
index 16ffa5e7..00000000
--- a/src/image.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright © 2016-2020 Hayaki Saito <saitoha@me.com>
- * Copyright © 2020 Hans Petter Jansson <hpj@cl.no>
- *
- * 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 <https://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <glib.h>
-#include <stdio.h>
-#include "vteinternal.hh"
-
-#include "image.hh"
-
-namespace vte {
-
-namespace image {
-
-/* Paint the image with provided cairo context */
-void
-Image::paint(cairo_t* cr,
- int offset_x,
- int offset_y,
- int cell_width,
- int cell_height) const noexcept
-{
- auto scale_x = 1.0;
- auto scale_y = 1.0;
-
- auto real_offset_x = double(offset_x);
- auto real_offset_y = double(offset_y);
-
- if (cell_width != m_cell_width || cell_height != m_cell_height) {
- scale_x = cell_width / (double) m_cell_width;
- scale_y = cell_height / (double) m_cell_height;
-
- real_offset_x /= scale_x;
- real_offset_y /= scale_y;
- }
-
- cairo_save(cr);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
- if (!(_vte_double_equal (scale_x, 1.0) && _vte_double_equal (scale_y, 1.0)))
- cairo_scale (cr, scale_x, scale_y);
-
- cairo_rectangle(cr, real_offset_x, real_offset_y, m_width_pixels, m_height_pixels);
- cairo_clip(cr);
- cairo_set_source_surface(cr, m_surface.get(), real_offset_x, real_offset_y);
- cairo_paint(cr);
- cairo_restore(cr);
-}
-
-} // namespace image
-
-} // namespace vte
diff --git a/src/image.hh b/src/image.hh
deleted file mode 100644
index 6f88a123..00000000
--- a/src/image.hh
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright © 2016-2020 Hayaki Saito <saitoha@me.com>
- * Copyright © 2020 Hans Petter Jansson <hpj@cl.no>
- *
- * 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 <https://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include <pango/pangocairo.h>
-#include "cairo-glue.hh"
-
-namespace vte {
-
-namespace image {
-
-class Image {
-private:
- // Image data, device-independent
- vte::Freeable<cairo_surface_t> m_surface{};
-
- // Draw/prune priority, must be unique
- size_t m_priority;
-
- // Image dimensions in pixels
- int m_width_pixels;
- int m_height_pixels;
-
- // Top left corner offset in cell units
- int m_left_cells;
- int m_top_cells;
-
- // Cell dimensions in pixels at time of image creation
- int m_cell_width;
- int m_cell_height;
-
-public:
- Image(vte::Freeable<cairo_surface_t> surface,
- size_t priority,
- int width_pixels,
- int height_pixels,
- int col,
- int row,
- int cell_width,
- int cell_height) noexcept
- : m_surface{std::move(surface)},
- m_priority{priority},
- m_width_pixels{width_pixels},
- m_height_pixels{height_pixels},
- m_left_cells{col},
- m_top_cells{row},
- m_cell_width{cell_width},
- m_cell_height{cell_height}
- {
- }
-
- ~Image() = default;
-
- Image(Image const&) = delete;
- Image(Image&&) = delete;
- Image operator=(Image const&) = delete;
- Image operator=(Image&&) = delete;
-
- inline constexpr auto get_priority() const noexcept { return m_priority; }
- inline constexpr auto get_left() const noexcept { return m_left_cells; }
- inline auto get_top() const noexcept { return m_top_cells; }
- inline void set_top(int row) noexcept { m_top_cells = row; }
- inline constexpr auto get_width() const noexcept { return (m_width_pixels + m_cell_width - 1) / m_cell_width; }
- inline constexpr auto get_height() const noexcept { return (m_height_pixels + m_cell_height - 1) / m_cell_height; }
- inline auto get_bottom() const noexcept { return m_top_cells + get_height() - 1; }
-
- inline auto resource_size() const noexcept
- {
- if (cairo_image_surface_get_stride(m_surface.get()) != 0)
- return cairo_image_surface_get_stride(m_surface.get()) * m_height_pixels;
-
- /* Not an image surface: Only the device knows for sure, so we guess */
- return m_width_pixels * m_height_pixels * 4;
- }
-
- void paint(cairo_t* cr,
- int offset_x,
- int offset_y,
- int cell_width,
- int cell_height) const noexcept;
-
-}; // class Image
-
-} // namespace image
-
-} // namespace vte
diff --git a/src/meson.build b/src/meson.build
index 165ed000..20083e49 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -132,20 +132,6 @@ regex_sources = files(
'regex.hh'
)
-sixel_parser_sources = files(
- 'sixel-parser.hh',
-)
-
-sixel_context_sources = files(
- 'sixel-context.cc',
- 'sixel-context.hh',
-)
-
-sixel_sources = sixel_parser_sources + sixel_context_sources + files(
- 'image.cc',
- 'image.hh',
-)
-
std_glue_sources = files(
'std-glue.hh',
)
@@ -229,10 +215,6 @@ if get_option('icu')
libvte_common_sources += icu_sources
endif
-if get_option('sixel')
- libvte_common_sources += sixel_sources
-endif
-
if systemd_dep.found()
libvte_common_sources += systemd_sources
endif
@@ -402,10 +384,6 @@ parser_cat_sources = config_sources + glib_glue_sources + libc_glue_sources + pa
'vtedefines.hh',
)
-if get_option('sixel')
- parser_cat_sources += sixel_parser_sources
-endif
-
parser_cat = executable(
'parser-cat',
parser_cat_sources,
@@ -586,34 +564,6 @@ test_refptr = executable(
install: false,
)
-if get_option('sixel')
- fuzz_sixel_sources = config_sources + files(
- 'sixel-fuzzer.cc',
- )
-
- fuzz_sixel = executable(
- 'fuzz-sixel',
- sources: fuzz_sixel_sources,
- dependencies: [glib_dep,],
- include_directories: top_inc,
- install: false,
- )
-
- test_sixel_sources = config_sources + glib_glue_sources + sixel_parser_sources + sixel_context_sources + files(
- 'cairo-glue.hh',
- 'sixel-test.cc',
- 'vtedefines.hh',
- )
-
- test_sixel = executable(
- 'test-sixel',
- sources: test_sixel_sources,
- dependencies: [glib_dep,],
- include_directories: top_inc,
- install: false,
- )
-endif
-
test_stream_sources = config_sources + files(
'vtestream-base.h',
'vtestream-file.h',
@@ -695,12 +645,6 @@ if get_option('gtk3')
]
endif
-if get_option('sixel')
- test_units += [
- ['sixel', test_sixel],
- ]
-endif
-
foreach test: test_units
test(
test[0],
diff --git a/src/parser-cat.cc b/src/parser-cat.cc
index 5fade9db..afb6fb1a 100644
--- a/src/parser-cat.cc
+++ b/src/parser-cat.cc
@@ -40,10 +40,6 @@
#include "utf8.hh"
#include "vtedefines.hh"
-#ifdef WITH_SIXEL
-#include "sixel-parser.hh"
-#endif
-
enum {
#define _VTE_SGR(...)
#define _VTE_NGR(name, value) VTE_SGR_##name = value,
@@ -58,9 +54,6 @@ enum class DataSyntax {
ECMA48_UTF8,
/* ECMA48_PCTERM, */
/* ECMA48_ECMA35, */
- #ifdef WITH_SIXEL
- DECSIXEL,
- #endif
};
char*
@@ -154,9 +147,6 @@ private:
std::string m_str;
bool m_plain;
bool m_codepoints;
-#ifdef WITH_SIXEL
- char32_t m_sixel_st;
-#endif
inline constexpr bool plain() const noexcept { return m_plain; }
@@ -389,48 +379,6 @@ private:
}
}
-#ifdef WITH_SIXEL
-
- void
- print_params(vte::sixel::Sequence const& seq) noexcept
- {
- auto const size = seq.size();
- if (size > 0)
- m_str.push_back(' ');
-
- for (unsigned int i = 0; i < size; i++) {
- if (!seq.param_default(i))
- print_format("%d", seq.param(i));
- if (i + 1 < size)
- m_str.push_back(';');
- }
- }
-
- void
- print_seq(vte::sixel::Sequence const& seq) noexcept
- {
- ReverseAttr attr(this);
- GreenAttr green(this);
-
- m_str.push_back('{');
- switch (seq.command()) {
- case vte::sixel::Command::DECGRI: m_str.append("DECGRI"); break;
- case vte::sixel::Command::DECGRA: m_str.append("DECGRA"); break;
- case vte::sixel::Command::DECGCI: m_str.append("DECGCI"); break;
- case vte::sixel::Command::DECGCR: m_str.append("DECGCR"); break;
- case vte::sixel::Command::DECGNL: m_str.append("DECGNL"); break;
- default:
- print_format("%d/%d",
- int(seq.command()) / 16,
- int(seq.command()) % 16);
- break;
- }
- print_params(seq);
- m_str.push_back('}');
- }
-
-#endif /* WITH_SIXEL */
-
void
printout() noexcept
{
@@ -463,45 +411,9 @@ public:
printout();
}
-#ifdef WITH_SIXEL
-
- void SIXEL_CMD(vte::sixel::Sequence const& seq) noexcept
- {
- print_seq(seq);
-
- switch (seq.command()) {
- case vte::sixel::Command::DECGCR:
- case vte::sixel::Command::DECGNL:
- printout();
- break;
- default:
- break;
- }
- }
-
- void SIXEL(uint8_t sixel) noexcept
- {
- print_format("%c", sixel + 0x3f);
- }
-
- void SIXEL_ST(char32_t st) noexcept
- {
- m_sixel_st = st;
- }
-
-#endif /* WITH_SIXEL */
-
void enter_data_syntax(DataSyntax syntax) noexcept
{
switch (syntax) {
-#ifdef WITH_SIXEL
- case DataSyntax::DECSIXEL: {
- GreenAttr green(this);
- print_literal("<SIXEL[");
- m_sixel_st = 0;
- break;
- }
-#endif
default:
break;
}
@@ -511,17 +423,6 @@ public:
bool success) noexcept
{
switch (syntax) {
-#ifdef WITH_SIXEL
- case DataSyntax::DECSIXEL:
- if (success) {
- GreenAttr green(this);
- print_literal("]ST>");
- } else {
- RedAttr green(this);
- print_literal("]>");
- }
- break;
-#endif
default:
break;
}
@@ -718,13 +619,6 @@ private:
}
}
-#ifdef WITH_SIXEL
- char32_t m_sixel_st{0};
- bool m_seen_sixel_commands{false};
- bool m_seen_sixel_data{false};
- std::bitset<VTE_SIXEL_NUM_COLOR_REGISTERS> m_sixel_color_set;
-#endif
-
public:
Linter() noexcept = default;
~Linter() noexcept = default;
@@ -753,22 +647,6 @@ public:
check_sgr(seq);
break;
-#ifdef WITH_SIXEL
- case VTE_CMD_DECSIXEL:
- /* OR mode is a nonstandard NetBSD/x68k extension that is
- * not supported in VTE.
- */
- if (seq.collect1(1) == 5)
- warn("DECSIXEL OR-mode not supported");
-
- /* Image ID (args[3]) is a nonstandard RLogin extension that is
- * not supported in VTE.
- */
- if (seq.collect1(3) != -1)
- warn("DECSIXEL ID extension not supported");
- break;
-#endif /* WITH_SIXEL */
-
default:
if (cmd >= VTE_CMD_NOP_FIRST)
warn("%s is unimplemented", cmd_to_str(cmd));
@@ -776,135 +654,8 @@ public:
}
}
-#ifdef WITH_SIXEL
-
- void SIXEL(uint8_t raw) noexcept
- {
- m_seen_sixel_data = true;
- }
-
- void SIXEL_CMD(vte::sixel::Sequence const& seq) noexcept
- {
- switch (seq.command()) {
- case vte::sixel::Command::DECGRI: {
- auto const count = seq.param(0, 1);
- if (count < 3)
- warn("DECGRI %d wastes space", seq.param(0));
- else if (count == 3)
- warn("DECGRI %d saves no space", count);
- else if (count > 255)
- warn("DECGRI %d exceeds DEC limit of 255", count);
- break;
- }
-
- case vte::sixel::Command::DECGRA:
- if (m_seen_sixel_commands || m_seen_sixel_data)
- warn("DECGRA ignored after any SIXEL commands or data");
- break;
-
- case vte::sixel::Command::DECGCI: {
-
- auto reg = seq.param(0);
- if (reg == -1) {
- warn("DECGCI does not admit a default value for parameter 1");
- break;
- } else if (reg >= VTE_SIXEL_NUM_COLOR_REGISTERS) {
- warn("DECGCI %d exceeds number of available colour registers, wrapped to register %d", reg, reg & (VTE_SIXEL_NUM_COLOR_REGISTERS - 1));
- reg &= (VTE_SIXEL_NUM_COLOR_REGISTERS - 1);
- }
-
- if (seq.size() > 1) {
- switch (seq.param(1)) {
- case -1: /* default */
- warn("DECGCI does not admit a default value for parameter 2");
- break;
- case 1: /* HLS */ {
- auto const h = seq.param(2, 0);
- auto const l = seq.param(3, 0);
- auto const s = seq.param(4, 0);
- if (h > 360)
- warn("DECGCI HSL colour hue %d exceeds range 0..360", h);
- if (l > 100)
- warn("DECGCI HSL colour luminosity %d exceeds range 0..100", l);
- if (s > 100)
- warn("DECGCI HSL colour saturation %d exceeds range 0..100", s);
- break;
- }
-
- case 2: /* RGB */ {
- auto const r = seq.param(2, 0);
- auto const g = seq.param(3, 0);
- auto const b = seq.param(4, 0);
- if (r > 100)
- warn("DECGCI RGB colour red %d exceeds range 0..100", r);
- if (g > 100)
- warn("DECGCI RGB colour red %d exceeds range 0..100", g);
- if (b > 100)
- warn("DECGCI RGB colour red %d exceeds range 0..100", b);
- break;
- }
-
- case 3: /* RGB truecolour.
- * This is an RLogin extension and not supported by VTE.
- */
- warn("DECGCI RGB truecolour extension is not supported");
- break;
-
- case 0:
- default:
- warn("DECGCI unknown colour coordinate system %d", seq.param(1));
- break;
- }
-
- m_sixel_color_set.set(reg);
- } else {
- /* Select colour register param[0] */
-
- if (!m_sixel_color_set.test(reg))
- warn("DECGCI %d selects colour which has not been defined", reg);
- }
-
- break;
- }
-
- case vte::sixel::Command::DECGCR:
- break;
-
- case vte::sixel::Command::DECGNL:
- break;
-
- default:
- warn("Ignoring unknown SIXEL command %d/%d '%c'",
- int(seq.command()) / 16,
- int(seq.command()) % 16,
- char(seq.command()));
- break;
- }
-
- m_seen_sixel_commands = true;
- }
-
- void SIXEL_ST(char32_t st) noexcept
- {
- m_sixel_st = st;
- }
-
-#endif /* WITH_SIXEL */
-
void enter_data_syntax(DataSyntax syntax) noexcept
{
- switch (syntax) {
-#ifdef WITH_SIXEL
- case DataSyntax::DECSIXEL:
- m_sixel_st = 0;
- m_seen_sixel_commands = m_seen_sixel_data = false;
- m_sixel_color_set.reset();
- break;
-#endif
-
- default:
- break;
- }
}
void leave_data_syntax(DataSyntax syntax,
@@ -922,12 +673,6 @@ class Sink {
public:
void VT(vte::parser::Sequence const& seq) noexcept { }
-#ifdef WITH_SIXEL
- void SIXEL(uint8_t raw) noexcept { }
- void SIXEL_CMD(vte::sixel::Sequence const& seq) noexcept { }
- void SIXEL_ST(char32_t st) noexcept { }
-#endif
-
void enter_data_syntax(DataSyntax syntax) noexcept { }
void leave_data_syntax(DataSyntax syntax,
bool success) noexcept { }
@@ -943,7 +688,6 @@ private:
D& m_delegate;
size_t m_buffer_size{0};
- bool m_no_sixel{false};
bool m_statistics{false};
bool m_benchmark{false};
@@ -956,10 +700,6 @@ private:
vte::base::UTF8Decoder m_utf8_decoder{};
vte::parser::Parser m_parser{};
-#ifdef WITH_SIXEL
- vte::sixel::Parser m_sixel_parser{};
-#endif
-
DataSyntax m_primary_data_syntax{DataSyntax::ECMA48_UTF8};
DataSyntax m_current_data_syntax{DataSyntax::ECMA48_UTF8};
@@ -971,12 +711,6 @@ private:
m_utf8_decoder.reset();
break;
-#ifdef WITH_SIXEL
- case DataSyntax::DECSIXEL:
- m_sixel_parser.reset();
- break;
-#endif
-
default:
break;
}
@@ -994,20 +728,6 @@ private:
process_seq(vte::parser::Sequence const& seq) noexcept
{
m_delegate.VT(seq);
-
-#ifdef WITH_SIXEL
- if (G_UNLIKELY(!m_no_sixel &&
- seq.command() == VTE_CMD_DECSIXEL &&
- seq.is_unripe())) {
- m_parser.reset(); // sixel parser takes over until ST
- m_sixel_parser.reset();
- m_current_data_syntax = DataSyntax::DECSIXEL;
-
- m_delegate.enter_data_syntax(m_current_data_syntax);
- return false;
- }
-#endif /* WITH_SIXEL */
-
return true;
}
@@ -1070,33 +790,6 @@ private:
return bufend;
}
-#ifdef WITH_SIXEL
-
- uint8_t const*
- process_data_decsixel(uint8_t const* const bufstart,
- uint8_t const* const bufend,
- bool eos) noexcept
- {
- auto [status, ip] = m_sixel_parser.parse(bufstart, bufend, eos, m_delegate);
-
- switch (status) {
- case vte::sixel::Parser::ParseStatus::CONTINUE:
- break;
-
- case vte::sixel::Parser::ParseStatus::COMPLETE:
- case vte::sixel::Parser::ParseStatus::ABORT: {
- auto const success = (status == vte::sixel::Parser::ParseStatus::COMPLETE);
- m_delegate.leave_data_syntax(m_current_data_syntax, success);
- m_current_data_syntax = m_primary_data_syntax;
- break;
- }
- }
-
- return ip;
- }
-
-#endif /* WITH_SIXEL */
-
void
process_fd(int fd)
{
@@ -1124,12 +817,6 @@ private:
sptr = process_data_utf8(sptr, bufend, eos);
break;
-#ifdef WITH_SIXEL
- case DataSyntax::DECSIXEL:
- sptr = process_data_decsixel(sptr, bufend, eos);
- break;
-#endif
-
default:
g_assert_not_reached();
break;
@@ -1179,22 +866,16 @@ public:
Processor(Delegate& delegate,
size_t buffer_size,
- bool no_sixel,
bool statistics,
bool benchmark) noexcept
: m_delegate{delegate},
m_buffer_size{std::max(buffer_size, k_buf_overlap + 1)},
- m_no_sixel{no_sixel},
m_statistics{statistics},
m_benchmark{benchmark}
{
memset(&m_seq_stats, 0, sizeof(m_seq_stats));
memset(&m_cmd_stats, 0, sizeof(m_cmd_stats));
m_bench_times = g_array_new(false, true, sizeof(int64_t));
-
-#ifdef WITH_SIXEL
- m_parser.set_dispatch_unripe(!m_no_sixel);
-#endif
}
~Processor() noexcept
@@ -1290,7 +971,6 @@ private:
bool m_benchmark{false};
bool m_codepoints{false};
bool m_lint{false};
- bool m_no_sixel{false};
bool m_plain{false};
bool m_quiet{false};
bool m_statistics{false};
@@ -1310,7 +990,6 @@ public:
inline constexpr size_t buffer_size() const noexcept { return m_buffer_size; }
inline constexpr bool codepoints() const noexcept { return m_codepoints; }
inline constexpr bool lint() const noexcept { return m_lint; }
- inline constexpr bool no_sixel() const noexcept { return m_no_sixel; }
inline constexpr bool plain() const noexcept { return m_plain; }
inline constexpr bool quiet() const noexcept { return m_quiet; }
inline constexpr bool statistics() const noexcept { return m_statistics; }
@@ -1328,7 +1007,6 @@ public:
auto benchmark = BoolOption{m_benchmark, false};
auto codepoints = BoolOption{m_codepoints, false};
auto lint = BoolOption{m_lint, false};
- auto no_sixel = BoolOption{m_no_sixel, false};
auto plain = BoolOption{m_plain, false};
auto quiet = BoolOption{m_quiet, false};
auto statistics = BoolOption{m_statistics, false};
@@ -1345,10 +1023,6 @@ public:
"Output unicode code points by number", nullptr },
{ "lint", 'l', 0, G_OPTION_ARG_NONE, &lint,
"Check input", nullptr },
-#ifdef WITH_SIXEL
- { "no-sixel", 0, 0, G_OPTION_ARG_NONE, &no_sixel,
- "Disable DECSIXEL processing", nullptr },
-#endif
{ "plain", 'p', 0, G_OPTION_ARG_NONE, &plain,
"Output plain text without attributes", nullptr },
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet,
@@ -1377,7 +1051,6 @@ process(Options const& options,
{
auto proc = Processor{delegate,
options.buffer_size(),
- options.no_sixel(),
options.statistics(),
options.benchmark()};
diff --git a/src/parser-seq.py b/src/parser-seq.py
index 83b067fd..c484c0ac 100755
--- a/src/parser-seq.py
+++ b/src/parser-seq.py
@@ -918,7 +918,7 @@ sequences = [
comment='restore terminal state'),
seq_DCS('XTERM_STCAP', 'p', intermediates=(Intermediate.PLUS,), flags=Flags.NOP,
comment='xterm set termcap/terminfo'),
- seq_DCS('DECSIXEL', 'q', flags=Flags.UNRIPE | Flags.HANDLER_RV,
+ seq_DCS('DECSIXEL', 'q', flags=Flags.NOP,
comment='SIXEL graphics'),
seq_DCS('DECRQSS', 'q', intermediates=(Intermediate.CASH,),
comment='request selection or setting'),
diff --git a/src/pty.cc b/src/pty.cc
index c2d11817..695d7de7 100644
--- a/src/pty.cc
+++ b/src/pty.cc
@@ -293,10 +293,6 @@ Pty::set_size(int rows,
memset(&size, 0, sizeof(size));
size.ws_row = rows > 0 ? rows : 24;
size.ws_col = columns > 0 ? columns : 80;
-#ifdef WITH_SIXEL
- size.ws_ypixel = size.ws_row * cell_height_px;
- size.ws_xpixel = size.ws_col * cell_width_px;
-#endif
_vte_debug_print(VTE_DEBUG_PTY,
"Setting size on fd %d to (%d,%d).\n",
master, columns, rows);
diff --git a/src/ring.cc b/src/ring.cc
index 23d79600..fe5bab17 100644
--- a/src/ring.cc
+++ b/src/ring.cc
@@ -25,20 +25,6 @@
#include <string.h>
-#ifdef WITH_SIXEL
-
-#include "cxx-utils.hh"
-
-/* We should be able to hold a single fullscreen 4K image at most.
- * 35MiB equals 3840 * 2160 * 4 plus a little extra. */
-#define IMAGE_FAST_MEMORY_USED_MAX (35 * 1024 * 1024)
-
-/* Hard limit on number of images to keep around. This limits the impact
- * of potential issues related to algorithmic complexity. */
-#define IMAGE_FAST_COUNT_MAX 4096
-
-#endif /* WITH_SIXEL */
-
/*
* Copy the common attributes from VteCellAttr to VteStreamCellAttr or vice versa.
*/
@@ -204,115 +190,6 @@ Ring::hyperlink_maybe_gc(row_t increment)
hyperlink_gc();
}
-#ifdef WITH_SIXEL
-
-void
-Ring::image_gc_region() noexcept
-{
- cairo_region_t *region = cairo_region_create();
-
- for (auto rit = m_image_map.rbegin();
- rit != m_image_map.rend();
- ) {
- auto const& image = rit->second;
- auto const rect = cairo_rectangle_int_t{image->get_left(),
- image->get_top(),
- image->get_width(),
- image->get_height()};
-
- if (cairo_region_contains_rectangle(region, &rect) == CAIRO_REGION_OVERLAP_IN) {
- /* vte::image::Image has been completely overdrawn; delete it */
-
- m_image_fast_memory_used -= image->resource_size();
-
- /* Apparently this is the cleanest way to erase() with a reverse iterator... */
- /* Unlink the image from m_image_by_top_map, then erase it from m_image_map */
- unlink_image_from_top_map(image.get());
- rit = image_map_type::reverse_iterator{m_image_map.erase(std::next(rit).base())};
- continue;
- }
-
- cairo_region_union_rectangle(region, &rect);
- ++rit;
- }
-
- cairo_region_destroy(region);
-}
-
-void
-Ring::image_gc() noexcept
-{
- while (m_image_fast_memory_used > IMAGE_FAST_MEMORY_USED_MAX ||
- m_image_map.size() > IMAGE_FAST_COUNT_MAX) {
- if (m_image_map.empty()) {
- /* If this happens, we've miscounted somehow. */
- break;
- }
-
- auto& image = m_image_map.begin()->second;
- m_image_fast_memory_used -= image->resource_size();
- unlink_image_from_top_map(image.get());
- m_image_map.erase(m_image_map.begin());
- }
-}
-
-void
-Ring::unlink_image_from_top_map(vte::image::Image const* image) noexcept
-{
- auto [begin, end] = m_image_by_top_map.equal_range(image->get_top());
-
- for (auto it = begin; it != end; ++it) {
- if (it->second != image)
- continue;
-
- m_image_by_top_map.erase(it);
- break;
- }
-}
-
-void
-Ring::rebuild_image_top_map() /* throws */
-{
- m_image_by_top_map.clear();
-
- for (auto it = m_image_map.begin(), end = m_image_map.end();
- it != end;
- ++it) {
- auto const& image = it->second;
- m_image_by_top_map.emplace(std::piecewise_construct,
- std::forward_as_tuple(image->get_top()),
- std::forward_as_tuple(image.get()));
- }
-}
-
-bool
-Ring::rewrap_images_in_range(Ring::image_by_top_map_type::iterator& it,
- size_t text_start_ofs,
- size_t text_end_ofs,
- row_t new_row_index) noexcept
-{
- for (auto const end = m_image_by_top_map.end();
- it != end;
- ++it) {
- auto const& image = it->second;
- auto ofs = CellTextOffset{};
-
- if (!frozen_row_column_to_text_offset(image->get_top(), 0, &ofs))
- return false;
-
- if (ofs.text_offset >= text_end_ofs)
- break;
-
- if (ofs.text_offset >= text_start_ofs && ofs.text_offset < text_end_ofs) {
- image->set_top(new_row_index);
- }
- }
-
- return true;
-}
-
-#endif /* WITH_SIXEL */
-
/*
* Find existing idx for the hyperlink or allocate a new one.
*
@@ -713,13 +590,6 @@ Ring::reset()
m_start = m_writable = m_end;
m_cached_row_num = (row_t)-1;
-#ifdef WITH_SIXEL
- m_image_by_top_map.clear();
- m_image_map.clear();
- m_next_image_priority = 0;
- m_image_fast_memory_used = 0;
-#endif
-
return m_end;
}
@@ -1150,16 +1020,7 @@ Ring::frozen_row_column_to_text_offset(row_t position,
} else
records[1].text_start_offset = _vte_stream_head(m_text_stream);
- offset->fragment_cells = 0;
- offset->eol_cells = -1;
- offset->text_offset = records[0].text_start_offset;
-
- /* Save some work if we're in column 0. This holds true for images, whose column
- * positions are disregarded for the purposes of wrapping. */
- if (column == 0)
- return true;
-
- g_string_set_size (buffer, records[1].text_start_offset - records[0].text_start_offset);
+ g_string_set_size (buffer, records[1].text_start_offset - records[0].text_start_offset);
if (!_vte_stream_read(m_text_stream, records[0].text_start_offset, buffer->str, buffer->len))
return false;
@@ -1171,6 +1032,8 @@ Ring::frozen_row_column_to_text_offset(row_t position,
/* row and buffer now contain the same text, in different representation */
/* count the number of characters up to the given column */
+ offset->fragment_cells = 0;
+ offset->eol_cells = -1;
num_chars = 0;
for (i = 0, cell = row->cells; i < row->len && i < column; i++, cell++) {
if (G_LIKELY (!cell->attr.fragment())) {
@@ -1191,7 +1054,7 @@ Ring::frozen_row_column_to_text_offset(row_t position,
off++;
if ((buffer->str[off] & 0xC0) != 0x80) num_chars--;
}
- offset->text_offset += off;
+ offset->text_offset = records[0].text_start_offset + off;
return true;
}
@@ -1303,9 +1166,6 @@ Ring::rewrap(column_t columns,
gsize paragraph_len; /* excluding trailing '\n' */
gsize attr_offset;
gsize old_ring_end;
-#ifdef WITH_SIXEL
- auto image_it = m_image_by_top_map.begin();
-#endif
if (G_UNLIKELY(length() == 0))
return;
@@ -1441,14 +1301,6 @@ Ring::rewrap(column_t columns,
}
}
-#ifdef WITH_SIXEL
- if (!rewrap_images_in_range(image_it,
- new_record.text_start_offset,
- text_offset,
- new_row_index))
- goto err;
-#endif
-
new_row_index++;
new_record.text_start_offset = text_offset;
new_record.attr_start_offset = attr_offset;
@@ -1498,14 +1350,6 @@ Ring::rewrap(column_t columns,
}
}
-#ifdef WITH_SIXEL
- if (!rewrap_images_in_range(image_it,
- new_record.text_start_offset,
- paragraph_end_text_offset,
- new_row_index))
- goto err;
-#endif
-
new_row_index++;
paragraph_start_text_offset = paragraph_end_text_offset;
}
@@ -1538,14 +1382,6 @@ Ring::rewrap(column_t columns,
g_free(marker_text_offsets);
g_free(new_markers);
-#ifdef WITH_SIXEL
- try {
- rebuild_image_top_map();
- } catch (...) {
- vte::log_exception();
- }
-#endif
-
_vte_debug_print(VTE_DEBUG_RING, "Ring after rewrapping:\n");
validate();
return;
@@ -1649,56 +1485,3 @@ Ring::write_contents(GOutputStream* stream,
return true;
}
-
-#ifdef WITH_SIXEL
-
-/**
- * Ring::append_image:
- * @surface: A Cairo surface object
- * @pixelwidth: vte::image::Image width in pixels
- * @pixelheight: vte::image::Image height in pixels
- * @left: Left position of image in cell units
- * @top: Top position of image in cell units
- * @cell_width: Width of image in cell units
- * @cell_height: Height of image in cell units
- *
- * Append an image to the internal image list.
- */
-void
-Ring::append_image(vte::Freeable<cairo_surface_t> surface,
- int pixelwidth,
- int pixelheight,
- long left,
- long top,
- long cell_width,
- long cell_height) /* throws */
-{
- auto const priority = m_next_image_priority;
- auto [it, success] = m_image_map.try_emplace
- (priority, // key
- std::make_unique<vte::image::Image>(std::move(surface),
- priority,
- pixelwidth,
- pixelheight,
- left,
- top,
- cell_width,
- cell_height));
- if (!success)
- return;
-
- ++m_next_image_priority;
-
- auto const& image = it->second;
-
- m_image_by_top_map.emplace(std::piecewise_construct,
- std::forward_as_tuple(image->get_top()),
- std::forward_as_tuple(image.get()));
-
- m_image_fast_memory_used += image->resource_size ();
-
- image_gc_region();
- image_gc();
-}
-
-#endif /* WITH_SIXEL */
diff --git a/src/ring.hh b/src/ring.hh
index 54223904..186a92bd 100644
--- a/src/ring.hh
+++ b/src/ring.hh
@@ -27,13 +27,6 @@
#include "vterowdata.hh"
#include "vtestream.h"
-#ifdef WITH_SIXEL
-#include "cairo-glue.hh"
-#include "image.hh"
-#include <map>
-#include <memory>
-#endif
-
#include <type_traits>
typedef struct _VteVisualPosition {
@@ -234,44 +227,6 @@ private:
hyperlink_idx_t m_hyperlink_hover_idx{0}; /* The hyperlink idx of the hovered cell.
An idx is allocated on hover even if the cell is scrolled out to the streams. */
row_t m_hyperlink_maybe_gc_counter{0}; /* Do a GC when it reaches 65536. */
-
-#ifdef WITH_SIXEL
-
-private:
- size_t m_next_image_priority{0};
- size_t m_image_fast_memory_used{0};
-
- /* m_image_priority_map stores the Image. key is the priority of the image. */
- using image_map_type = std::map<size_t, std::unique_ptr<vte::image::Image>>;
- image_map_type m_image_map{};
-
- /* m_image_by_top_map stores only an iterator to the Image in m_image_priority_map;
- * key is the top row of the image.
- */
- using image_by_top_map_type = std::multimap<row_t, vte::image::Image*>;
- image_by_top_map_type m_image_by_top_map{};
-
- void image_gc() noexcept;
- void image_gc_region() noexcept;
- void unlink_image_from_top_map(vte::image::Image const* image) noexcept;
- void rebuild_image_top_map() /* throws */;
- bool rewrap_images_in_range(image_by_top_map_type::iterator& it,
- size_t text_start_ofs,
- size_t text_end_ofs,
- row_t new_row_index) noexcept;
-
-public:
- auto const& image_map() const noexcept { return m_image_map; }
-
- void append_image(vte::Freeable<cairo_surface_t> surface,
- int pixelwidth,
- int pixelheight,
- long left,
- long top,
- long cell_width,
- long cell_height) /* throws */;
-
-#endif /* WITH_SIXEL */
};
}; /* namespace base */
diff --git a/src/sixel-context.cc b/src/sixel-context.cc
deleted file mode 100644
index 20238ac6..00000000
--- a/src/sixel-context.cc
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright © 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 <https://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include "sixel-context.hh"
-
-#include <algorithm>
-#include <cmath>
-#include <cstdint>
-
-#ifdef VTE_DEBUG
-#include "debug.h"
-#include "libc-glue.hh"
-#endif
-
-namespace vte::sixel {
-
-/* BEGIN */
-
-/* The following code is copied from xterm/graphics.c where it is under the
- * licence below; and modified and used here under the GNU Lesser General Public
- * Licence, version 3 (or, at your option), any later version.
- */
-
-/*
- * Copyright 2013-2019,2020 by Ross Combs
- * Copyright 2013-2019,2020 by Thomas E. Dickey
- *
- * All Rights Reserved
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Except as contained in this notice, the name(s) of the above copyright
- * holders shall not be used in advertising or otherwise to promote the
- * sale, use or other dealings in this Software without prior written
- * authorization.
- */
-
-/*
- * Context::make_color_hls:
- * @h: hue
- * @l: luminosity
- * @s: saturation
- *
- * Returns the colour specified by (h, l, s) as RGB, 8 bit per component.
- *
- * Primary color hues are blue: 0 degrees, red: 120 degrees, and green: 240 degrees.
- */
-Context::color_t
-Context::make_color_hls(int h,
- int l,
- int s) noexcept
-{
- auto const c2p = std::abs(2 * l - 100);
- auto const cp = ((100 - c2p) * s) << 1;
- auto const hs = ((h + 240) / 60) % 6;
- auto const xp = (hs & 1) ? cp : 0;
- auto const mp = 200 * l - (cp >> 1);
-
- int r1p, g1p, b1p;
- switch (hs) {
- case 0:
- r1p = cp;
- g1p = xp;
- b1p = 0;
- break;
- case 1:
- r1p = xp;
- g1p = cp;
- b1p = 0;
- break;
- case 2:
- r1p = 0;
- g1p = cp;
- b1p = xp;
- break;
- case 3:
- r1p = 0;
- g1p = xp;
- b1p = cp;
- break;
- case 4:
- r1p = xp;
- g1p = 0;
- b1p = cp;
- break;
- case 5:
- r1p = cp;
- g1p = 0;
- b1p = xp;
- break;
- default:
- __builtin_unreachable();
- }
-
- auto const r = ((r1p + mp) * 255 + 10000) / 20000;
- auto const g = ((g1p + mp) * 255 + 10000) / 20000;
- auto const b = ((b1p + mp) * 255 + 10000) / 20000;
-
- return make_color(r, g, b);
-}
-
-/* END */
-
-/* This is called when resetting the Terminal which is currently using
- * DataSyntax::DECSIXEL syntax. Clean up buffers, but don't reset colours
- * etc since they will be re-initialised anyway when the context is
- * used the next time.
- */
-void
-Context::reset() noexcept
-{
- /* Keep buffer of default size */
- if (m_scanlines_data_capacity > minimum_capacity()) {
- m_scanlines_data.reset();
- m_scanlines_data_capacity = 0;
- }
-
- m_scanline_begin = m_scanline_pos = m_scanline_end = nullptr;
-}
-
-/*
- * Ensure that the scanlines buffer has space for the image (as specified
- * by the raster and actual dimensions) and at least one full k_max_width
- * scanline.
- *
- * The scanline offsets must be up-to-date before calling this function.
- *
- * On success, m_scanline_begin and m_scanline_pos will point to the start
- * of the current scanline (that is, m_scanline_data + *m_scanlines_offsets_pos),
- * and m_scanline_end will point to the end of the scanline of k_max_width sixels,
- * and %true returned.
- *
- * On failure, all of m_scanline_begin/pos/end will be set to nullptr, and
- * %false returned.
- */
- bool
- Context::ensure_scanlines_capacity() noexcept
- {
- auto const width = std::max(m_raster_width, m_width);
- auto const height = std::max(m_raster_height, m_height);
-
- /* This is guaranteed not to overflow since width and height
- * are limited by k_max_{width,height}.
- */
- auto const needed_capacity = capacity(width, height);
- auto const old_capacity = m_scanlines_data_capacity;
-
- if (needed_capacity <= old_capacity)
- return true;
-
- /* Not enought space, so we need to enlarge the buffer. Don't
- * overallocate, but also don't reallocate too often; so try
- * doubling but use an upper limit.
- */
- auto const new_capacity = std::min(std::max({minimum_capacity(),
- needed_capacity,
- old_capacity * 2}),
- capacity(k_max_width, k_max_height));
-
- m_scanlines_data = vte::glib::take_free_ptr(reinterpret_cast<color_index_t*>(g_try_realloc_n(m_scanlines_data.release(),
- new_capacity,
- sizeof(color_index_t))));
- if (!m_scanlines_data) {
- m_scanlines_data_capacity = 0;
- m_scanline_pos = m_scanline_begin = m_scanline_end = nullptr;
- return false;
- }
-
- /* Clear newly allocated capacity */
- std::memset(m_scanlines_data.get() + old_capacity, 0,
- (new_capacity - old_capacity) * sizeof(*m_scanlines_data.get()));
-
- m_scanlines_data_capacity = new_capacity;
-
- /* Relocate the buffer pointers. The update_scanline_offsets() above
- * made sure that m_scanlines_offsets is up to date.
- */
- auto const old_scanline_pos = m_scanline_pos - m_scanline_begin;
- m_scanline_begin = m_scanlines_data.get() + m_scanlines_offsets_pos[0];
- m_scanline_end = m_scanlines_data.get() + m_scanlines_offsets_pos[1];
- m_scanline_pos = m_scanline_begin + old_scanline_pos;
-
- assert(m_scanline_begin <= scanlines_data_end());
- assert(m_scanline_pos <= scanlines_data_end());
- assert(m_scanline_end <= scanlines_data_end());
-
- return true;
-}
-
-void
-Context::reset_colors() noexcept
-{
- /* DECPPLV2 says that on startup, and after DECSTR, DECSCL and RIS,
- * all colours are assigned to Black, *not* to a palette.
- * Instead, it says that devices may have 8- or 16-colour palettes,
- * and which HLS and RGB values used in DECGCI will result in which
- * of these 8 or 64 colours being actually used.
- *
- * It also says that between DECSIXEL invocations, colour registers
- * are preserved; in xterm, whether colours are kept or cleared,
- * is controlled by the XTERM_SIXEL_PRIVATE_COLOR_REGISTERS private
- * mode.
- */
-
- /* Background fill colour, fully transparent by default */
- m_colors[0] = 0u;
-
- /* This is the VT340 default colour palette of 16 colours.
- * PPLV2 defines 8- and 64-colour palettes; not sure
- * why everyone seems to use the VT340 one?
- *
- * Colours 9..14 (name marked with '*') are less saturated
- * versions of colours 1..6.
- */
- m_colors[0 + 2] = make_color_rgb( 0, 0, 0); /* HLS( 0, 0, 0) */ /* Black */
- m_colors[1 + 2] = make_color_rgb(20, 20, 80); /* HLS( 0, 50, 60) */ /* Blue */
- m_colors[2 + 2] = make_color_rgb(80, 13, 13); /* HLS(120, 46, 72) */ /* Red */
- m_colors[3 + 2] = make_color_rgb(20, 80, 20); /* HLS(240, 50, 60) */ /* Green */
- m_colors[4 + 2] = make_color_rgb(80, 20, 80); /* HLS( 60, 50, 60) */ /* Magenta */
- m_colors[5 + 2] = make_color_rgb(20, 80, 80); /* HLS(300, 50, 60) */ /* Cyan */
- m_colors[6 + 2] = make_color_rgb(80, 80, 20); /* HLS(180, 50, 60) */ /* Yellow */
- m_colors[7 + 2] = make_color_rgb(53, 53, 53); /* HLS( 0, 53, 0) */ /* Grey 50% */
- m_colors[8 + 2] = make_color_rgb(26, 26, 26); /* HLS( 0, 26, 0) */ /* Grey 25% */
- m_colors[9 + 2] = make_color_rgb(33, 33, 60); /* HLS( 0, 46, 29) */ /* Blue* */
- m_colors[10 + 2] = make_color_rgb(60, 26, 26); /* HLS(120, 43, 39) */ /* Red* */
- m_colors[11 + 2] = make_color_rgb(33, 60, 33); /* HLS(240, 46, 29) */ /* Green* */
- m_colors[12 + 2] = make_color_rgb(60, 33, 60); /* HLS( 60, 46, 29) */ /* Magenta* */
- m_colors[13 + 2] = make_color_rgb(33, 60, 60); /* HLS(300, 46, 29) */ /* Cyan* */
- m_colors[14 + 2] = make_color_rgb(60, 60, 33); /* HLS(180, 46, 29) */ /* Yellow* */
- m_colors[15 + 2] = make_color_rgb(80, 80, 80); /* HLS( 0, 80, 0) */ /* Grey 75% */
-
- /* Devices may use the same colour palette for DECSIXEL as for
- * text mode, so initialise colours 16..255 to the standard 256-colour
- * palette. I haven't seen any documentation from DEC that says
- * this is what they actually did, but this is what all the libsixel
- * related terminal emulator patches did, so let's copy that. Except
- * that they use a variant of the 666 colour cube which
- * uses make_color_rgb(r * 51, g * 51, b * 51) instead of the formula
- * below which is the same as for the text 256-colour palette's 666
- * colour cube, and make_color_rgb(i * 11, i * 11, i * 11) instead of
- * the formula below which is the same as for the text 256-colour palette
- * greyscale ramp.
- */
- /* 666-colour cube */
- auto make_cube_color = [&](unsigned r,
- unsigned g,
- unsigned b) constexpr noexcept -> auto
- {
- return make_color(r ? r * 40u + 55u : 0,
- g ? g * 40u + 55u : 0,
- b ? b * 40u + 55u : 0);
- };
-
- for (auto n = 0; n < 216; ++n)
- m_colors[n + 16 + 2] = make_cube_color(n / 36, (n / 6) % 6, n % 6);
-
- /* 24-colour greyscale ramp */
- for (auto n = 0; n < 24; ++n)
- m_colors[n + 16 + 216 + 2] = make_color(8 + n * 10, 8 + n * 10, 8 + n * 10);
-
- /* Set all other colours to black */
- for (auto n = 256 + 2; n < k_num_colors + 2; ++n)
- m_colors[n] = make_color(0, 0, 0);
-}
-
-void
-Context::prepare(uint32_t introducer,
- unsigned fg_red,
- unsigned fg_green,
- unsigned fg_blue,
- unsigned bg_red,
- unsigned bg_green,
- unsigned bg_blue,
- bool bg_transparent,
- bool private_color_registers,
- double pixel_aspect) noexcept
-{
- m_introducer = introducer;
- m_st = 0;
- m_width = m_height = 0;
- m_raster_width = m_raster_height = 0;
-
- if (private_color_registers)
- reset_colors();
-
- if (bg_transparent)
- m_colors[0] = 0u; /* fully transparent */
- else
- m_colors[0] = make_color(bg_red, bg_green, bg_blue);
-
- m_colors[1] = make_color(fg_red, fg_green, fg_blue);
-
- /*
- * DEC PPLV2 says that on entering DECSIXEL mode, the active colour
- * is set to colour register 0. Xterm defaults to register 3.
- * We use the current foreground color in our special register 1.
- */
- set_current_color(1);
-
- /* Clear buffer and scanline offsets */
- std::memset(m_scanlines_offsets, 0, sizeof(m_scanlines_offsets));
-
- if (m_scanlines_data)
- std::memset(m_scanlines_data.get(), 0,
- m_scanlines_data_capacity * sizeof(color_index_t));
-
- m_scanlines_offsets_pos = scanlines_offsets_begin();
- m_scanlines_offsets[0] = 0;
-
- ensure_scanline();
-}
-
-template<typename C,
- typename P>
-inline C*
-Context::image_data(size_t* size,
- unsigned stride,
- P pen) noexcept
-{
- auto const height = image_height();
- auto const width = image_width();
- if (height == 0 || width == 0 || !m_scanlines_data)
- return nullptr;
-
- if (size)
- *size = height * stride;
-
- auto wdata = vte::glib::take_free_ptr(reinterpret_cast<C*>(g_try_malloc_n(height, stride)));
- if (!wdata)
- return nullptr;
-
- /* FIXMEchpe: this can surely be optimised, perhaps using SIMD, and
- * being more cache-friendly.
- */
-
- assert((stride % sizeof(C)) == 0);
- auto wstride = stride / sizeof(C);
- assert(wstride >= width);
- // auto wdata_end = wdata + wstride * height;
-
- /* There may be one scanline at the bottom that extends below the image's height,
- * and needs to be handled specially. First convert all the full scanlines, then
- * the last partial one.
- */
- auto scanlines_offsets_pos = scanlines_offsets_begin();
- auto wdata_pos = wdata.get();
- auto y = 0u;
- for (;
- (scanlines_offsets_pos + 1) < scanlines_offsets_end() && (y + 6) <= height;
- ++scanlines_offsets_pos, wdata_pos += 6 * wstride, y += 6) {
- auto const scanline_begin = m_scanlines_data.get() + scanlines_offsets_pos[0];
- auto const scanline_end = m_scanlines_data.get() + scanlines_offsets_pos[1];
- auto x = 0u;
- for (auto scanline_pos = scanline_begin; scanline_pos < scanline_end; ++x) {
- for (auto n = 0; n < 6; ++n) {
- wdata_pos[n * wstride + x] = pen(*scanline_pos++);
- }
- }
-
- /* Clear leftover space */
- if (x < wstride) {
- auto const bg = pen(0);
- for (auto n = 0; n < 6; ++n) {
- std::fill(&wdata_pos[n * wstride + x],
- &wdata_pos[(n + 1) * wstride],
- bg);
- }
- }
- }
-
- if (y < height && (y + 6) > height &&
- (scanlines_offsets_pos + 1) < scanlines_offsets_end()) {
- auto const h = height - y;
- auto const scanline_begin = m_scanlines_data.get() + scanlines_offsets_pos[0];
- auto const scanline_end = m_scanlines_data.get() + scanlines_offsets_pos[1];
- auto x = 0u;
- for (auto scanline_pos = scanline_begin; scanline_pos < scanline_end; ++x) {
- for (auto n = 0u; n < h; ++n) {
- wdata_pos[n * wstride + x] = pen(*scanline_pos++);
- }
-
- scanline_pos += 6 - h;
- }
-
- /* Clear leftover space */
- if (x < wstride) {
- auto const bg = pen(0);
- for (auto n = 0u; n < h; ++n) {
- std::fill(&wdata_pos[n * wstride + x],
- &wdata_pos[(n + 1) * wstride],
- bg);
- }
- }
- }
-
- /* We drop the scanlines buffer here if it's bigger than the default buffer size,
- * so that parsing a big image doesn't retain the large buffer forever.
- */
- if (m_scanlines_data_capacity > minimum_capacity()) {
- m_scanlines_data.reset();
- m_scanlines_data_capacity = 0;
- }
-
- return wdata.release();
-}
-
-// This is only used in the test suite
-Context::color_index_t*
-Context::image_data_indexed(size_t* size,
- unsigned extra_width_stride) noexcept
-{
- return image_data<color_index_t>(size,
- (image_width() + extra_width_stride) * sizeof(color_index_t),
- [](color_index_t pen) constexpr noexcept -> color_index_t { return pen; });
-}
-
-#ifdef VTE_COMPILATION
-
-uint8_t*
-Context::image_data() noexcept
-{
- return reinterpret_cast<uint8_t*>(image_data<color_t>(nullptr,
- cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, image_width()),
- [&](color_index_t pen) constexpr noexcept -> color_t { return m_colors[pen]; }));
-}
-
-vte::Freeable<cairo_surface_t>
-Context::image_cairo() noexcept
-{
- static cairo_user_data_key_t s_data_key;
-
- auto data = image_data();
- if (!data)
- return nullptr;
-
- auto const stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, image_width());
- auto surface = vte::take_freeable(cairo_image_surface_create_for_data(data,
- CAIRO_FORMAT_ARGB32,
- image_width(),
- image_height(),
- stride));
-
-#ifdef VTE_DEBUG
- _VTE_DEBUG_IF(VTE_DEBUG_IMAGE) {
- static auto num = 0;
-
- auto tmpl = vte::glib::take_string(g_strdup_printf("vte-image-sixel-%05d-XXXXXX.png",
- ++num));
- auto err = vte::glib::Error{};
- char* path = nullptr;
- auto fd = vte::libc::FD{g_file_open_tmp(tmpl.get(), &path, err)};
- if (fd) {
- auto rv = cairo_surface_write_to_png(surface.get(), path);
- if (rv == CAIRO_STATUS_SUCCESS)
- g_printerr("SIXEL Image written to '%s'\n", path);
- else
- g_printerr("Failed to write SIXEL image to '%s': %m\n", path);
- } else {
- g_printerr("Failed to create tempfile for SIXEL image: %s\n", err.message());
- }
- g_free(path);
- }
-#endif /* VTE_DEBUG */
-
- if (cairo_surface_set_user_data(surface.get(),
- &s_data_key,
- data,
- (cairo_destroy_func_t)&g_free) != CAIRO_STATUS_SUCCESS) {
- /* When this fails, it's not documented whether the destroy func
- * will have been called; reading cairo code, it appears it is *not*.
- */
- cairo_surface_finish(surface.get()); // drop data buffer
- g_free(data);
-
- return nullptr;
- }
-
- return surface;
-}
-
-#endif /* VTE_COMPILATION */
-
-} // namespace vte::sixel
diff --git a/src/sixel-context.hh b/src/sixel-context.hh
deleted file mode 100644
index 264f3046..00000000
--- a/src/sixel-context.hh
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * Copyright © 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 <https://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include <bit>
-#include <cstdint>
-#include <iterator>
-#include <utility>
-
-#ifdef VTE_COMPILATION
-#include <cairo.h>
-#include "cairo-glue.hh"
-#endif
-
-#include "glib-glue.hh"
-//#include "parser-glue.hh"
-#include "sixel-parser.hh"
-#include "vtedefines.hh"
-
-namespace vte::sixel {
-
-class Context {
-
- friend class Parser;
-
-public:
- Context() = default;
- ~Context() = default;
-
- Context(Context const&) = delete;
- Context(Context&&) noexcept = delete;
-
- Context& operator=(Context const&) = delete;
- Context& operator=(Context&&) noexcept = delete;
-
- /* Packed colour, RGBA 8 bits per component */
- using color_t = uint32_t;
-
- /* Indexed colour */
- using color_index_t = uint16_t;
-
-private:
-
- uint32_t m_introducer{0};
- uint32_t m_st{0};
-
- static inline constexpr unsigned const k_max_width = VTE_SIXEL_MAX_WIDTH;
-
- static inline constexpr unsigned const k_max_height = VTE_SIXEL_MAX_HEIGHT;
- static_assert((k_max_height % 6) == 0, "k_max_height not divisible by 6");
-
- static inline constexpr int const k_num_colors = VTE_SIXEL_NUM_COLOR_REGISTERS;
- static_assert((k_num_colors & (k_num_colors - 1)) == 0, "k_num_colors not a power of 2");
-
- /* The width and height as set per DECGRA */
- unsigned m_raster_width{0};
- unsigned m_raster_height{0};
-
- /* The width and height as per the SIXEL data received */
- unsigned m_width{0};
- unsigned m_height{0};
-
-public:
-
- constexpr auto max_width() const noexcept { return k_max_width; }
- constexpr auto max_height() const noexcept { return k_max_height; }
- constexpr auto num_colors() const noexcept { return k_num_colors; }
-
- constexpr auto image_width() const noexcept
- {
- return std::max(m_width, m_raster_width);
- }
-
- constexpr auto image_height() const noexcept
- {
- return std::max(m_height, m_raster_height);
- }
-
-private:
-
- color_t m_colors[2 + k_num_colors];
-
- color_index_t m_current_color{0};
-
- Parser m_sixel_parser{};
-
- /* All sixels on the current scanline OR'd together */
- uint8_t m_scanline_mask{0};
-
- int m_repeat_count{1};
-
- /*
- * m_scanlines_data stores the pixel data in indexed colours (not resolved
- * RGBA colours).
- *
- * Pixels are stored interleaved in scan lines of six vertical pixels.
- * This makes writing them cache-efficient, and allows to easily write
- * more pixels in one scanline than the previous scanlines without having
- * to copy and pad already-written data. The buffer is created at the
- * start, and enlarged (if necessary) when starting a new scanline.
- *
- * m_scanlines_data is allocated/re-allocated as needed, and stores
- * m_scanlines_data_capacity color_index_t items.
- *
- * The offsets of the scanlines in m_scanlines_data are stored in
- * m_scanlines_offsets; scanline N occupies
- * [m_scanlines_offsets[N], m_scanlines_offsets[N+1]).
- *
- * m_scanlines_offsets_pos points to the offset in m_scanlines_offsets of the
- * current scanline, and is never nullptr. When in a valid scanline, there is
- * space to write to m_scanlines_offsets_pos[1] to store the scanline end
- * position.
- *
- * m_scanline_begin is a pointer to the current scanline being written;
- * m_scanline_pos is a pointer to the current write position, and
- * m_scanline_end is a pointer to the end of the scanline. All scanlines
- * have space to write up to k_max_width sixels (i.e. have 6 * k_max_width
- * items), regardless of m_width.
- * If allocation fails, or height limits are exceeded, all three pointers
- * are set to nullptr.
- *
- * [FIXME: This could be further improved (e.g. wrt. memory fragmentation) by
- * using a tempfile to store the pixel data, having only a fixed buffer
- * of N * k_max_width * 6 size, and writing out the scanline data on DECGNL,
- * instead of re-/allocating memory for the whole buffer.]
- */
-
- size_t m_scanlines_data_capacity{0};
- vte::glib::FreePtr<color_index_t> m_scanlines_data{};
-
- color_index_t* m_scanline_begin{nullptr};
- color_index_t* m_scanline_end{nullptr};
- color_index_t* m_scanline_pos{nullptr};
- unsigned m_scanlines_offsets[(k_max_height + 5) / 6 + 1]; // one more than the maximum
- // number of scanlines since
- // we need to store begin and
- // end offsets for each scanline
- unsigned* m_scanlines_offsets_pos{nullptr};
-
- inline auto scanlines_data_begin() const noexcept
- {
- return m_scanlines_data.get();
- }
-
- inline auto scanlines_data_end() const noexcept
- {
- return m_scanlines_data.get() + m_scanlines_data_capacity;
- }
-
- inline auto scanlines_offsets_begin() noexcept
- {
- return std::begin(m_scanlines_offsets);
- }
-
- inline constexpr auto scanlines_offsets_end() const noexcept
- {
- return std::end(m_scanlines_offsets);
- }
-
- inline constexpr auto scanline_capacity() const noexcept
- {
- return k_max_width * 6;
- }
-
- inline constexpr auto scanlines_count() const noexcept
- {
- return unsigned(m_scanlines_offsets_pos - std::begin(m_scanlines_offsets));
- }
-
- /* Returns the capacity needed to storage an image of width×height
- * dimensions, plus one max-sized scanline.
- */
- inline constexpr auto
- capacity(size_t const width,
- size_t const height) noexcept
- {
- auto const scanlines = (height + 5) / 6;
- return (width * scanlines + k_max_width) * 6;
- }
-
- inline constexpr auto minimum_capacity() noexcept { return capacity(k_max_width, 64); }
-
- bool ensure_scanlines_capacity() noexcept;
-
- void
- ensure_scanline() noexcept
- {
- if (!ensure_scanlines_capacity()) {
- m_scanline_pos = m_scanline_begin = m_scanline_end = nullptr;
- return;
- }
-
- m_scanlines_offsets_pos[1] = m_scanlines_offsets_pos[0];
- m_scanline_pos = m_scanline_begin = scanlines_data_begin() + m_scanlines_offsets_pos[0];
- m_scanline_end = m_scanline_begin + scanline_capacity();
- }
-
- void
- update_scanline_offsets() noexcept
- {
- /* Update the scanline end offset and the line width */
- auto const width = unsigned(m_scanline_pos - m_scanline_begin);
- assert((width % 6) == 0);
- m_width = std::min(std::max(m_width, width / 6), k_max_width);
-
- auto const pos = unsigned(m_scanline_pos - m_scanlines_data.get());
- assert((pos % 6) == 0);
- m_scanlines_offsets_pos[1] = std::max(m_scanlines_offsets_pos[1], pos);
- }
-
- bool
- finish_scanline()
- {
- if (m_scanline_begin == m_scanline_end)
- return false;
-
- auto msb = [](unsigned v) constexpr noexcept -> unsigned
- {
- return 8 * sizeof(unsigned) - __builtin_clz(v);
- };
-
- static_assert(msb(0b1u) == 1, "wrong");
- static_assert(msb(0b10u) == 2, "wrong");
- static_assert(msb(0b100u) == 3, "wrong");
- static_assert(msb(0b1000u) == 4, "wrong");
- static_assert(msb(0b1'0000u) == 5, "wrong");
- static_assert(msb(0b10'0000u) == 6, "wrong");
- static_assert(msb(0b11'1111u) == 6, "wrong");
-
- /* Update the image height if there was any pixel set in the current scanline. */
- m_height = m_scanline_mask ? std::min(scanlines_count() * 6 + msb(m_scanline_mask), k_max_height) : m_height;
-
- m_scanline_mask = 0;
- m_repeat_count = 1;
-
- update_scanline_offsets();
-
- return true;
- }
-
- inline constexpr auto
- param_to_color_register(int param) noexcept
- {
- /* Colour registers are wrapped, as per DEC documentation.
- *
- * We internally reserve registers 0 and 1 for the background
- * and foreground colors, the buffer being initialized to 0.
- * Therefore the user-provided registers are stored at + 2 their
- * public number.
- */
- return (param & (k_num_colors - 1)) + 2;
- }
-
- inline constexpr color_t
- make_color(unsigned r,
- unsigned g,
- unsigned b) noexcept
- {
- if constexpr (std::endian::native == std::endian::little) {
- return b | g << 8 | r << 16 | 0xffu << 24 /* opaque */;
- } else if constexpr (std::endian::native == std::endian::big) {
- return 0xffu /* opaque */ | r << 8 | g << 16 | b << 24;
- } else {
- __builtin_unreachable();
- }
- }
-
- color_t
- make_color_hls(int h,
- int l,
- int s) noexcept;
-
- inline constexpr color_t
- make_color_rgb(unsigned r,
- unsigned g,
- unsigned b) noexcept
- {
- auto scale = [](unsigned value) constexpr noexcept -> auto
- {
- return (value * 255u + 50u) / 100u;
- };
-
- return make_color(scale(r), scale(g), scale(b));
- }
-
- void
- set_color(color_index_t reg,
- color_t color) noexcept
- {
- m_colors[m_current_color = reg] = color;
- }
-
- void
- set_color_hls(unsigned reg,
- unsigned h,
- unsigned l,
- unsigned s) noexcept
- {
- set_color(reg, make_color_hls(h, l, s));
- }
-
- void
- set_color_rgb(unsigned reg,
- unsigned r,
- unsigned g,
- unsigned b) noexcept
- {
- set_color(reg, make_color_rgb(r, g, b));
- }
-
- void
- set_current_color(unsigned reg) noexcept
- {
- m_current_color = reg;
- }
-
- template<typename C,
- typename P>
- inline C* image_data(size_t* size,
- unsigned stride,
- P pen) noexcept;
-
- void
- DECGCI(vte::sixel::Sequence const& seq) noexcept
- {
- /*
- * DECGCI - DEC Graphics Color Introducer
- * Selects and defines the current colour.
- *
- * Arguments:
- * args[0]: colour register
- * args[1]: colour coordinate system
- * 1: HLS
- * 2: RGB
- * args[2..4]: colour components
- * args[2]: 0..360 for HLS or 0..100 for RGB
- * args[3]: 0..100 for HSL and RGB
- * args[4]: 0..100 for HSL and RGB
- *
- * Defaults:
- * args[0]: 0
- * args[2]: no default
- * args[3..5]: 0
- *
- * If only one parameter is specified, selects the colour register
- * for the following SIXELs to use. If more parameters are specified,
- * additionally re-defines that colour register with the colour
- * specified by the parameters.
- *
- * If the colour values exceed the ranges specified above, the DEC
- * documentation says that the sequence is ignored.
- * [FIXMEchpe: alternatively, we could just clamp to the range]
- * [FIXMEchpe: check whether we need to set the current colour
- * register even in that case]
- *
- * References: DEC PPLV2 § 5.8
- */
-
- m_repeat_count = 1;
-
- auto const reg = param_to_color_register(seq.param(0, 0));
-
- switch (seq.size()) {
- case 0: /* no param means param 0 has default value */
- case 1:
- /* Switch to colour register */
- set_current_color(reg);
- break;
-
- case 2 ... 5:
- switch (seq.param(1)) {
- case -1: /* this parameter admits no default */
- default:
- break;
-
- case 1: /* HLS */ {
- auto const h = seq.param(2, 0);
- auto const l = seq.param(3, 0);
- auto const s = seq.param(4, 0);
- if (G_UNLIKELY(h > 360 || l > 100 || s > 100))
- break;
-
- set_color_hls(reg, h, l, s);
- break;
- }
-
- case 2: /* RGB */ {
- auto const r = seq.param(2, 0);
- auto const g = seq.param(3, 0);
- auto const b = seq.param(4, 0);
- if (G_UNLIKELY(r > 100 || g > 100 || b > 100))
- break;
-
- set_color_rgb(reg, r, g, b);
- break;
- }
- }
- break;
-
- default:
- break;
- }
- }
-
- void
- DECGCR(vte::sixel::Sequence const& seq) noexcept
- {
- /* DECGCR - DEC Graphics Carriage Return
- * Moves the active position to the left margin.
- *
- * (Note: DECCRNLM mode does not apply here.)
- *
- * References: DEC PPLV2 § 5.8
- */
-
- /* Failed already, or exceeded limits */
- if (m_scanline_begin == m_scanline_end)
- return;
-
- /* Update the scanline end offset of the current scanline, and return
- * position to the start of the scanline.
- */
- update_scanline_offsets();
-
- m_repeat_count = 1;
- m_scanline_pos = m_scanline_begin;
- }
-
- void
- DECGNL(vte::sixel::Sequence const& seq) noexcept
- {
- /* DECGNL - DEC Graphics Next Line
- * Moves the active position to the left margin and
- * down by one scanline (6 pixels).
- *
- * References: DEC PPLV2 § 5.8
- */
-
- /* Failed already, or exceeded limits */
- if (!finish_scanline())
- return;
-
- /* Go to next scanline. If the number of scanlines exceeds the maximum
- * (as defined by k_max_height), set the scanline pointers to nullptr.
- */
- ++m_scanlines_offsets_pos;
- if (m_scanlines_offsets_pos + 1 >= scanlines_offsets_end()) {
- m_scanline_pos = m_scanline_begin = m_scanline_end = nullptr;
- return;
- }
-
- ensure_scanline();
- }
-
- void
- DECGRA(vte::sixel::Sequence const& seq) noexcept
- {
- /*
- * DECGRA - DEC Graphics Raster Attributes
- * Selects the raster attributes for the SIXEL data following.
- *
- * Arguments:
- * args[0]: pixel aspect ratio numerator (max: 32k)
- * args[1]: pixel aspect ratio denominator (max: 32k)
- * args[2]: horizontal size (in px) of the image
- * args[3]: vertical size (in px) of the image
- *
- * Defaults:
- * args[0]: 1
- * args[1]: 1
- * args[2]: no default
- * args[3]: no default
-
- * Note that the image will not be clipped to the provided
- * size.
- *
- * References: DEC PPLV2 § 5.8
- */
-
- /* If any SIXEL data, or positioning command (DECGCR, DECGNL) has
- * been received prior to this command, then DECGRA should be ignored.
- * This check only approximates that condition, but that's good enough.
- */
- if (m_scanlines_offsets_pos != scanlines_offsets_begin() ||
- m_scanline_begin != m_scanlines_data.get() ||
- m_scanline_pos != m_scanline_begin ||
- m_scanlines_offsets[1] != 0 ||
- m_scanlines_offsets[1] != m_scanlines_offsets[0])
- return;
-
- #if 0
- /* VTE doesn't currently use the pixel aspect ratio */
- auto const aspect_num = seq.param(0, 1, 1, 1 << 15 /* 32Ki */);
- auto const aspect_den = seq.param(1, 1, 1, 1 << 15 /* 32Ki */);
- auto const pixel_aspect = std::clamp(double(aspect_num) / double(aspect_den), 0.1, 10.0);
- #endif
-
- m_raster_width = seq.param(2, 0, 0, k_max_width);
- m_raster_height = seq.param(3, 0, 0, k_max_height);
-
- /* Nothing else needs to be done here right now; the current
- * scanline has enough space for k_max_width sixels, and the
- * new raster width and height will be taken into account when
- * resizing the m_scanlines_data buffer next.
- */
- }
-
- void
- DECGRI(vte::sixel::Sequence const& seq) noexcept
- {
- /* DECGRI - DEC Graphics Repeat Introducer
- * Specifies the repeat count for the following SIXEL.
- *
- * Arguments:
- * args[0]: the repeat count
- *
- * Defaults:
- * args[0]: 1
- *
- * References: DEC PPLV2 § 5.8
- * DEC STD 070
- */
-
- /* DEC terminals limited the repetition count to 255, but the SIXEL
- * test data includes repeat counts much greater. Since we limit to
- * k_max_width anyway when executing the repeat on the next sixel,
- * don't limit here.
- *
- * A repeat count of 0 is treated like 1.
- */
- m_repeat_count = seq.param(0, 1) ? : 1;
- }
-
- void
- SIXEL(uint8_t sixel) noexcept
- {
- /* SIXEL data
- * Data encodes a scanline of six pixels in the integer range
- * 0x00 .. 0x3f, with the LSB representing the top pixel
- * and the MSB representing the bottom pixel.
- *
- * References: DEC PPLV2 § 5.5.1
- */
-
- if (sixel) {
- auto const color = m_current_color;
- auto const scanline_end = m_scanline_end;
- auto scanline_pos = m_scanline_pos;
-
- for (auto n = m_repeat_count;
- n > 0 && G_LIKELY(scanline_pos < scanline_end);
- --n) {
- /* Note that the scanline has space for at least 6 pixels, wo we
- * don't need to check scanline_pos < scanline_end in this inner loop.
- *
- * FIXMEchpe: this can likely be optimised with some SIMD?
- */
- for (auto mask = 0b1u; mask < 0b100'0000u; mask <<= 1) {
- auto const old_color = *scanline_pos;
- *scanline_pos++ = sixel & mask ? color : old_color;
- }
-
- assert(scanline_pos <= scanline_end);
- }
-
- m_scanline_pos = scanline_pos;
- m_scanline_mask |= sixel;
-
- } else {
- /* If there are no bits to set, just advance the position,
- * making sure to guard against overflow.
- */
- m_scanline_pos = std::clamp(m_scanline_pos + m_repeat_count * 6,
- m_scanline_begin, m_scanline_end);
- }
-
- m_repeat_count = 1;
- }
-
- void
- SIXEL_NOP(vte::sixel::Sequence const& seq) noexcept
- {
- m_repeat_count = 1;
- }
-
- void
- SIXEL_ST(char32_t st) noexcept
- {
- m_st = st;
-
- /* Still need to finish the current scanline. */
- finish_scanline();
- }
-
-public:
-
- void prepare(uint32_t introducer,
- unsigned fg_red,
- unsigned fg_green,
- unsigned fg_blue,
- unsigned bg_red,
- unsigned bg_green,
- unsigned bg_blue,
- bool bg_transparent,
- bool private_color_registers,
- double pixel_aspect = 1.0) noexcept;
-
- void reset_colors() noexcept;
-
- void reset() noexcept;
-
- uint8_t* image_data() noexcept;
-
- // These are only used in the test suite
- color_index_t* image_data_indexed(size_t* size = nullptr,
- unsigned extra_width_stride = 0) noexcept;
- auto color(unsigned idx) const noexcept { return m_colors[idx]; }
-
-#ifdef VTE_COMPILATION
- vte::Freeable<cairo_surface_t> image_cairo() noexcept;
-#endif
-
- void
- set_mode(Parser::Mode mode)
- {
- m_sixel_parser.set_mode(mode);
- }
-
- auto
- parse(uint8_t const* const bufstart,
- uint8_t const* const bufend,
- bool eos) noexcept -> auto
- {
- return m_sixel_parser.parse(bufstart, bufend, eos, *this);
- }
-
- constexpr auto introducer() const noexcept { return m_introducer; }
- constexpr auto st() const noexcept { return m_st; }
-
- constexpr bool
- is_matching_controls() const noexcept
- {
- return ((introducer() ^ st()) & 0x80) == 0;
- }
-
-}; // class Context
-
-} // namespace vte::sixel
diff --git a/src/sixel-fuzzer.cc b/src/sixel-fuzzer.cc
deleted file mode 100644
index 207f3cfd..00000000
--- a/src/sixel-fuzzer.cc
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- * Copyright © 2020 Hans Petter Jansson <hpj@cl.no>
- *
- * 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 <https://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include <termios.h> /* TIOCGWINSZ */
-#include <sys/ioctl.h> /* ioctl() */
-
-#include <glib.h>
-
-/* The image data is stored as a series of palette indexes, with 16 bits
- * per pixel and TRANSPARENT_SLOT indicating transparency. This allows for
- * palette sizes up to 65535 colors.
- *
- * TRANSPARENT_SLOT can be any u16 value. Typically, the first or last
- * slot (0, n_colors) is used. The transparency index is never emitted;
- * instead pixels with this value are left blank in the output. */
-
-#define N_COLORS_MAX 65536
-#define TRANSPARENT_SLOT ((N_COLORS_MAX) - 1)
-
-#define WIDTH_MAX 65536
-#define HEIGHT_MAX 65536
-
-#define N_PIXELS_IN_SIXEL 6
-
-#define PRE_SEQ "\x1bP"
-#define POST_SEQ "\x1b\\"
-
-#define TEST_IMAGE_SIZE_MIN 16
-#define TEST_IMAGE_SIZE_MAX 512
-
-/* Big palettes make our toy printer extremely slow; use with caution */
-#define TEST_PALETTE_SIZE_MIN 1
-#define TEST_PALETTE_SIZE_MAX 16
-
-/* --- Helpers --- */
-
-static int
-random_int_in_range (int min, int max)
-{
- if (min == max)
- return min;
-
- if (min > max) {
- int t = max;
- max = min;
- min = t;
- }
-
- return min + (random () % (max - min));
-}
-
-static int
-round_up_to_multiple (int n, int m)
-{
- n += m - 1;
- return n - (n % m);
-}
-
-static int
-round_down_to_multiple (int n, int m)
-{
- return round_up_to_multiple (n, m + 1) - m;
-}
-
-static void
-memset_u16 (uint16_t *buf, uint16_t val, int n)
-{
- int i;
-
- for (i = 0; i < n; i++) {
- buf [i] = val;
- }
-}
-
-static uint16_t
-pen_to_slot (int i)
-{
- if (i >= TRANSPARENT_SLOT)
- return i + 1;
-
- return i;
-}
-
-static uint8_t
-interp_u8 (uint8_t a, uint8_t b, int fraction, int total)
-{
- uint32_t ta, tb;
-
- assert (fraction >= 0 && fraction <= total);
-
- /* Only one color in palette */
- if (total == 0)
- return a;
-
- ta = (uint32_t) a * (total - fraction) / total;
- tb = (uint32_t) b * fraction / total;
-
- return ta + tb;
-}
-
-static uint32_t
-interp_colors (uint32_t a, uint32_t b, int fraction, int total)
-{
- return interp_u8 (a, b, fraction, total)
- | (interp_u8 (a >> 8, b >> 8, fraction, total) << 8)
- | (interp_u8 (a >> 16, b >> 16, fraction, total) << 16)
- | (interp_u8 (a >> 24, b >> 24, fraction, total) << 24);
-}
-
-static int
-transform_range (int n, int old_min, int old_max, int new_min, int new_max)
-{
- if (new_min == new_max)
- return new_min;
-
- if (n < old_min)
- n = old_min;
- if (n > old_max)
- n = old_max;
-
- return ((n - old_min) * (new_max - new_min) / (old_max - old_min)) + new_min;
-}
-
-/* Transform to sixel color channels, which are in the 0..100 range. */
-static void
-argb_to_sixel_rgb (uint32_t argb, int *r, int *g, int *b)
-{
- *r = transform_range ((argb >> 16) & 0xff, 0, 256, 0, 101);
- *g = transform_range ((argb >> 8) & 0xff, 0, 256, 0, 101);
- *b = transform_range (argb & 0xff, 0, 256, 0, 101);
-}
-
-/* --- Image gen and sixel conversion --- */
-
-typedef struct
-{
- int width, height;
- int n_colors;
- uint32_t palette [N_COLORS_MAX];
- uint16_t *pixels;
-}
-Image;
-
-static void
-image_init (Image *image, int width, int height, int n_colors)
-{
- int alloc_height;
- int n_pixels;
-
- assert (width > 0 && width <= WIDTH_MAX);
- assert (height > 0 && height <= HEIGHT_MAX);
- assert (n_colors > 0 && n_colors < N_COLORS_MAX);
-
- image->width = width;
- image->height = height;
- image->n_colors = n_colors;
-
- alloc_height = round_up_to_multiple (height, N_PIXELS_IN_SIXEL);
-
- n_pixels = width * alloc_height;
- image->pixels = (uint16_t *) malloc (n_pixels * sizeof (uint16_t));
- memset_u16 (image->pixels, TRANSPARENT_SLOT, n_pixels);
-}
-
-static void
-image_deinit (Image *image)
-{
- free (image->pixels);
- image->pixels = NULL;
-}
-
-static void
-image_generate_palette (Image *image, uint32_t first_color, uint32_t last_color)
-{
- int pen;
-
- for (pen = 0; pen < image->n_colors; pen++) {
- image->palette [pen_to_slot (pen)]
- = interp_colors (first_color, last_color, pen, image->n_colors - 1);
- }
-}
-
-static void
-image_set_pixel (Image *image, int x, int y, uint16_t value)
-{
- image->pixels [y * image->width + x] = value;
-}
-
-static uint16_t
-image_get_pixel (const Image *image, int x, int y)
-{
- return image->pixels [y * image->width + x];
-}
-
-static uint8_t
-image_get_sixel (const Image *image, int x, int y, uint16_t value)
-{
- uint8_t sixel = 0;
- int i;
-
- for (i = 0; i < N_PIXELS_IN_SIXEL; i++) {
- uint16_t p = image_get_pixel (image, x, y + N_PIXELS_IN_SIXEL - 1 - i);
-
- sixel <<= 1;
- if (p == value)
- sixel |= 1;
- }
-
- return sixel;
-}
-
-static void
-image_draw_shape (Image *image)
-{
- int y, x;
-
- for (y = 0; y < image->height; y++) {
- int pen = ((image->n_colors - 1) * y + image->height / 2) / image->height;
-
- for (x = 0; x < image->width; x++) {
- if (x == 0 || x == image->width - 1 /* Box left/right */
- || y == 0 || y == image->height - 1 /* Box top/bottom */
- || y == x || y == image->width - 1 - x) /* X diagonals */
- image_set_pixel (image, x, y, pen_to_slot (pen));
- }
- }
-}
-
-static void
-image_generate (Image *image, uint32_t first_color, uint32_t last_color)
-{
- image_generate_palette (image, first_color, last_color);
- image_draw_shape (image);
-}
-
-static void
-image_print_sixels_palette (const Image *image, GString *gstr)
-{
- int pen;
-
- for (pen = 0; pen < image->n_colors; pen++) {
- uint32_t col = image->palette [pen_to_slot (pen)];
- int r, g, b;
-
- argb_to_sixel_rgb (col, &r, &g, &b);
- g_string_append_printf (gstr, "#%d;2;%d;%d;%d",
- pen_to_slot (pen), r, g, b);
- }
-}
-
-static void
-emit_sixels (GString *gstr, uint8_t sixel, int n, uint16_t slot,
- bool pass_ended, uint16_t *emitted_slot_inout,
- bool *need_emit_cr_inout, bool *need_emit_cr_inout_next)
-{
- if (n == 0) {
- return;
- }
-
- if (!pass_ended || sixel != 0) {
- char c = '?' + (char) sixel;
-
- if (*need_emit_cr_inout) {
- g_string_append_c (gstr, '$');
- *need_emit_cr_inout = FALSE;
- }
-
- if (slot != *emitted_slot_inout) {
- g_string_append_printf (gstr, "#%d", slot);
- *emitted_slot_inout = slot;
- }
-
- while (n > 255) {
- g_string_append_printf (gstr, "!255%c", c);
- n -= 255;
- }
-
- if (n >= 4) {
- g_string_append_printf (gstr, "!%d%c", n, c);
- n = 0;
- } else {
- for ( ; n > 0; n--)
- g_string_append_c (gstr, c);
- }
- }
-
- if (sixel != 0)
- *need_emit_cr_inout_next = TRUE;
-}
-
-static void
-image_print_sixels_row (const Image *image, GString *gstr, int y, uint16_t *emitted_slot_inout)
-{
- bool need_emit_cr = FALSE;
- bool need_emit_cr_next = FALSE;
- int pen;
-
- for (pen = 0; pen < image->n_colors; pen++) {
- uint16_t slot = pen_to_slot (pen);
- uint8_t cur_sixel = 0;
- int n_cur_sixel = 0;
- int x;
-
- for (x = 0; x < image->width; x++) {
- uint8_t next_sixel = image_get_sixel (image, x, y, slot);
-
- if (next_sixel == cur_sixel) {
- n_cur_sixel++;
- continue;
- }
-
- emit_sixels (gstr, cur_sixel, n_cur_sixel, slot, FALSE,
- emitted_slot_inout, &need_emit_cr, &need_emit_cr_next);
- cur_sixel = next_sixel;
- n_cur_sixel = 1;
- }
-
- emit_sixels (gstr, cur_sixel, n_cur_sixel, slot, TRUE,
- emitted_slot_inout, &need_emit_cr, &need_emit_cr_next);
- need_emit_cr = need_emit_cr_next;
- }
-
- /* CR + Linefeed */
- g_string_append_c (gstr, '-');
-}
-
-static void
-image_print_sixels_data (const Image *image, GString *gstr)
-{
- uint16_t emitted_slot = TRANSPARENT_SLOT;
- int y;
-
- for (y = 0; y < image->height; y += N_PIXELS_IN_SIXEL) {
- image_print_sixels_row (image, gstr, y, &emitted_slot);
- }
-}
-
-static void
-image_print_sixels (const Image *image, GString *gstr)
-{
- g_string_append_printf (gstr, PRE_SEQ "0;0;0q\"1;1;%d;%d",
- image->width, image->height);
- image_print_sixels_palette (image, gstr);
- image_print_sixels_data (image, gstr);
- g_string_append (gstr, POST_SEQ);
-}
-
-/* --- Main loop and printing --- */
-
-typedef enum
-{
- TEST_MODE_UNSET,
- TEST_MODE_FUZZ
-}
-TestMode;
-
-typedef struct
-{
- TestMode mode;
-
- float delay;
- int n_errors;
- int n_frames;
- int seed;
- int n_scroll;
-
- int term_width_cells, term_height_cells;
- int term_width_pixels, term_height_pixels;
-
- int term_cell_width, term_cell_height;
-}
-Options;
-
-static void
-cursor_to_offset (gint x, gint y, GString *gstr)
-{
- g_string_printf (gstr, "\x1b[%d;%df", y, x);
-}
-
-static void
-cursor_to_random_offset (gint x_max, gint y_max, GString *gstr)
-{
- cursor_to_offset (random_int_in_range (0, x_max),
- random_int_in_range (0, y_max),
- gstr);
-}
-
-static void
-scroll_n_lines (const Options *options, int n, GString *gstr)
-{
- if (n < 1)
- return;
-
- cursor_to_offset (0, options->term_height_cells, gstr);
- for (int i = 0; i < n; i++)
- g_string_append_printf (gstr, "\n");
-}
-
-static void
-print_text (const gchar *text, GString *gstr)
-{
- g_string_append (gstr, text);
-}
-
-static void
-print_random_image (const Options *options, GString *gstr)
-{
- int dim_max = MIN (TEST_IMAGE_SIZE_MAX,
- MAX (TEST_IMAGE_SIZE_MIN,
- MIN (options->term_width_pixels,
- round_down_to_multiple (options->term_height_pixels - options->term_cell_height,
- N_PIXELS_IN_SIXEL))));
- int dim = random_int_in_range (TEST_IMAGE_SIZE_MIN, dim_max + 1);
- Image image;
-
- image_init (&image, dim, dim,
- random_int_in_range (TEST_PALETTE_SIZE_MIN, TEST_PALETTE_SIZE_MAX));
-
- /* In order to produce colors that contrast both white and black backgrounds,
- * limit the range of the red component. This doesn't work reliably with grey
- * backgrounds, but eh. */
- image_generate (&image,
- random_int_in_range (0x00400000, 0x00a00000),
- random_int_in_range (0x00400000, 0x00a00000));
-
- cursor_to_random_offset ((options->term_width_pixels - dim) / options->term_cell_width,
- (options->term_height_pixels - dim) / options->term_cell_height,
- gstr);
- image_print_sixels (&image, gstr);
-
- image_deinit (&image);
-}
-
-static void
-print_random_text (const Options *options, GString *gstr)
-{
- cursor_to_random_offset (options->term_width_cells - strlen ("Hallo!"),
- options->term_height_cells,
- gstr);
- print_text ("Hallo!", gstr);
-}
-
-typedef enum
-{
- FUZZ_REPLACE,
- FUZZ_COPY,
- FUZZ_SWAP,
-
- FUZZ_MAX
-}
-FuzzType;
-
-static void
-fuzz_replace (GString *gstr)
-{
- int a, b;
-
- a = random_int_in_range (0, gstr->len - 1);
- b = a + random_int_in_range (0, MIN (gstr->len - a, 64));
-
- for (int i = a; i < b; i++) {
- gstr->str [i] = random_int_in_range (1, 256);
- }
-}
-
-static void
-fuzz_copy (GString *gstr)
-{
- int a, b, c;
-
- a = random_int_in_range (0, gstr->len - 1);
- b = random_int_in_range (0, MIN (gstr->len - a, 64));
- c = random_int_in_range (0, gstr->len - b);
-
- memcpy (gstr->str + c, gstr->str + a, b);
-}
-
-static void
-fuzz_swap (GString *gstr)
-{
- unsigned char buf [64];
- int a, b, c;
-
- a = random_int_in_range (0, gstr->len - 1);
- b = random_int_in_range (0, MIN (gstr->len - a, 64));
- c = random_int_in_range (0, gstr->len - b);
-
- memcpy (buf, gstr->str + c, b);
- memcpy (gstr->str + c, gstr->str + a, b);
- memcpy (gstr->str + c, buf, b);
-}
-
-static void
-random_fuzz (const Options *options, GString *gstr)
-{
- if (gstr->len < 1)
- return;
-
- for (int i = 0; i < options->n_errors; i++) {
- FuzzType fuzz_type = FuzzType(random () % FUZZ_MAX);
-
- switch (fuzz_type) {
- case FUZZ_REPLACE:
- fuzz_replace (gstr);
- break;
- case FUZZ_COPY:
- fuzz_copy (gstr);
- break;
- case FUZZ_SWAP:
- fuzz_swap (gstr);
- break;
- default:
- break;
- }
- }
-}
-
-static void
-print_loop (const Options *options)
-{
- for (int i = 0; options->n_frames == 0 || i < options->n_frames; i++) {
- GString *gstr;
-
- gstr = g_string_new ("");
-
- scroll_n_lines (options, options->n_scroll, gstr);
-
- if (random () % 2) {
- print_random_image (options, gstr);
- } else {
- print_random_text (options, gstr);
- }
-
- random_fuzz (options, gstr);
-
- fwrite (gstr->str, sizeof (char), gstr->len, stdout);
- g_string_free (gstr, TRUE);
- fflush (stdout);
-
- if (options->delay > 0.000001f)
- g_usleep (options->delay * 1000000.0f);
- }
-}
-
-/* --- Argument parsing and init --- */
-
-static bool
-parse_int (const char *arg, const char *val, int *out)
-{
- char *endptr;
- int ret;
- bool result = FALSE;
-
- assert (arg != NULL);
- assert (val != NULL);
- assert (out != NULL);
-
- if (*val == '\0') {
- fprintf (stderr, "Empty value for argument '%s'. Aborting.\n", arg);
- goto out;
- }
-
- ret = strtol (val, &endptr, 10);
-
- if (*endptr != '\0') {
- fprintf (stderr, "Unrecognized value for argument '%s': '%s'. Aborting.\n", arg, val);
- goto out;
- }
-
- *out = ret;
- result = TRUE;
-
-out:
- return result;
-}
-
-static bool
-parse_float (const char *arg, const char *val, float *out)
-{
- char *endptr;
- float ret;
- bool result = FALSE;
-
- assert (arg != NULL);
- assert (val != NULL);
- assert (out != NULL);
-
- if (*val == '\0') {
- fprintf (stderr, "Empty value for argument '%s'. Aborting.\n", arg);
- goto out;
- }
-
- ret = strtof (val, &endptr);
-
- if (*endptr != '\0') {
- fprintf (stderr, "Unrecognized value for argument '%s': '%s'. Aborting.\n", arg, val);
- goto out;
- }
-
- *out = ret;
- result = TRUE;
-
-out:
- return result;
-}
-
-static bool
-parse_options (Options *options, int argc, char **argv)
-{
- bool result = FALSE;
- int i;
-
- if (argc < 2) {
- fprintf (stderr, "Usage: %s <mode> [options]\n\n"
- "Modes:\n"
- " fuzz Perform fuzzing test.\n\n"
- "Options:\n"
- " -d <float> Delay between frames, in seconds (default: 0.0).\n"
- " -e <int> Maximum number of random errors per frame (default: 0).\n"
- " -n <int> Number of frames to output (default: infinite).\n"
- " -r <int> Random seed to use (default: current time).\n"
- " -s <int> Number of lines to scroll for each frame (default: 0).\n\n",
- argv [0]);
- goto out;
- }
-
- for (i = 1; i < argc; ) {
- const char *arg = argv [i];
- const char *val;
-
- if (!strcmp (arg, "fuzz")) {
- options->mode = TEST_MODE_FUZZ;
- i++;
- continue;
- }
-
- if (i + 1 >= argc)
- break;
-
- val = argv [i + 1];
-
- if (!strcmp (arg, "-d")) {
- if (!parse_float (arg, val, &options->delay))
- goto out;
- i += 2;
- } else if (!strcmp (arg, "-e")) {
- if (!parse_int (arg, val, &options->n_errors))
- goto out;
- i += 2;
- } else if (!strcmp (arg, "-n")) {
- if (!parse_int (arg, val, &options->n_frames))
- goto out;
- i += 2;
- } else if (!strcmp (arg, "-r")) {
- if (!parse_int (arg, val, &options->seed))
- goto out;
- i += 2;
- } else if (!strcmp (arg, "-s")) {
- if (!parse_int (arg, val, &options->n_scroll))
- goto out;
- i += 2;
- } else {
- fprintf (stderr, "Unrecognized option '%s'. Aborting.\n", arg);
- goto out;
- }
- }
-
- if (i != argc) {
- fprintf (stderr, "Stray option '%s'. Aborting.\n", argv [i]);
- goto out;
- }
-
- if (options->mode == TEST_MODE_UNSET) {
- fprintf (stderr, "No test mode specified. Try \"fuzz\".\n");
- goto out;
- }
-
- result = TRUE;
-
-out:
- return result;
-}
-
-static bool
-query_terminal (Options *options)
-{
- struct winsize wsz;
-
- if (ioctl (fileno (stdout), TIOCGWINSZ, &wsz) != 0) {
- fprintf (stderr, "ioctl() failed: %s\n", strerror (errno));
- return FALSE;
- }
-
- options->term_width_cells = wsz.ws_col;
- options->term_height_cells = wsz.ws_row;
- options->term_width_pixels = wsz.ws_xpixel;
- options->term_height_pixels = wsz.ws_ypixel;
-
- if (options->term_width_cells < 4
- || options->term_height_cells < 4) {
- fprintf (stderr, "Terminal window is too small (must be greater than 4x4 cells).\n");
- return FALSE;
- }
-
- if (options->term_width_pixels == 0
- || options->term_height_pixels == 0) {
- fprintf (stderr, "Terminal did not report its pixel size.\n");
- return FALSE;
- }
-
- if (options->term_width_pixels < 16
- || options->term_height_pixels < 16) {
- fprintf (stderr, "Terminal window is too small (must be greater than 16x16 pixels).\n");
- return FALSE;
- }
-
- options->term_cell_width = wsz.ws_xpixel / wsz.ws_col;
- options->term_cell_height = wsz.ws_ypixel / wsz.ws_row;
-
- return TRUE;
-}
-
-/* --- Entry point --- */
-
-int
-main (int argc, char *argv [])
-{
- static Options options = { };
-
- options.seed = (int) time (NULL);
-
- if (!parse_options (&options, argc, argv))
- return 1;
-
- if (!query_terminal (&options))
- return 2;
-
- print_loop (&options);
- return 0;
-}
diff --git a/src/sixel-parser.hh b/src/sixel-parser.hh
deleted file mode 100644
index 850928da..00000000
--- a/src/sixel-parser.hh
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Copyright © 2018, 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 <https://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <cstdio>
-#include <cstring>
-#include <initializer_list>
-#include <type_traits>
-#include <utility>
-
-#include "cxx-utils.hh"
-#include "parser-arg.hh"
-
-#define VTE_SIXEL_PARSER_ARG_MAX (8)
-
-namespace vte::sixel {
-
-class Parser;
-
-enum class Command : uint8_t {
- NONE = 0x20,
- DECGRI = 0x21, // DEC Graphics Repeat Introducer
- DECGRA = 0x22, // DEC Set Raster Attributes
- DECGCI = 0x23, // DEC Graphics Color Introducer
- DECGCR = 0x24, // DEC Graphics Carriage Return
- DECGNL = 0x2d, // DEC Graphics Next Line
- RESERVED_2_05 = 0x25,
- RESERVED_2_06 = 0x26,
- RESERVED_2_07 = 0x27,
- RESERVED_2_08 = 0x28,
- RESERVED_2_09 = 0x29,
- RESERVED_2_10 = 0x2a,
- RESERVED_2_11 = 0x2b,
- RESERVED_2_12 = 0x2c,
- RESERVED_2_14 = 0x2e,
- RESERVED_2_15 = 0x2f,
- RESERVED_3_12 = 0x3c,
- RESERVED_3_13 = 0x3d,
- RESERVED_3_14 = 0x3e,
-};
-
-class Sequence {
-protected:
- friend class Parser;
-
- unsigned m_command{(unsigned)Command::NONE};
- unsigned m_n_args{0};
- vte_seq_arg_t m_args[VTE_SIXEL_PARSER_ARG_MAX]{0, 0, 0, 0, 0, 0 ,0, 0};
-
- constexpr auto capacity() const noexcept
- {
- return sizeof(m_args) / sizeof(m_args[0]);
- }
-
-public:
-
- constexpr Sequence() noexcept = default;
-
- Sequence(Command cmd,
- std::initializer_list<int> params = {}) noexcept
- : m_command(vte::to_integral(cmd))
- {
- assert(params.size() <= capacity());
- for (auto p : params)
- m_args[m_n_args++] = vte_seq_arg_init(std::min(p, 0xffff));
- }
-
- ~Sequence() = default;
-
- Sequence(Sequence const&) noexcept = default;
- Sequence(Sequence&&) noexcept = default;
-
- Sequence& operator=(Sequence const&) noexcept = default;
- Sequence& operator=(Sequence&&) noexcept = default;
-
- constexpr bool
- operator==(Sequence const& rhs) const noexcept
- {
- return command() == rhs.command() &&
- size() == rhs.size() &&
- std::memcmp(m_args, rhs.m_args, m_n_args * sizeof(m_args[0])) == 0;
- }
-
- /* command:
- *
- * Returns: the command the sequence codes for.
- */
- inline constexpr Command command() const noexcept
- {
- return Command(m_command);
- }
-
- /* size:
- *
- * Returns: the number of parameters
- */
- inline constexpr unsigned int size() const noexcept
- {
- return m_n_args;
- }
-
- /* param_default:
- * @idx:
- *
- * Returns: whether the parameter at @idx has default value
- */
- inline constexpr bool param_default(unsigned int idx) const noexcept
- {
- return __builtin_expect(idx < size(), 1) ? vte_seq_arg_default(m_args[idx]) : true;
- }
-
- /* param:
- * @idx:
- * @default_v: the value to use for default parameters
- *
- * Returns: the value of the parameter at index @idx, or @default_v if
- * the parameter at this index has default value, or the index
- * is out of bounds
- */
- inline constexpr int param(unsigned int idx,
- int default_v = -1) const noexcept
- {
- return __builtin_expect(idx < size(), 1) ? vte_seq_arg_value(m_args[idx], default_v) : default_v;
- }
-
- /* param:
- * @idx:
- * @default_v: the value to use for default parameters
- * @min_v: the minimum value
- * @max_v: the maximum value
- *
- * Returns: the value of the parameter at index @idx, or @default_v if
- * the parameter at this index has default value, or the index
- * is out of bounds. The returned value is clamped to the
- * range @min_v..@max_v (or returns min_v, if min_v > max_v).
- */
- inline constexpr int param(unsigned int idx,
- int default_v,
- int min_v,
- int max_v) const noexcept
- {
- auto const v = param(idx, default_v);
- // not using std::clamp() since it's not guaranteed that min_v <= max_v
- return std::max(std::min(v, max_v), min_v);
- }
-
-}; // class Sequence
-
-/* SIXEL parser.
- *
- * Known differences to the DEC terminal SIXEL parser:
- *
- * * Input bytes with the high bit set are ignored, and not processed as if masked
- * with ~0x80; except for C1 controls in Mode::EIGHTBIT mode which will abort parsing
- *
- * * Supports UTF-8 C1 controls. C1 ST will finish parsing; all other C1 controls
- * will abort parsing (in Mode::UTF8)
- *
- * * All C0 controls (except CAN, ESC, SUB) and not just the format effector controls
- * (HT, BS, LF, VT, FF, CR) are ignored, not executed as if received before the DCS start
- *
- * * 3/10 ':' is reserved for future use as subparameter separator analogous to
- * the main parser; any parameter sequences including ':' will be ignored.
- *
- * * When the number of parameter exceeds the maximum (16), DEC executes the function
- * with these parameters, ignoring the excessive parameters; vte ignores the
- * whole function instead.
- */
-
-class Parser {
-public:
- enum class Mode {
- UTF8, /* UTF-8 */
- EIGHTBIT, /* ECMA-35, 8 bit */
- SEVENBIT, /* ECMA-35, 7 bit */
- };
-
- enum class Status {
- CONTINUE = 0,
- COMPLETE,
- ABORT,
- ABORT_REWIND_ONE,
- ABORT_REWIND_TWO,
- };
-
- Parser() = default;
- ~Parser() = default;
-
- Parser(Mode mode) :
- m_mode{mode}
- {
- }
-
-private:
- Parser(Parser const&) = delete;
- Parser(Parser&&) = delete;
-
- Parser& operator=(Parser const&) = delete;
- Parser& operator=(Parser&) = delete;
-
- enum class State {
- GROUND, /* initial state and ground */
- PARAMS, /* have command, now parsing parameters */
- IGNORE, /* ignore until next command */
- ESC, /* have seen ESC, waiting for backslash */
- UTF8_C2, /* have seen 0xC2, waiting for second UTF-8 byte */
- };
-
- Mode m_mode{Mode::UTF8};
- State m_state{State::GROUND};
- Sequence m_seq{};
-
- [[gnu::always_inline]]
- void
- params_clear() noexcept
- {
- /* The (m_n_args+1)th parameter may have been started but not
- * finialised, so it needs cleaning too. All further params
- * have not been touched, so need not be cleaned.
- */
- unsigned int n_args = G_UNLIKELY(m_seq.m_n_args >= VTE_SIXEL_PARSER_ARG_MAX)
- ? VTE_SIXEL_PARSER_ARG_MAX
- : m_seq.m_n_args + 1;
- memset(m_seq.m_args, 0, n_args * sizeof(m_seq.m_args[0]));
-#ifdef PARSER_EXTRA_CLEAN
- /* Assert that the assumed-clean params are actually clean. */
- for (auto n = n_args; n < VTE_SIXEL_PARSER_ARG_MAX; ++n)
- g_assert_cmpuint(m_seq.m_args[n], ==, VTE_SEQ_ARG_INIT_DEFAULT);
-#endif
-
- m_seq.m_n_args = 0;
- }
-
- [[gnu::always_inline]]
- void
- params_overflow() noexcept
- {
- /* An overflow of the parameter number occurs when
- * m_n_arg == VTE_SIXEL_PARSER_ARG_MAX, and either an 0…9
- * is encountered, starting the next param, or an
- * explicit ':' or ';' terminating a (defaulted) (sub)param,
- * or when the next command or sixel data character occurs
- * after a defaulted (sub)param.
- *
- * Transition to IGNORE to ignore the whole sequence.
- */
- transition(0, State::IGNORE);
- }
-
- [[gnu::always_inline]]
- void
- params_finish() noexcept
- {
- if (G_LIKELY(m_seq.m_n_args < VTE_SIXEL_PARSER_ARG_MAX)) {
- if (m_seq.m_n_args > 0 ||
- vte_seq_arg_started(m_seq.m_args[m_seq.m_n_args])) {
- vte_seq_arg_finish(&m_seq.m_args[m_seq.m_n_args], false);
- ++m_seq.m_n_args;
- }
- }
- }
-
- [[gnu::always_inline]]
- Status
- param_finish(uint8_t raw) noexcept
- {
- if (G_LIKELY(m_seq.m_n_args < VTE_SIXEL_PARSER_ARG_MAX - 1)) {
- vte_seq_arg_finish(&m_seq.m_args[m_seq.m_n_args], false);
- ++m_seq.m_n_args;
- } else
- params_overflow();
-
- return Status::CONTINUE;
- }
-
- [[gnu::always_inline]]
- Status
- param(uint8_t raw) noexcept
- {
- if (G_LIKELY(m_seq.m_n_args < VTE_SIXEL_PARSER_ARG_MAX))
- vte_seq_arg_push(&m_seq.m_args[m_seq.m_n_args], raw);
- else
- params_overflow();
-
- return Status::CONTINUE;
- }
-
- template<class D, class = std::void_t<>>
- struct has_SIXEL_CMD_member : std::false_type { };
-
- template<class D>
- struct has_SIXEL_CMD_member<D, std::void_t<decltype(&D::SIXEL_CMD)>> : std::true_type { };
-
- template<class D>
- [[gnu::always_inline]]
- std::enable_if_t<has_SIXEL_CMD_member<D>::value>
- dispatch(uint8_t raw,
- D& delegate) noexcept
- {
- params_finish();
- delegate.SIXEL_CMD(m_seq);
- }
-
- template<class D>
- [[gnu::always_inline]]
- std::enable_if_t<!has_SIXEL_CMD_member<D>::value>
- dispatch(uint8_t raw,
- D& delegate) noexcept
- {
- params_finish();
- switch (m_seq.command()) {
- case Command::DECGRI: return delegate.DECGRI(m_seq);
- case Command::DECGRA: return delegate.DECGRA(m_seq);
- case Command::DECGCI: return delegate.DECGCI(m_seq);
- case Command::DECGCR: return delegate.DECGCR(m_seq);
- case Command::DECGNL: return delegate.DECGNL(m_seq);
- case Command::NONE: return;
- case Command::RESERVED_2_05:
- case Command::RESERVED_2_06:
- case Command::RESERVED_2_07:
- case Command::RESERVED_2_08:
- case Command::RESERVED_2_09:
- case Command::RESERVED_2_10:
- case Command::RESERVED_2_11:
- case Command::RESERVED_2_12:
- case Command::RESERVED_2_14:
- case Command::RESERVED_2_15:
- case Command::RESERVED_3_12:
- case Command::RESERVED_3_13:
- case Command::RESERVED_3_14: return delegate.SIXEL_NOP(m_seq);
- default: __builtin_unreachable(); return;
- }
- }
-
- template<class D>
- [[gnu::always_inline]]
- Status
- data(uint8_t sixel,
- D& delegate) noexcept
- {
- delegate.SIXEL(sixel);
- return Status::CONTINUE;
- }
-
- [[gnu::always_inline]]
- Status
- transition(uint8_t raw,
- State state) noexcept
- {
- m_state = state;
- return Status::CONTINUE;
-
- }
-
- [[gnu::always_inline]]
- Status
- abort(uint8_t raw,
- Status result) noexcept
- {
- transition(raw, State::GROUND);
- return result;
- }
-
- template<class D>
- [[gnu::always_inline]]
- Status
- complete(uint8_t raw,
- D& delegate) noexcept
- {
- transition(raw, State::GROUND);
- delegate.SIXEL_ST(raw);
- return Status::COMPLETE;
- }
-
- [[gnu::always_inline]]
- Status
- consume(uint8_t raw) noexcept
- {
- params_clear();
- m_seq.m_command = raw;
- return transition(raw, State::PARAMS);
- }
-
- [[gnu::always_inline]]
- Status
- nop(uint8_t raw) noexcept
- {
- return Status::CONTINUE;
- }
-
-public:
-
- template<class D>
- Status
- feed(uint8_t raw,
- D& delegate) noexcept
- {
- // Refer to Table 2-2 in DECPPLV2 for information how to handle C0 and C1
- // controls, DEL, and GR data (in 8-bit mode).
- switch (m_state) {
- case State::PARAMS:
- switch (raw) {
- case 0x00 ... 0x17:
- case 0x19:
- case 0x1c ... 0x1f: /* C0 \ { CAN, SUB, ESC } */
- /* FIXMEchpe: maybe only do this for the format effector controls?,
- * and let GROUND handle everything else C0?
- */
- return nop(raw);
- case 0x30 ... 0x39: /* '0' ... '9' */
- return param(raw);
- case 0x3a: /* ':' */
- // Reserved for subparams; just ignore the whole sequence.
- return transition(raw, State::IGNORE);
- case 0x3b: /* ';' */
- return param_finish(raw);
- case 0x7f: /* DEL */
- case 0xa0 ... 0xc1:
- case 0xc3 ... 0xff:
- return nop(raw);
- case 0xc2: /* Start byte for UTF-8 C1 controls */
- if (m_mode == Mode::EIGHTBIT)
- return nop(raw);
-
- [[fallthrough]];
- case 0x80 ... 0x9f:
- if (m_mode == Mode::SEVENBIT)
- return nop(raw);
-
- [[fallthrough]];
- case 0x18: /* CAN */
- case 0x1b: /* ESC */
- case 0x20 ... 0x2f:
- case 0x3c ... 0x7e:
- // Dispatch the current command and continue parsing
- dispatch(raw, delegate);
- [[fallthrough]];
- case 0x1a: /* SUB */
- /* The question is whether SUB should only act like '?' or
- * also dispatch the current sequence. I interpret the DEC
- * docs as indicating it aborts the sequence without dispatching
- * it and only inserts the '?'.
- */
- transition(raw, State::GROUND);;
- }
-
- [[fallthrough]];
- case State::GROUND:
- ground:
- switch (raw) {
- case 0x00 ... 0x17:
- case 0x19:
- case 0x1c ... 0x1f: /* C0 \ { CAN, SUB, ESC } */
- // According to DECPPLV2, the format effector controls
- // (HT, BS, LF, VT, FF, CR) should be executed as if
- // received before the DECSIXEL DCS, and then processing
- // to continue for the control string, and the other C0
- // controls should be ignored.
- // VTE just ignores all C0 controls except ESC, CAN, SUB
- return nop(raw);
- case 0x18: /* CAN */
- return abort(raw, Status::ABORT_REWIND_ONE);
- case 0x1b: /* ESC */
- return transition(raw, State::ESC);
- case 0x20: /* SP */
- return nop(raw);
- case 0x21 ... 0x2f:
- case 0x3c ... 0x3e:
- return consume(raw);
- case 0x30 ... 0x3b: /* { '0' .. '9', ':', ';' } */
- // Parameters, but we don't have a command yet.
- // Ignore the whole sequence.
- return transition(raw, State::IGNORE);
- case 0x1a: /* SUB */
- // Same as 3/15 '?' according to DECPPLV2
- raw = 0x3fu;
- [[fallthrough]];
- case 0x3f ... 0x7e: /* { '?' .. '~' } */
- // SIXEL data
- return data(raw - 0x3f, delegate);
- case 0x7f: /* DEL */
- // Ignore according to DECPPLV2
- return nop(raw);
- case 0xc2: /* Start byte for UTF-8 C1 controls */
- if (m_mode == Mode::UTF8)
- return transition(raw, State::UTF8_C2);
- return nop(raw);
- case 0x9c: /* raw C1 ST */
- if (m_mode == Mode::EIGHTBIT)
- return complete(raw, delegate);
- [[fallthrough]];
- case 0x80 ... 0x9b:
- case 0x9d ... 0x9f: /* raw C1 \ { ST } */
- // Abort and execute C1 control
- if (m_mode == Mode::EIGHTBIT)
- return abort(raw, Status::ABORT_REWIND_ONE);
- [[fallthrough]];
- case 0xa0 ... 0xc1:
- case 0xc3 ... 0xff: /* GR */
- return nop(raw);
-
- }
- break;
-
- case State::IGNORE:
- switch (raw) {
- // FIXMEchpe do we need to nop() C0 constrols (except SUB, CAN, ESC) here?
- case 0x30 ... 0x3b: /* { '0' .. '9', ':', ';' } */
- case 0x7f: /* DEL */
- return nop(raw);
- case 0x00 ... 0x2f:
- case 0x3c ... 0x7e:
- case 0x80 ... 0xff:
- transition(raw, State::GROUND);
- goto ground;
- }
- break;
-
- case State::ESC:
- switch (raw) {
- case 0x5c: /* '\' */
- return complete(raw, delegate);
- case 0x7f: /* DEL */
- // FIXMEchpe is this correct? check with main parser / spec / DEC
- return nop(raw);
- case 0x00 ... 0x5b:
- case 0x5d ... 0x7e:
- case 0x80 ... 0xff:
- /* Abort and let the outer parser handle the ESC again */
- return abort(raw, Status::ABORT_REWIND_TWO);
- }
- break;
-
- case State::UTF8_C2:
- switch (raw) {
- case 0x1b: /* ESC */
- return transition(raw, State::ESC);
- case 0x80 ... 0x9b:
- case 0x9d ... 0x9f: /* C1 \ { ST } */
- /* Abort and let the outer parser handle the C1 control again */
- return abort(raw, Status::ABORT_REWIND_TWO);
- case 0x9c: /* ST */
- return complete(raw, delegate);
- case 0xc2:
- return transition(raw, State::UTF8_C2);
- case 0x00 ... 0x1a:
- case 0x1c ... 0x7f: /* including DEL */
- case 0xa0 ... 0xc1:
- case 0xc3 ... 0xff:
- transition(raw, State::GROUND);
- goto ground;
- }
- break;
- default:
- break;
- }
- __builtin_unreachable();
- return Status::CONTINUE;
- }
-
- template<class D>
- Status
- flush(D& delegate) noexcept
- {
- switch (m_state) {
- case State::PARAMS:
- dispatch(0, delegate);
- [[fallthrough]];
- case State::GROUND:
- case State::IGNORE:
- return abort(0, Status::ABORT);
- default:
- __builtin_unreachable();
- [[fallthrough]];
- case State::ESC:
- case State::UTF8_C2:
- return abort(0, Status::ABORT_REWIND_ONE);
- }
- }
-
- void
- reset() noexcept
- {
- transition(0, State::GROUND);
- }
-
- void
- set_mode(Mode mode) noexcept
- {
- reset();
- m_mode = mode;
- }
-
- constexpr auto const& sequence() const noexcept { return m_seq; }
-
- enum class ParseStatus {
- CONTINUE,
- COMPLETE,
- ABORT
- };
-
- template<class D>
- std::pair<ParseStatus, uint8_t const*>
- parse(uint8_t const* const bufstart,
- uint8_t const* const bufend,
- bool eos,
- D& delegate) noexcept
- {
- for (auto sptr = bufstart; sptr < bufend; ) {
- switch (feed(*(sptr++), delegate)) {
- case vte::sixel::Parser::Status::CONTINUE:
- break;
-
- case vte::sixel::Parser::Status::COMPLETE:
- return {ParseStatus::COMPLETE, sptr};
-
- case vte::sixel::Parser::Status::ABORT_REWIND_TWO:
- --sptr;
- [[fallthrough]];
- case vte::sixel::Parser::Status::ABORT_REWIND_ONE:
- --sptr;
- [[fallthrough]];
- case vte::sixel::Parser::Status::ABORT:
- return {ParseStatus::ABORT, sptr};
- }
- }
-
- if (eos) {
- auto sptr = bufend;
- switch (flush(delegate)) {
- case vte::sixel::Parser::Status::CONTINUE:
- break;
-
- case vte::sixel::Parser::Status::COMPLETE:
- return {ParseStatus::COMPLETE, sptr};
-
- case vte::sixel::Parser::Status::ABORT_REWIND_TWO:
- --sptr;
- [[fallthrough]];
- case vte::sixel::Parser::Status::ABORT_REWIND_ONE:
- --sptr;
- [[fallthrough]];
- case vte::sixel::Parser::Status::ABORT:
- return {ParseStatus::ABORT, sptr};
- }
- }
-
- return {ParseStatus::CONTINUE, bufend};
- }
-
-}; // class Parser
-
-} // namespace vte::sixel
diff --git a/src/sixel-test.cc b/src/sixel-test.cc
deleted file mode 100644
index adc7cbac..00000000
--- a/src/sixel-test.cc
+++ /dev/null
@@ -1,1597 +0,0 @@
-/*
- * Copyright © 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 <https://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <initializer_list>
-#include <string>
-#include <variant>
-#include <vector>
-
-#include <glib.h>
-
-#include "sixel-parser.hh"
-#include "sixel-context.hh"
-
-using namespace std::literals;
-
-using Command = vte::sixel::Command;
-using Context = vte::sixel::Context;
-using Mode = vte::sixel::Parser::Mode;
-using ParseStatus = vte::sixel::Parser::ParseStatus;
-
-// Parser tests
-
-static inline constexpr auto
-param_to_color_register(unsigned reg)
-{
- return reg + 2; /* Public colour registers start at 2 */
-}
-
-static char const*
-cmd_to_str(Command command)
-{
- switch (command) {
- case Command::DECGRI: return "DECGRI";
- case Command::DECGRA: return "DECGRA";
- case Command::DECGCI: return "DECGCI";
- case Command::DECGCR: return "DECGCR";
- case Command::DECGNL: return "DECGNL";
- case Command::NONE: return "NONE";
- default:
- static char buf[32];
- snprintf(buf, sizeof(buf), "UNKOWN(%d/%02d)",
- (int)command / 16,
- (int)command % 16);
- return buf;
- }
-}
-
-enum class StType {
- C0,
- C1_UTF8,
- C1_EIGHTBIT
-};
-
-inline constexpr auto
-ST(StType type)
-{
- switch (type) {
- case StType::C0: return "\e\\"sv;
- case StType::C1_UTF8: return "\xc2\x9c"sv;
- case StType::C1_EIGHTBIT: return "\x9c"sv;
- default: __builtin_unreachable();
- }
-}
-
-inline constexpr auto
-ST(Mode mode)
-{
- switch (mode) {
- case Mode::UTF8: return ST(StType::C1_UTF8);
- case Mode::EIGHTBIT: return ST(StType::C1_EIGHTBIT);
- case Mode::SEVENBIT: return ST(StType::C0);
- default: __builtin_unreachable();
- }
-}
-
-class Sequence : public vte::sixel::Sequence {
-public:
- using Base = vte::sixel::Sequence;
-
- Sequence(Base const& seq)
- : Base{seq}
- {
- }
-
- Sequence(Command cmd,
- std::vector<int> const& params) noexcept
- : Base{cmd}
- {
- assert(params.size() <= (sizeof(m_args) / sizeof(m_args[0])));
- for (auto p : params)
- m_args[m_n_args++] = vte_seq_arg_init(std::min(p, 0xffff));
- }
-
- void append(std::string& str) const
- {
- if (command() != Command::NONE)
- str.append(1, char(command()));
- for (auto i = 0u; i < size(); ++i) {
- auto const p = param(i);
- if (p != -1) {
- char buf[12];
- auto const len = g_snprintf(buf, sizeof(buf), "%d", p);
- str.append(buf, len);
- }
- if ((i + 1) < size())
- str.append(1, ';');
- }
- }
-
- void prettyprint(std::string& str) const
- {
- str.append("Sequence(");
- str.append(cmd_to_str(command()));
- if (size()) {
- str.append(" ");
- for (auto i = 0u; i < size(); ++i) {
- auto const p = param(i);
-
- char buf[12];
- auto const len = g_snprintf(buf, sizeof(buf), "%d", p);
- str.append(buf, len);
-
- if ((i + 1) < size())
- str.append(1, ';');
- }
- }
- str.append(")");
- }
-};
-
-constexpr bool operator==(Sequence const& lhs, Sequence const& rhs) noexcept
-{
- if (lhs.command() != rhs.command())
- return false;
-
- auto const m = std::min(lhs.size(), rhs.size());
- for (auto n = 0u; n < m; ++n)
- if (lhs.param(n) != rhs.param(n))
- return false;
-
- if (lhs.size() == rhs.size())
- return true;
-
- if ((lhs.size() == (rhs.size() + 1)) && lhs.param(rhs.size()) == -1)
- return true;
-
- if (((lhs.size() + 1) == rhs.size()) && rhs.param(lhs.size()) == -1)
- return true;
-
- return false;
-}
-
-class Sixel {
-public:
- constexpr Sixel(uint8_t sixel)
- : m_sixel(sixel)
- {
- assert(m_sixel < 0b100'0000);
- }
-
- ~Sixel() = default;
-
- constexpr auto sixel() const noexcept { return m_sixel; }
-
- void append(std::string& str) const { str.append(1, char(m_sixel + 0x3f)); }
-
- void prettyprint(std::string& str) const
- {
- str.append("Sixel(");
- char buf[3];
- auto const len = g_snprintf(buf, sizeof(buf), "%02x", sixel());
- str.append(buf, len);
- str.append(")");
- }
-
-private:
- uint8_t m_sixel{0};
-};
-
-constexpr bool operator==(Sixel const& lhs, Sixel const& rhs) noexcept
-{
- return lhs.sixel() == rhs.sixel();
-}
-
-class Unicode {
-public:
- Unicode(char32_t c) :
- m_c{c}
- {
- m_utf8_len = g_unichar_to_utf8(c, m_utf8_buf);
- }
- ~Unicode() = default;
-
- constexpr auto unicode() const noexcept { return m_c; }
-
- void append(std::string& str) const { str.append(m_utf8_buf, m_utf8_len); }
-
- void prettyprint(std::string& str) const
- {
- str.append("Unicode(");
- char buf[7];
- auto const len = g_snprintf(buf, sizeof(buf), "%04X", unicode());
- str.append(buf, len);
- str.append(")");
- }
-
-private:
- char32_t m_c{0};
- size_t m_utf8_len{0};
- char m_utf8_buf[4]{0, 0, 0, 0};
-};
-
-constexpr bool operator==(Unicode const& lhs, Unicode const& rhs) noexcept
-{
- return lhs.unicode() == rhs.unicode();
-}
-
-class C0Control {
-public:
- C0Control(uint8_t c) :
- m_control{c}
- {
- assert(c < 0x20 || c == 0x7f);
- }
- ~C0Control() = default;
-
- constexpr auto control() const noexcept { return m_control; }
-
- void append(std::string& str) const { str.append(1, char(m_control)); }
-
- void prettyprint(std::string& str) const
- {
- str.append("C0(");
- char buf[3];
- auto const len = g_snprintf(buf, sizeof(buf), "%02X", control());
- str.append(buf, len);
- str.append(")");
- }
-
-private:
- uint8_t m_control{0};
-};
-
-constexpr bool operator==(C0Control const& lhs, C0Control const& rhs) noexcept
-{
- return lhs.control() == rhs.control();
-}
-
-class C1Control {
-public:
- C1Control(uint8_t c) :
- m_control{c}
- {
- assert(c >= 0x80 && c < 0xa0);
- auto const len = g_unichar_to_utf8(c, m_utf8_buf);
- assert(len == 2);
- }
- ~C1Control() = default;
-
- constexpr auto control() const noexcept { return m_control; }
-
- void append(std::string& str,
- Mode mode) const {
- switch (mode) {
- case Mode::UTF8:
- str += std::string_view(m_utf8_buf, 2);
- break;
- case Mode::EIGHTBIT:
- str.append(1, char(m_control));
- break;
- case Mode::SEVENBIT:
- str.append(1, char(0x1b));
- str.append(1, char(m_control - 0x40));
- break;
- }
- }
-
- void prettyprint(std::string& str) const
- {
- str.append("C1(");
- char buf[3];
- auto const len = g_snprintf(buf, sizeof(buf), "%02X", control());
- str.append(buf, len);
- str.append(")");
- }
-
-private:
- uint8_t m_control{0};
- char m_utf8_buf[2]{0, 0};
-};
-
-constexpr bool operator==(C1Control const& lhs, C1Control const& rhs) noexcept
-{
- return lhs.control() == rhs.control();
-}
-
-class Raw {
-public:
- Raw(uint8_t raw) :
- m_raw{raw}
- {
- }
- ~Raw() = default;
-
- constexpr auto raw() const noexcept { return m_raw; }
-
- void append(std::string& str) const { str += char(m_raw); }
-
- void prettyprint(std::string& str) const
- {
- str.append("Raw(");
- char buf[3];
- auto const len = g_snprintf(buf, sizeof(buf), "%02X", raw());
- str.append(buf, len);
- str.append(")");
- }
-
-private:
- uint8_t m_raw{0};
-};
-
-constexpr bool operator==(Raw const& lhs, Raw const& rhs) noexcept
-{
- return lhs.raw() == rhs.raw();
-}
-
-inline auto
-DECGRI(int count) noexcept
-{
- return Sequence{Command::DECGRI, {count}};
-}
-
-inline auto
-DECGRA(int an,
- int ad,
- int w,
- int h) noexcept
-{
- return Sequence{Command::DECGRA, {an, ad, w, h}};
-}
-
-inline auto
-DECGCI(int reg) noexcept
-{
- return Sequence{Command::DECGCI, {reg}};
-}
-
-inline auto
-DECGCI_HLS(int reg,
- int h,
- int l,
- int s) noexcept
-{
- return Sequence{Command::DECGCI, {reg, 1, h, l, s}};
-}
-
-inline auto
-DECGCI_RGB(int reg,
- int r,
- int g,
- int b) noexcept
-{
- return Sequence{Command::DECGCI, {reg, 2, r, g, b}};
-}
-
-inline auto
-DECGCR() noexcept
-{
- return Sequence{Command::DECGCR};
-}
-
-inline auto
-DECGNL() noexcept
-{
- return Sequence{Command::DECGNL};
-}
-
-using Item = std::variant<Sequence, Sixel, C0Control, C1Control, Unicode, Raw>;
-using ItemList = std::vector<Item>;
-
-#if 0
-
-class ItemPrinter {
-public:
- ItemPrinter(Item const& item)
- {
- std::visit(*this, item);
- }
-
- ~ItemPrinter() = default;
-
- std::string const& string() const noexcept { return m_str; }
- std::string_view string_view() const noexcept { return m_str; }
-
- void operator()(Sequence const& seq) { seq.prettyprint(m_str); }
- void operator()(Sixel const& sixel) { sixel.prettyprint(m_str); }
- void operator()(C0Control const& control) { control.prettyprint(m_str); }
- void operator()(C1Control const& control) { control.prettyprint(m_str); }
- void operator()(Unicode const& unicode) { unicode.prettyprint(m_str); }
- void operator()(Raw const& raw) { raw.prettyprint(m_str); }
-
-private:
- std::string m_str{};
-};
-
-static void
-print_items(char const* intro,
- ItemList const& items)
-{
- auto str = std::string{};
-
- for (auto const& item : items) {
- str += ItemPrinter{item}.string();
- str += " ";
- }
-
- g_printerr("%s: %s\n", intro, str.c_str());
-}
-
-#endif
-
-class ItemStringifier {
-public:
- ItemStringifier(Mode mode = Mode::UTF8) :
- m_mode{mode}
- { }
-
- ItemStringifier(Item const& item,
- Mode mode = Mode::UTF8) :
- m_mode{mode}
- {
- std::visit(*this, item);
- }
-
- ItemStringifier(ItemList const& items,
- Mode mode = Mode::UTF8) :
- m_mode{mode}
- {
- for (auto&& i : items)
- std::visit(*this, i);
- }
-
- ~ItemStringifier() = default;
-
- std::string string() const noexcept { return m_str; }
- std::string_view string_view() const noexcept { return m_str; }
-
- void operator()(Sequence const& seq) { seq.append(m_str); }
- void operator()(Sixel const& sixel) { sixel.append(m_str); }
- void operator()(C0Control const& control) { control.append(m_str); }
- void operator()(C1Control const& control) { control.append(m_str, m_mode); }
- void operator()(Unicode const& unicode) { unicode.append(m_str); }
- void operator()(Raw const& raw) { raw.append(m_str); }
-
-private:
- std::string m_str{};
- Mode m_mode;
-};
-
-class SimpleContext {
-
- friend class Parser;
-public:
- SimpleContext() = default;
- ~SimpleContext() = default;
-
- auto parse(std::string_view const& str,
- size_t end_pos = size_t(-1))
- {
- auto const beginptr = reinterpret_cast<uint8_t const*>(str.data());
- auto const endptr = reinterpret_cast<uint8_t const*>(beginptr + str.size());
- return m_parser.parse(beginptr, endptr, true, *this);
- }
-
- auto parse(Item const& item,
- Mode input_mode)
- {
- return parse(ItemStringifier{{item}, input_mode}.string_view());
- }
-
- auto parse(ItemList const& list,
- Mode input_mode)
- {
- return parse(ItemStringifier{list, input_mode}.string_view());
- }
-
- void set_mode(Mode mode)
- {
- m_parser.set_mode(mode);
- }
-
- void reset_mode()
- {
- set_mode(Mode::UTF8);
- }
-
- void reset()
- {
- m_parser.reset();
- m_parsed_items.clear();
- m_st = 0;
- }
-
- auto const& parsed_items() const noexcept { return m_parsed_items; }
-
- void SIXEL(uint8_t raw) noexcept
- {
- m_parsed_items.push_back(Sixel(raw));
- }
-
- void SIXEL_CMD(vte::sixel::Sequence const& seq) noexcept
- {
- m_parsed_items.push_back(Sequence(seq));
- }
-
- void SIXEL_ST(char32_t st) noexcept
- {
- m_st = st;
- }
-
- vte::sixel::Parser m_parser{};
- ItemList m_parsed_items{};
- char32_t m_st{0};
-
-}; // class SimpleContext
-
-/*
- * assert_parse:
- * @context:
- * @mode:
- * @str:
- * @str_size:
- * @expected_parsed_len:
- * @expected_status:
- *
- * Asserts that parsing @str (up to @str_size, or until its size if @str_size is -1)
- * in mode @mode results in @expected_status, with the endpointer pointing to the end
- * of @str if @expected_parsed_len is -1, or to @expected_parsed_len otherwise.
- */
-template<class C>
-static void
-assert_parse(C& context,
- Mode mode,
- std::string_view const& str,
- size_t str_size = size_t(-1),
- size_t expected_parse_end = size_t(-1),
- ParseStatus expected_status = ParseStatus::COMPLETE,
- int line = __builtin_LINE())
-{
- context.reset();
- context.set_mode(mode);
-
- auto const beginptr = reinterpret_cast<uint8_t const*>(str.data());
- auto const len = str_size == size_t(-1) ? str.size() : str_size;
- auto const [status, ip] = context.parse(str, len);
- auto const parsed_len = size_t(ip - beginptr);
-
- g_assert_cmpint(int(status), ==, int(expected_status));
- g_assert_cmpint(parsed_len, ==, expected_parse_end == size_t(-1) ? len : expected_parse_end);
-}
-
-/*
- * assert_parse:
- * @context:
- * @mode:
- * @str:
- * @expected_items:
- * @str_size:
- * @expected_parsed_len:
- * @expected_status:
- *
- * Asserts that parsing @str (up to @str_size, or until its size if @str_size is -1)
- * in mode @mode results in @expected_status, with the parsed items equal to
- * @expected_items, and the endpointer pointing to the end of @str if @expected_parsed_len
- * is -1, or to @expected_parsed_len otherwise.
- */
-template<class C>
-static void
-assert_parse(C& context,
- Mode mode,
- std::string_view const& str,
- ItemList const& expected_items,
- size_t str_size = size_t(-1),
- size_t expected_parse_end = size_t(-1),
- ParseStatus expected_status = ParseStatus::COMPLETE,
- int line = __builtin_LINE())
-{
- assert_parse(context, mode, str, str_size, expected_parse_end, expected_status, line);
-
- g_assert_true(context.parsed_items() == expected_items);
-}
-
-/*
- * assert_parse_st:
- *
- * Like assert_parse above, but ST-terminates the passed string.
- */
-template<class C>
-static void
-assert_parse_st(C& context,
- Mode mode,
- std::string_view const& str,
- size_t str_size = size_t(-1),
- size_t expected_parse_end = size_t(-1),
- ParseStatus expected_status = ParseStatus::COMPLETE,
- StType st = StType::C0,
- int line = __builtin_LINE())
-{
- auto str_st = std::string{str};
- str_st.append(ST(st));
- auto str_st_size = str_size;
-
- assert_parse(context, mode, str_st, str_st_size, expected_parse_end, expected_status, line);
-}
-
-/*
- * assert_parse_st:
- *
- * Like assert_parse above, but ST-terminates the passed string.
- */
-template<class C>
-static void
-assert_parse_st(C& context,
- Mode mode,
- std::string_view const& str,
- ItemList const& expected_items,
- size_t str_size = size_t(-1),
- size_t expected_parse_end = size_t(-1),
- ParseStatus expected_status = ParseStatus::COMPLETE,
- StType st = StType::C0,
- int line = __builtin_LINE())
-{
- auto str_st = std::string{str};
- str_st.append(ST(st));
- auto str_st_size = str_size == size_t(-1) ? str_st.size() : str_size;
-
- assert_parse(context, mode, str_st, expected_items, str_st_size, expected_parse_end, expected_status, line);
-}
-
-/*
- * assert_parse_st:
- *
- * Like assert_parse above, but ST-terminates the passed string.
- */
-template<class C>
-static void
-assert_parse_st(C& context,
- Mode mode,
- ItemList const& items,
- ItemList const& expected_items,
- ParseStatus expected_status = ParseStatus::COMPLETE,
- StType st = StType::C0,
- int line = __builtin_LINE())
-{
- assert_parse_st(context, mode, ItemStringifier{items, mode}.string_view(), expected_items, -1, -1, expected_status, st, line);
-}
-
-static void
-test_parser_seq_params(SimpleContext& context,
- Mode mode,
- std::vector<int> const& params)
-{
- for (auto i = 0x20; i < 0x3f; ++i) {
- if (i >= 0x30 && i < 0x3c) // Parameter characters
- continue;
-
-
- auto const items = ItemList{Sequence{Command(i), params}};
- assert_parse_st(context, mode, items,
- (i == 0x20) ? ItemList{} /* 0x20 is ignored */ : items);
- }
-}
-
-static void
-test_parser_seq_params(SimpleContext& context,
- vte_seq_arg_t params[8],
- bool as_is = false)
-{
- for (auto mode : {Mode::UTF8, Mode::EIGHTBIT, Mode::SEVENBIT}) {
- context.set_mode(mode);
-
- for (auto n = 0; n <= 8; ++n) {
- auto pv = std::vector<int>(&params[0], &params[n]);
-
- test_parser_seq_params(context, mode, pv);
-
- if (n > 0 && !as_is) {
- pv[n - 1] = -1;
- test_parser_seq_params(context, mode, pv);
- }
- }
- }
-
- context.reset_mode();
-}
-
-static void
-test_parser_seq_params(void)
-{
- auto context = SimpleContext{};
-
- /* Tests sixel commands, which have the form I P...P with an initial byte
- * in the 2/0..2/15, 3/12..3/14 range, and parameter bytes P from 3/0..3/11.
- */
- vte_seq_arg_t params1[8]{1, 0, 1000, 10000, 65534, 65535, 65536, 1};
- test_parser_seq_params(context, params1);
-
- vte_seq_arg_t params2[8]{1, -1, -1, -1, 1, -1, 1, 1};
- test_parser_seq_params(context, params2, true);
-}
-
-static void
-test_parser_seq_subparams(void)
-{
- // Test that subparams cause the whole sequence to be ignored
-
- auto context = SimpleContext{};
-
- for (auto mode : {Mode::UTF8, Mode::EIGHTBIT, Mode::SEVENBIT}) {
-
- assert_parse_st(context, mode, "#0;1:2;#:#;1;3:#;:;;"sv, ItemList{});
- }
-}
-
-static void
-test_parser_seq_params_clear(void)
-{
- /* Check that parameters are cleared from the last sequence */
-
- auto context = SimpleContext{};
-
- for (auto mode : {Mode::UTF8, Mode::EIGHTBIT, Mode::SEVENBIT}) {
- auto items = ItemList{Sequence{Command::DECGCI, {0, 1, 2, 3, 4, 5, 6, 7}},
- Sequence{Command::DECGRI, {5, 3}},
- Sequence{Command::DECGNL}};
- assert_parse_st(context, mode, items, items);
-
- auto parsed_items = context.parsed_items();
-
- /* Verify that non-specified paramaters have default value */
- auto& item1 = std::get<Sequence>(parsed_items[1]);
- for (auto n = 2; n < 8; ++n)
- g_assert_cmpint(item1.param(n), ==, -1);
-
-
- auto& item2 = std::get<Sequence>(parsed_items[2]);
- for (auto n = 0; n < 8; ++n)
- g_assert_cmpint(item2.param(n), ==, -1);
- }
-}
-
-static void
-test_parser_seq_params_max(void)
-{
- /* Check that an excessive number of parameters causes the
- * sequence to be ignored.
- */
-
- auto context = SimpleContext{};
-
- auto items = ItemList{Sequence{Command::DECGRA, {0, 1, 2, 3, 4, 5, 6, 7}}};
- auto str = ItemStringifier{items, Mode::SEVENBIT}.string();
-
- /* The sequence with VTE_SIXEL_PARSER_ARG_MAX args must be parsed */
- assert_parse_st(context, Mode::UTF8, str, items);
-
- /* Now test that adding one more parameter (whether with an
- * explicit value, or default), causes the sequence to be ignored.
- */
- assert_parse_st(context, Mode::UTF8, str + ";8"s, ItemList{});
- assert_parse_st(context, Mode::UTF8, str + ";"s, ItemList{});
-}
-
-static void
-test_parser_seq_glue_arg(void)
-{
- /* The sixel Sequence's parameter accessors are copied from the main parser's
- * Sequence class, so we don't need to test them here again.
- */
-}
-
-static void
-test_parser_st(void)
-{
- /* Test that ST is recognised in all forms and from all states, and
- * that different-mode C1 ST is not recognised.
- */
-
- auto context = SimpleContext{};
-
- assert_parse(context, Mode::UTF8, "?\x9c\e\\"sv, {Sixel{0}});
- assert_parse(context, Mode::UTF8, "!5\x9c\e\\"sv, {Sequence{Command::DECGRI, {5}}});
- assert_parse(context, Mode::UTF8, "5\x9c\e\\"sv, ItemList{});
- assert_parse(context, Mode::UTF8, "\x9c\xc2\e\\"sv, ItemList{});
-
- assert_parse(context, Mode::UTF8, "?\x9c\xc2\x9c"sv, {Sixel{0}});
- assert_parse(context, Mode::UTF8, "!5\x9c\xc2\x9c"sv, {Sequence{Command::DECGRI, {5}}});
- assert_parse(context, Mode::UTF8, "5\x9c\xc2\x9c"sv, ItemList{});
- assert_parse(context, Mode::UTF8, "\x9c\xc2\xc2\x9c"sv, ItemList{});
-
- assert_parse(context, Mode::EIGHTBIT, "?\e\\"sv, {Sixel{0}});
- assert_parse(context, Mode::EIGHTBIT, "!5\e\\"sv, {Sequence{Command::DECGRI, {5}}});
- assert_parse(context, Mode::EIGHTBIT, "5\e\\"sv, ItemList{});
- assert_parse(context, Mode::EIGHTBIT, "\xc2\e\\"sv, ItemList{});
-
- assert_parse(context, Mode::EIGHTBIT, "?\xc2\x9c"sv, {Sixel{0}});
- assert_parse(context, Mode::EIGHTBIT, "!5\xc2\x9c"sv, {Sequence{Command::DECGRI, {5}}});
- assert_parse(context, Mode::EIGHTBIT, "5\xc2\x9c"sv, ItemList{});
- assert_parse(context, Mode::EIGHTBIT, "\xc2\xc2\x9c"sv, ItemList{});
-
- assert_parse(context, Mode::SEVENBIT, "?\xc2\x9c\e\\"sv, {Sixel{0}});
- assert_parse(context, Mode::SEVENBIT, "!5\xc2\x9c\e\\"sv, {Sequence{Command::DECGRI, {5}}});
- assert_parse(context, Mode::SEVENBIT, "5\xc2\x9c\e\\"sv, ItemList{});
- assert_parse(context, Mode::SEVENBIT, "\xc2\x9c\xc2\e\\"sv, ItemList{});
-}
-
-static constexpr auto
-test_string()
-{
- return "a#22a#22\xc2z22a22\xc2"sv;
-}
-
-template<class C>
-static void
-test_parser_insert(C& context,
- Mode mode,
- std::string_view const& str,
- std::string_view const& insert_str,
- ParseStatus expected_status = ParseStatus::COMPLETE,
- int line = __builtin_LINE())
-{
- for (auto pos = 0u; pos <= str.size(); ++pos) {
- auto estr = std::string{str};
- estr.insert(pos, insert_str);
-
- assert_parse_st(context, mode, estr, -1,
- expected_status == ParseStatus::COMPLETE ? size_t(-1) : size_t(pos),
- expected_status, StType::C0, line);
-
- if (expected_status == ParseStatus::COMPLETE) {
- auto items = context.parsed_items(); // copy
-
- assert_parse_st(context, mode, str);
- assert(items == context.parsed_items());
- }
- }
-}
-
-template<class C>
-static void
-test_parser_insert(C& context,
- std::string_view const& str,
- std::string_view const& insert_str,
- ParseStatus expected_status = ParseStatus::COMPLETE,
- int line = __builtin_LINE())
-{
- for (auto mode : {Mode::UTF8, Mode::EIGHTBIT, Mode::SEVENBIT}) {
- test_parser_insert(context, mode, str, insert_str, expected_status, line);
- }
-}
-
-static void
-test_parser_controls_c0_esc(void)
-{
- /* Test that ESC (except C0 ST) always aborts the parsing at the position of the ESC */
-
- auto context = SimpleContext{};
- auto const str = test_string();
-
- for (auto c = 0x20; c < 0x7f; ++c) {
- if (c == 0x5c) /* '\' */
- continue;
-
- char esc[2] = {0x1b, char(c)};
- test_parser_insert(context, str, {esc, 2}, ParseStatus::ABORT);
- }
-}
-
-static void
-test_parser_controls_c0_can(void)
-{
- /* Test that CAN is handled correctly in all states */
-
- auto context = SimpleContext{};
-
- for (auto mode : {Mode::UTF8, Mode::EIGHTBIT, Mode::SEVENBIT}) {
-
- assert_parse_st(context, mode, "@\x18"sv, {Sixel{1}}, -1, 1, ParseStatus::ABORT);
- assert_parse_st(context, mode, "!5\x18"sv, {Sequence{Command::DECGRI, {5}}}, -1, 2, ParseStatus::ABORT);
- assert_parse_st(context, mode, "5\x18"sv, ItemList{}, -1, 1, ParseStatus::ABORT);
- assert_parse_st(context, mode, "\xc2\x18"sv, ItemList{}, -1, 1, ParseStatus::ABORT);
- }
-}
-
-static void
-test_parser_controls_c0_sub(void)
-{
- /* Test that SUB is handled correctly in all states */
-
- auto context = SimpleContext{};
-
- for (auto mode : {Mode::UTF8, Mode::EIGHTBIT, Mode::SEVENBIT}) {
-
- assert_parse_st(context, mode, "@\x1a"sv, {Sixel{1}, Sixel{0}});
-
- /* The parser chooses to not dispatch the current sequence on SUB; see the
- * comment in the Parser class. Otherwise there'd be a
- * Sequence{Command::DECGRI, {5}} as the first expected item here.
- */
- assert_parse_st(context, mode, "!5\x1a"sv, {Sixel{0}});
-
- assert_parse_st(context, mode, "5\x1a"sv, {Sixel{0}});
- assert_parse_st(context, mode, "\xc2\x1a"sv, {Sixel{0}});
- }
-}
-
-static void
-test_parser_controls_c0_ignored(void)
-{
- /* Test that all C0 controls except ESC, CAN, and SUB, are ignored,
- * that is, parsing a string results in the same parsed item when inserting
- * the C0 control at any position (except after \xc2 + 0x80..0x9f in UTF-8 mode,
- * where the \xc2 + C0 produces an U+FFFD (which is ignored) plus the raw C1 which
- * is itself ignored).
- */
-
- auto context = SimpleContext{};
- auto const str = test_string();
-
- for (auto c0 = 0; c0 < 0x20; ++c0) {
- if (c0 == 0x18 /* CAN */ ||
- c0 == 0x1a /* SUB */ ||
- c0 == 0x1b /* ESC */)
- continue;
-
- char c[1] = {char(c0)};
- test_parser_insert(context, str, {c, 1});
-
- assert_parse_st(context, Mode::UTF8, "?\xc2"s + std::string{c, 1} + "\x80@"s, {Sixel{0}, Sixel{1}});
- }
-}
-
-static void
-test_parser_controls_del(void)
-{
- /* Test that DEL is ignored (except between 0xc2 and 0x80..0x9f in UTF-8 mode) */
-
- auto context = SimpleContext{};
-
- for (auto mode : {Mode::UTF8, Mode::EIGHTBIT, Mode::SEVENBIT}) {
-
- assert_parse_st(context, mode, "!2\x7f;3"sv, {Sequence{Command::DECGRI, {2, 3}}});
- assert_parse_st(context, mode, "2\x7f;3"sv, ItemList{});
- }
-
- assert_parse_st(context, Mode::UTF8, "?\xc2\x7f\x9c", {Sixel{0}});
-}
-
-static void
-test_parser_controls_c1(void)
-{
- /* Test that any C1 control aborts the parsing at the insertion position,
- * except in 7-bit mode where C1 controls are ignored.
- */
-
- auto context = SimpleContext{};
- auto const str = test_string();
- for (auto c1 = 0x80; c1 < 0xa0; ++c1) {
- if (c1 == 0x9c /* ST */)
- continue;
-
- char c1_utf8[2] = {char(0xc2), char(c1)};
- test_parser_insert(context, Mode::UTF8, str, {c1_utf8, 2}, ParseStatus::ABORT);
- test_parser_insert(context, Mode::SEVENBIT, str, {c1_utf8, 2});
-
- char c1_raw[1] = {char(c1)};
- test_parser_insert(context, Mode::EIGHTBIT, str, {c1_raw, 2}, ParseStatus::ABORT);
- test_parser_insert(context, Mode::SEVENBIT, str, {c1_utf8, 2});
- }
-}
-
-// Context tests
-
-class TestContext: public Context {
-public:
- using base_type = Context;
- using base_type::base_type;
-
- auto parse(std::string_view const& str)
- {
- auto const beginptr = reinterpret_cast<uint8_t const*>(str.data());
- auto const endptr = reinterpret_cast<uint8_t const*>(beginptr + str.size());
- return Context::parse(beginptr, endptr, true);
- }
-
-}; // class TestContext
-
-template<class C>
-static void
-parse_image(C& context,
- std::string_view const& str,
- unsigned fg_red,
- unsigned fg_green,
- unsigned fg_blue,
- unsigned bg_red,
- unsigned bg_green,
- unsigned bg_blue,
- bool private_color_registers = true,
- int line = __builtin_LINE())
-{
- context.reset();
- context.prepare(0x50 /* C0 DCS */,
- fg_red, fg_green, fg_blue,
- bg_red, bg_green, bg_blue,
- false /* bg transparent */,
- private_color_registers);
-
- auto str_st = std::string{str};
- str_st.append(ST(StType::C0));
- auto [status, ip] = context.parse(str_st);
- g_assert_cmpint(int(status), ==, int(ParseStatus::COMPLETE));
-}
-
-template<class C>
-static void
-parse_image(C& context,
- ItemList const& items,
- unsigned fg_red,
- unsigned fg_green,
- unsigned fg_blue,
- unsigned bg_red,
- unsigned bg_green,
- unsigned bg_blue,
- bool private_color_registers = true,
- int line = __builtin_LINE())
-{
- parse_image(context, ItemStringifier(items).string(),
- fg_red, fg_green, fg_blue,
- bg_red, bg_green, bg_blue,
- private_color_registers,
- line);
-}
-
-template<class C>
-static void
-parse_image(C& context,
- std::string_view const& str,
- int line = __builtin_LINE())
-{
- parse_image(context, str, 0xffu, 0xffu, 0xffu, 0xff8, 0xffu, 0xffu, true, line);
-}
-
-template<class C>
-static void
-parse_image(C& context,
- ItemList const& items,
- int line = __builtin_LINE())
-{
- parse_image(context, ItemStringifier{items, Mode::UTF8}.string_view(), line);
-}
-
-template<class C>
-static auto
-parse_pixels(C& context,
- std::string_view const& str,
- unsigned extra_width_stride = 0,
- int line = __builtin_LINE())
-{
- parse_image(context, str, line);
- auto size = size_t{};
- auto ptr = vte::glib::take_free_ptr(context.image_data_indexed(&size, extra_width_stride));
- return std::pair{std::move(ptr), size};
-}
-
-/* BEGIN */
-
-/* The following code is copied from xterm/graphics.c where it is under the
- * licence below; and modified and used here under the GNU Lesser General Public
- * Licence, version 3 (or, at your option), any later version.
- */
-
-/*
- * Copyright 2013-2019,2020 by Ross Combs
- * Copyright 2013-2019,2020 by Thomas E. Dickey
- *
- * All Rights Reserved
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Except as contained in this notice, the name(s) of the above copyright
- * holders shall not be used in advertising or otherwise to promote the
- * sale, use or other dealings in this Software without prior written
- * authorization.
- */
-
-static void
-hls2rgb_double(int
- h,
- int l,
- int s,
- int* r,
- int* g,
- int* b) noexcept
-{
- const int hs = ((h + 240) / 60) % 6;
- const double lv = l / 100.0;
- const double sv = s / 100.0;
- double c, x, m, c2;
- double r1, g1, b1;
-
- if (s == 0) {
- *r = *g = *b = (short) (lv * 255. + 0.5);
- return;
- }
-
- c2 = (2.0 * lv) - 1.0;
- if (c2 < 0.0)
- c2 = -c2;
- c = (1.0 - c2) * sv;
- x = (hs & 1) ? c : 0.0;
- m = lv - 0.5 * c;
-
- switch (hs) {
- case 0:
- r1 = c;
- g1 = x;
- b1 = 0.0;
- break;
- case 1:
- r1 = x;
- g1 = c;
- b1 = 0.0;
- break;
- case 2:
- r1 = 0.0;
- g1 = c;
- b1 = x;
- break;
- case 3:
- r1 = 0.0;
- g1 = x;
- b1 = c;
- break;
- case 4:
- r1 = x;
- g1 = 0.0;
- b1 = c;
- break;
- case 5:
- r1 = c;
- g1 = 0.0;
- b1 = x;
- break;
- default:
- *r = (short) 255;
- *g = (short) 255;
- *b = (short) 255;
- return;
- }
-
- *r = (short) ((r1 + m) * 255.0 + 0.5);
- *g = (short) ((g1 + m) * 255.0 + 0.5);
- *b = (short) ((b1 + m) * 255.0 + 0.5);
-
- if (*r < 0)
- *r = 0;
- else if (*r > 255)
- *r = 255;
- if (*g < 0)
- *g = 0;
- else if (*g > 255)
- *g = 255;
- if (*b < 0)
- *b = 0;
- else if (*b > 255)
- *b = 255;
-}
-
-/* This is essentially Context::make_color_hls from sixel-context.cc,
- * only changed to return the colour components separately.
- */
-static void
-hls2rgb_int(int h,
- int l,
- int s,
- int* r,
- int* g,
- int* b) noexcept
-{
- auto const c2p = std::abs(2 * l - 100);
- auto const cp = ((100 - c2p) * s) << 1;
- auto const hs = ((h + 240) / 60) % 6;
- auto const xp = (hs & 1) ? cp : 0;
- auto const mp = 200 * l - (cp >> 1);
-
- int r1p, g1p, b1p;
- switch (hs) {
- case 0:
- r1p = cp;
- g1p = xp;
- b1p = 0;
- break;
- case 1:
- r1p = xp;
- g1p = cp;
- b1p = 0;
- break;
- case 2:
- r1p = 0;
- g1p = cp;
- b1p = xp;
- break;
- case 3:
- r1p = 0;
- g1p = xp;
- b1p = cp;
- break;
- case 4:
- r1p = xp;
- g1p = 0;
- b1p = cp;
- break;
- case 5:
- r1p = cp;
- g1p = 0;
- b1p = xp;
- break;
- default:
- __builtin_unreachable();
- }
-
- *r = ((r1p + mp) * 255 + 10000) / 20000;
- *g = ((g1p + mp) * 255 + 10000) / 20000;
- *b = ((b1p + mp) * 255 + 10000) / 20000;
-}
-
-/* END */
-
-static void
-test_context_color_hls(void)
-{
- /* Test that our HLS colour conversion gives the right results
- * by comparing it against the xterm/libsixel implementation.
- *
- * The values may differ by 1, which happen only for (L, S) in
- * {(5, 100), (40, 75), (50, 80), (60, 75), (75, 60), (95, 100)}.
- * There, one or more of the R, G, B components' unscaled values,
- * times 255, produces an exact fraction of .5 in hsl2rgb_double,
- * which, plus 0.5,, and due to inexactness, result in the truncated
- * value "(short)v" being one less than the result of the integer
- * computation.
- */
-
- for (auto h = 0; h <= 360; ++h) {
- for (auto l = 0; l <= 100; ++l) {
- for (auto s = 0; s <= 100; ++s) {
- int rd, gd, bd, ri, gi, bi;
-
- hls2rgb_double(h, l, s, &rd, &gd, &bd);
- hls2rgb_int(h, l, s, &ri, &gi, &bi);
-
- g_assert_true((rd == ri || (rd + 1) == ri) &&
- (gd == gi || (gd + 1) == gi) &&
- (bd == bi || (bd + 1) == bi));
- }
- }
- }
-}
-
-template<class C>
-static void
-assert_image_dimensions(C& context,
- unsigned width,
- unsigned height,
- int line = __builtin_LINE())
-{
- g_assert_cmpuint(context.image_width(), ==, width);
- g_assert_cmpuint(context.image_height(), ==, height);
-}
-
-static void
-test_context_raster_attributes(void)
-{
- /* Test that DECGRA sets the image dimensions */
-
- auto context = TestContext{};
- parse_image(context, "\"0;0;64;128"sv);
- assert_image_dimensions(context, 64, 128);
-}
-
-static void
-test_context_repeat(void)
-{
- /* Test that DECGRI repetition works */
-
- auto context = TestContext{};
- auto [pixels, size] = parse_pixels(context, "#1!5@"sv);
- assert_image_dimensions(context, 5, 1);
-
- auto data = pixels.get();
- auto const v = *data++;
- for (auto x = 1u; x < context.image_width(); ++x)
- g_assert_cmpuint(*data++, ==, v);
-
- g_assert_cmpuint(size_t(data - pixels.get()), <=, size);
-
- /* Check that repeat param 0 is trated as 1 */
- parse_image(context, {DECGRI(0), Sixel(1u << 0)});;
- assert_image_dimensions(context, 1, 1);
-
- /* Check that omitted param is treated as default */
- parse_image(context, {DECGRI(-1), Sixel(1u << 0)});
- assert_image_dimensions(context, 1, 1);
-}
-
-static void
-test_context_scanlines_grow(void)
-{
- /* Test that scanlines grow on demand */
-
- auto context = TestContext{};
- parse_image(context, "@$AA$?$??~-~"sv);
- assert_image_dimensions(context, 3, 12);
-}
-
-static void
-test_context_scanlines_underfull(void)
-{
- /* Test that the image height is determined by the last set sixel, not
- * necessarily the number of scanlines.
- */
-
- auto context = TestContext{};
-
- parse_image(context, "?"sv);
- assert_image_dimensions(context, 1, 0);
-
- for (auto n = 0; n < 6; ++n) {
- parse_image(context, {Sixel(1u << n)});
- assert_image_dimensions(context, 1, n + 1);
-
- parse_image(context, {Sixel(0), Sixel(0), DECGNL(), Sixel(1u << n)});
- assert_image_dimensions(context, 2, 6 + n + 1);
- }
-}
-
-static void
-test_context_scanlines_max_width(void)
-{
- /* Test that scanlines up to max_width() work, and scanlines longer than that
- * are accepted but do not write outside the maximum width.
- */
-
- auto context = TestContext{};
-
- parse_image(context, {Sixel(1u << 0), DECGNL(), DECGRI(context.max_width() - 1), Sixel(0x3f)});
- assert_image_dimensions(context, context.max_width() - 1, 12);
-
- parse_image(context, {Sixel(1u << 0), DECGNL(), DECGRI(context.max_width()), Sixel(0x3f)});
- assert_image_dimensions(context, context.max_width(), 12);
-
- parse_image(context, {Sixel(1u << 0), DECGNL(), DECGRI(context.max_width() + 1), Sixel(0x3f)});
- assert_image_dimensions(context, context.max_width(), 12);
-}
-
-static void
-test_context_scanlines_max_height(void)
-{
- /* Test that scanlines up to max_height() work, and scanlines beyond that
- * are accepted but do nothing.
- */
-
- auto context = TestContext{};
-
- auto items = ItemList{};
- for (auto n = 0u; n < (context.max_height() / 6 - 1); ++n) {
- if (n > 0)
- items.emplace_back(DECGNL());
- items.emplace_back(Sixel(1u << 5));
- }
-
- parse_image(context, items);
- assert_image_dimensions(context, 1, context.max_height() - 6);
-
- items.emplace_back(DECGNL());
- items.emplace_back(Sixel(1u << 4));
-
- parse_image(context, items);
- assert_image_dimensions(context, 1, context.max_height() - 1);
-
- items.emplace_back(DECGCR());
- items.emplace_back(Sixel(1u << 5));
-
- parse_image(context, items);
- assert_image_dimensions(context, 1, context.max_height());
-
- /* Image cannot grow further */
-
- items.emplace_back(DECGNL());
- items.emplace_back(Sixel(1u << 0));
-
- parse_image(context, items);
- assert_image_dimensions(context, 1, context.max_height());
-
- items.emplace_back(DECGNL());
- items.emplace_back(Sixel(1u << 5));
-
- parse_image(context, items);
- assert_image_dimensions(context, 1, context.max_height());
-}
-
-static void
-test_context_image_stride(void)
-{
- /* Test that data in the stride padding is set to background */
-
- auto context = TestContext{};
-
- auto const extra_stride = 3u;
- auto [pixels, size] = parse_pixels(context, "#1~~-~~"sv, extra_stride);
- assert_image_dimensions(context, 2, 12);
-
- auto data = pixels.get();
- auto const reg = param_to_color_register(1);
-
- for (auto y = 0u; y < context.image_height(); ++y) {
- for (auto x = 0u; x < context.image_width(); ++x)
- g_assert_cmpuint(*data++, ==, unsigned(reg));
- for (auto e = 0u; e < extra_stride; ++e)
- g_assert_cmpuint(*data++, ==, 0);
- }
-
- g_assert_cmpuint(size_t(data - pixels.get()), <=, size);
-}
-
-class RGB {
-public:
- uint8_t r{0};
- uint8_t g{0};
- uint8_t b{0};
-
- RGB() = default;
- ~RGB() = default;
-
- RGB(int rv, int gv, int bv)
- : r(rv), g(gv), b(bv)
- {
- }
-};
-
-static void
-test_context_image_palette(void)
-{
- /* Test that the colour palette is recognised, and that colour registers
- * wrap around.
- */
-
- auto make_color_rgb = [](unsigned rp,
- unsigned gp,
- unsigned bp) constexpr noexcept -> auto
- {
- auto scale = [](unsigned value) constexpr noexcept -> auto
- {
- return (value * 255u + 50u) / 100u;
- };
-
- auto make_color = [](unsigned r,
- unsigned g,
- unsigned b) constexpr noexcept -> Context::color_t
- {
- if constexpr (std::endian::native == std::endian::little) {
- return b | g << 8 | r << 16 | 0xffu << 24 /* opaque */;
- } else if constexpr (std::endian::native == std::endian::big) {
- return 0xffu /* opaque */ | r << 8 | g << 16 | b << 24;
- } else {
- __builtin_unreachable();
- }
- };
-
- return make_color(scale(rp), scale(gp), scale(bp));
- };
-
- auto context = TestContext{};
-
- std::array<RGB, context.num_colors()> palette;
- for (auto& p : palette) {
- p = RGB(g_test_rand_int_range(0, 100),
- g_test_rand_int_range(0, 100),
- g_test_rand_int_range(0, 100));
- }
-
- auto items = ItemList{};
- auto reg = context.num_colors();
- for (auto const& p : palette) {
- items.emplace_back(DECGCI_RGB(reg++, p.r, p.g, p.b));
- }
-
- parse_image(context, items);
-
- for (auto n = 0; n < context.num_colors(); ++n) {
- g_assert_cmpuint(make_color_rgb(palette[n].r, palette[n].g, palette[n].b),
- ==,
- context.color(param_to_color_register(n)));
- }
-}
-
-static void
-test_context_image_compositing(void)
-{
- /* Test that multiple sixels in different colours are composited. */
-
- auto context = TestContext{};
-
- auto [pixels, size] = parse_pixels(context,
- "#256!24F$#257!24w-#258!24F$#259!24w-#260!24F$#261!24w"sv);
-
- auto data = pixels.get();
- for (auto y = 0u; y < context.image_height(); ++y) {
- auto const reg = param_to_color_register((256 + y / 3));
- for (auto x = 0u; x < context.image_width(); ++x)
- g_assert_cmpuint(*data++, ==, reg);
- }
-
-
- g_assert_cmpuint(size_t(data - pixels.get()), <=, size);
-}
-
-// Main
-
-int
-main(int argc,
- char* argv[])
-{
- g_test_init(&argc, &argv, nullptr);
-
- g_test_add_func("/vte/sixel/parser/sequences/parameters", test_parser_seq_params);
- g_test_add_func("/vte/sixel/parser/sequences/subparameters", test_parser_seq_subparams);
- g_test_add_func("/vte/sixel/parser/sequences/parameters-clear", test_parser_seq_params_clear);
- g_test_add_func("/vte/sixel/parser/sequences/parameters-max", test_parser_seq_params_max);
- g_test_add_func("/vte/sixel/parser/sequences/glue/arg", test_parser_seq_glue_arg);
- g_test_add_func("/vte/sixel/parser/st", test_parser_st);
- g_test_add_func("/vte/sixel/parser/controls/c0/escape", test_parser_controls_c0_esc);
- g_test_add_func("/vte/sixel/parser/controls/c0/can", test_parser_controls_c0_can);
- g_test_add_func("/vte/sixel/parser/controls/c0/sub", test_parser_controls_c0_sub);
- g_test_add_func("/vte/sixel/parser/controls/c0/ignored", test_parser_controls_c0_ignored);
- g_test_add_func("/vte/sixel/parser/controls/del", test_parser_controls_del);
- g_test_add_func("/vte/sixel/parser/controls/c1", test_parser_controls_c1);
- g_test_add_func("/vte/sixel/context/color/hls", test_context_color_hls);
- g_test_add_func("/vte/sixel/context/raster-attributes", test_context_raster_attributes);
- g_test_add_func("/vte/sixel/context/repeat", test_context_repeat);
- g_test_add_func("/vte/sixel/context/scanlines/grow", test_context_scanlines_grow);
- g_test_add_func("/vte/sixel/context/scanlines/underfull", test_context_scanlines_underfull);
- g_test_add_func("/vte/sixel/context/scanlines/max-width", test_context_scanlines_max_width);
- g_test_add_func("/vte/sixel/context/scanlines/max-height", test_context_scanlines_max_height);
- g_test_add_func("/vte/sixel/context/image/stride", test_context_image_stride);
- g_test_add_func("/vte/sixel/context/image/palette", test_context_image_palette);
- g_test_add_func("/vte/sixel/context/image/compositing", test_context_image_compositing);
-
- return g_test_run();
-}
diff --git a/src/vte.cc b/src/vte.cc
index c0053900..8b75883f 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -3075,43 +3075,6 @@ not_inserted:
m_line_wrapped = line_wrapped;
}
-#ifdef WITH_SIXEL
-
-void
-Terminal::insert_image(ProcessingContext& context,
- vte::Freeable<cairo_surface_t> image_surface) /* throws */
-{
- if (!image_surface)
- return;
-
- auto const image_width_px = cairo_image_surface_get_width(image_surface.get());
- auto const image_height_px = cairo_image_surface_get_height(image_surface.get());
-
- /* Calculate geometry */
-
- auto const left = m_screen->cursor.col;
- auto const top = m_screen->cursor.row;
- auto const width = (image_width_px + m_cell_width_unscaled - 1) / m_cell_width_unscaled;
- auto const height = (image_height_px + m_cell_height_unscaled - 1) / m_cell_height_unscaled;
-
- m_screen->row_data->append_image(std::move(image_surface),
- image_width_px,
- image_height_px,
- left,
- top,
- m_cell_width_unscaled,
- m_cell_height_unscaled);
-
- /* Erase characters under the image. Since this inserts content, we need
- * to update the processing context's bbox.
- */
- context.pre_GRAPHIC(*this);
- erase_image_rect(height, width);
- context.post_GRAPHIC(*this);
-}
-
-#endif /* WITH_SIXEL */
-
guint8
Terminal::get_bidi_flags() const noexcept
{
@@ -3475,12 +3438,6 @@ Terminal::process_incoming()
break;
#endif
-#ifdef WITH_SIXEL
- case DataSyntax::DECSIXEL:
- process_incoming_decsixel(context, *chunk);
- break;
-#endif
-
default:
g_assert_not_reached();
break;
@@ -3684,7 +3641,10 @@ Terminal::process_incoming_utf8(ProcessingContext& context,
}
}
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-label"
switched_data_syntax:
+#pragma GCC diagnostic pop
// Update start for data consumed
chunk.set_begin_reading(ip);
@@ -3809,7 +3769,10 @@ Terminal::process_incoming_pcterm(ProcessingContext& context,
return;
}
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-label"
switched_data_syntax:
+#pragma GCC diagnostic pop
// Update start for data consumed
chunk.set_begin_reading(ip);
@@ -3823,44 +3786,6 @@ Terminal::process_incoming_pcterm(ProcessingContext& context,
#endif /* WITH_ICU */
-#ifdef WITH_SIXEL
-
-void
-Terminal::process_incoming_decsixel(ProcessingContext& context,
- vte::base::Chunk& chunk)
-{
- auto const [status, ip] = m_sixel_context->parse(chunk.begin_reading(),
- chunk.end_reading(),
- chunk.eos());
-
- // Update start for data consumed
- chunk.set_begin_reading(ip);
-
- switch (status) {
- case vte::sixel::Parser::ParseStatus::CONTINUE:
- break;
-
- case vte::sixel::Parser::ParseStatus::COMPLETE:
- /* Like the main parser, the sequence only takes effect
- * if introducer and terminator match (both C0 or both C1).
- */
- if (m_sixel_context->is_matching_controls()) {
- try {
- insert_image(context, m_sixel_context->image_cairo());
- } catch (...) {
- }
- }
-
- [[fallthrough]];
- case vte::sixel::Parser::ParseStatus::ABORT:
- m_sixel_context->reset();
- pop_data_syntax();
- break;
- }
-}
-
-#endif /* WITH_SIXEL */
-
bool
Terminal::pty_io_read(int const fd,
GIOCondition const condition)
@@ -7653,12 +7578,6 @@ Terminal::Terminal(vte::platform::Widget* w,
for (auto i = 0; i < VTE_PALETTE_SIZE; i++)
m_palette[i].sources[VTE_COLOR_SOURCE_ESCAPE].is_set = FALSE;
- /* Dispatch unripe DCS (for now, just DECSIXEL) sequences,
- * so we can switch data syntax and parse the contents with
- * the SIXEL subparser.
- */
- m_parser.set_dispatch_unripe(true);
-
/* Set up I/O encodings. */
m_outgoing = _vte_byte_array_new();
@@ -8175,11 +8094,7 @@ Terminal::draw_cells(vte::view::DrawingContext::TextRequest* items,
else
rgb_from_index<4, 5, 4>(deco, dc);
-#ifndef WITH_SIXEL
if (clear && (draw_default_bg || back != VTE_DEFAULT_BG)) {
-#else
- {
-#endif
/* Paint the background. */
i = 0;
while (i < n) {
@@ -8198,25 +8113,11 @@ Terminal::draw_cells(vte::view::DrawingContext::TextRequest* items,
}
}
-#ifdef WITH_SIXEL
- if (back == VTE_DEFAULT_BG) {
- /* Clear cells in order to properly overdraw images */
- m_draw.clear(xl,
- y,
- xr - xl, row_height,
- get_color(VTE_DEFAULT_BG), m_background_alpha);
- }
-
- if (clear && (draw_default_bg || back != VTE_DEFAULT_BG)) {
-#else
- {
-#endif
- m_draw.fill_rectangle(
- xl,
- y,
- xr - xl, row_height,
- &bg, VTE_DRAW_OPAQUE);
- }
+ m_draw.fill_rectangle(
+ xl,
+ y,
+ xr - xl, row_height,
+ &bg, VTE_DRAW_OPAQUE);
}
}
@@ -8826,14 +8727,12 @@ Terminal::draw_rows(VteScreen *screen_,
nhilite = (nhyperlink && cell->attr.hyperlink_idx == m_hyperlink_hover_idx) ||
(!nhyperlink && regex_match_has_current() && m_match_span.contains(row, lcol));
if (cell->c == 0 ||
-#ifndef WITH_SIXEL
((cell->c == ' ' || cell->c == '\t') && // FIXME '\t' is newly added now, double check
cell->attr.has_none(VTE_ATTR_UNDERLINE_MASK |
VTE_ATTR_STRIKETHROUGH_MASK |
VTE_ATTR_OVERLINE_MASK) &&
!nhyperlink &&
!nhilite) ||
-#endif
cell->attr.fragment() ||
cell->attr.invisible()) {
/* Skip empty or fragment cell, but erase on ' ' and '\t', since
@@ -9224,9 +9123,6 @@ Terminal::draw(cairo_t* cr,
int allocated_width, allocated_height;
int extra_area_for_cursor;
bool text_blink_enabled_now;
-#ifdef WITH_SIXEL
- VteRing *ring = m_screen->row_data;
-#endif
gint64 now = 0;
allocated_width = get_allocated_width();
@@ -9249,33 +9145,6 @@ Terminal::draw(cairo_t* cr,
cairo_translate(cr, m_padding.left, m_padding.top);
-#ifdef WITH_SIXEL
- /* Draw images */
- if (m_images_enabled) {
- vte::grid::row_t top_row = first_displayed_row();
- vte::grid::row_t bottom_row = last_displayed_row();
- auto const& image_map = ring->image_map();
- auto const image_map_end = image_map.end();
- for (auto it = image_map.begin(); it != image_map_end; ++it) {
- auto const& image = it->second;
-
- if (image->get_bottom() < top_row ||
- image->get_top() > bottom_row)
- continue;
-
- auto const x = image->get_left () * m_cell_width;
- auto const y = (image->get_top () - m_screen->scroll_delta) * m_cell_height;
-
- /* Clear cell extent; image may be slightly smaller */
- m_draw.clear(x, y, image->get_width() * m_cell_width,
- image->get_height() * m_cell_height,
- get_color(VTE_DEFAULT_BG), m_background_alpha);
-
- image->paint(cr, x, y, m_cell_width, m_cell_height);
- }
- }
-#endif /* WITH_SIXEL */
-
/* Whether blinking text should be visible now */
m_text_blink_state = true;
text_blink_enabled_now = (unsigned)m_text_blink_mode & (unsigned)(m_has_focus ? TextBlinkMode::eFOCUSED : TextBlinkMode::eUNFOCUSED);
@@ -9832,12 +9701,6 @@ Terminal::reset_data_syntax()
return;
switch (current_data_syntax()) {
-#ifdef WITH_SIXEL
- case DataSyntax::DECSIXEL:
- m_sixel_context->reset();
- break;
-#endif
-
default:
break;
}
@@ -9845,15 +9708,6 @@ Terminal::reset_data_syntax()
pop_data_syntax();
}
-void
-Terminal::reset_graphics_color_registers()
-{
-#ifdef WITH_SIXEL
- if (m_sixel_context)
- m_sixel_context->reset_colors();
-#endif
-}
-
/*
* Terminal::reset:
* @clear_tabstops: whether to reset tabstops
@@ -9958,11 +9812,6 @@ Terminal::reset(bool clear_tabstops,
/* Clear modifiers. */
m_modifiers = 0;
-#ifdef WITH_SIXEL
- if (m_sixel_context)
- m_sixel_context->reset_colors();
-#endif
-
/* Reset the saved cursor. */
save_cursor(&m_normal_screen);
save_cursor(&m_alternate_screen);
@@ -9973,12 +9822,6 @@ Terminal::reset(bool clear_tabstops,
/* Reset XTerm window controls */
m_xterm_wm_iconified = false;
-
- /* When not using private colour registers, we should
- * clear (assign to black) all SIXEL colour registers.
- * (DEC PPLV2 § 5.8)
- */
- reset_graphics_color_registers();
}
void
diff --git a/src/vtedefines.hh b/src/vtedefines.hh
index 7f2e478a..23827c96 100644
--- a/src/vtedefines.hh
+++ b/src/vtedefines.hh
@@ -143,12 +143,6 @@
#define VTE_TERMINFO_NAME "xterm-256color"
-#define VTE_SIXEL_ENABLED_DEFAULT false
-
-#define VTE_SIXEL_MAX_WIDTH (2048)
-#define VTE_SIXEL_MAX_HEIGHT (2052)
-#define VTE_SIXEL_NUM_COLOR_REGISTERS (1024)
-
#define VTE_MIN_CURSOR_BLINK_CYCLE (50 /* ms */)
#define VTE_MIN_CURSOR_BLINK_TIMEOUT (50 /* ms */)
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index 2b86b346..61915e71 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -2118,11 +2118,7 @@ vte_terminal_class_init(VteTerminalClass *klass)
*/
pspecs[PROP_ENABLE_SIXEL] =
g_param_spec_boolean ("enable-sixel", nullptr, nullptr,
-#ifdef WITH_SIXEL
- VTE_SIXEL_ENABLED_DEFAULT,
-#else
false,
-#endif
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY));
@@ -2498,12 +2494,6 @@ vte_get_features (void) noexcept
#else
"-ICU"
#endif
- " "
-#ifdef WITH_SIXEL
- "+SIXEL"
-#else
- "-SIXEL"
-#endif
#ifdef __linux__
" "
#ifdef WITH_SYSTEMD
@@ -2534,9 +2524,6 @@ vte_get_feature_flags(void) noexcept
#ifdef WITH_ICU
VTE_FEATURE_FLAG_ICU |
#endif
-#ifdef WITH_SIXEL
- VTE_FEATURE_FLAG_SIXEL |
-#endif
#ifdef __linux__
#ifdef WITH_SYSTEMD
VTE_FEATURE_FLAG_SYSTEMD |
@@ -6249,12 +6236,7 @@ vte_terminal_set_enable_sixel(VteTerminal *terminal,
gboolean enabled) noexcept
try
{
-#ifdef WITH_SIXEL
g_return_if_fail(VTE_IS_TERMINAL(terminal));
-
- if (WIDGET(terminal)->set_sixel_enabled(enabled != FALSE))
- g_object_notify_by_pspec(G_OBJECT(terminal), pspecs[PROP_ENABLE_SIXEL]);
-#endif
}
catch (...)
{
@@ -6265,7 +6247,7 @@ catch (...)
* vte_terminal_get_enable_sixel:
* @terminal: a #VteTerminal
*
- * Returns: %TRUE if SIXEL image support is enabled, %FALSE otherwise
+ * Returns: %FALSE
*
* Since: 0.62
*/
@@ -6273,13 +6255,7 @@ gboolean
vte_terminal_get_enable_sixel(VteTerminal *terminal) noexcept
try
{
-#ifdef WITH_SIXEL
- g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE);
-
- return WIDGET(terminal)->sixel_enabled();
-#else
return false;
-#endif
}
catch (...)
{
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 54409499..eb95ad68 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -75,10 +75,6 @@
#include "icu-converter.hh"
#endif
-#ifdef WITH_SIXEL
-#include "sixel-context.hh"
-#endif
-
enum {
VTE_BIDI_FLAG_IMPLICIT = 1 << 0,
VTE_BIDI_FLAG_RTL = 1 << 1,
@@ -320,9 +316,6 @@ public:
/* ECMA48_ECMA35, not supported */
/* The following can never be primary data syntax: */
-#ifdef WITH_SIXEL
- DECSIXEL,
-#endif
};
DataSyntax m_primary_data_syntax{DataSyntax::ECMA48_UTF8};
@@ -381,10 +374,6 @@ public:
}
}
-#ifdef WITH_SIXEL
- std::unique_ptr<vte::sixel::Context> m_sixel_context{};
-#endif
-
/* Screen data. We support the normal screen, and an alternate
* screen, which seems to be a DEC-specific feature. */
VteScreen m_normal_screen;
@@ -509,21 +498,6 @@ public:
this),
"mouse-autoscroll-timer"};
- /* Inline images */
- bool m_sixel_enabled{VTE_SIXEL_ENABLED_DEFAULT};
- bool m_images_enabled{VTE_SIXEL_ENABLED_DEFAULT};
-
- bool set_sixel_enabled(bool enabled) noexcept
- {
- auto const changed = m_sixel_enabled != enabled;
- m_sixel_enabled = m_images_enabled = enabled;
- if (changed)
- invalidate_all();
- return changed;
- }
-
- constexpr bool sixel_enabled() const noexcept { return m_sixel_enabled; }
-
/* State variables for handling match checks. */
int m_match_regex_next_tag{0};
auto regex_match_next_tag() noexcept { return m_match_regex_next_tag++; }
@@ -795,11 +769,6 @@ public:
bool insert,
bool invalidate_now);
- #ifdef WITH_SIXEL
- void insert_image(ProcessingContext& context,
- vte::Freeable<cairo_surface_t> image_surface) /* throws */;
- #endif
-
void invalidate_row(vte::grid::row_t row);
void invalidate_rows(vte::grid::row_t row_start,
vte::grid::row_t row_end /* inclusive */);
@@ -825,10 +794,6 @@ public:
void process_incoming_pcterm(ProcessingContext& context,
vte::base::Chunk& chunk);
#endif
- #ifdef WITH_SIXEL
- void process_incoming_decsixel(ProcessingContext& context,
- vte::base::Chunk& chunk);
- #endif
bool process(bool emit_adj_changed);
inline bool is_processing() const { return m_active_terminals_link != nullptr; }
void start_processing();
@@ -1024,7 +989,6 @@ public:
void im_reset();
void im_update_cursor();
- void reset_graphics_color_registers();
void reset(bool clear_tabstops,
bool clear_history,
bool from_api = false);
@@ -1455,8 +1419,6 @@ public:
inline void move_cursor_down(vte::grid::row_t rows);
inline void erase_characters(long count,
bool use_basic = false);
- void erase_image_rect(vte::grid::row_t rows,
- vte::grid::column_t columns);
inline void insert_blank_character();
template<unsigned int redbits, unsigned int greenbits, unsigned int bluebits>
diff --git a/src/vteseq.cc b/src/vteseq.cc
index 9efde087..007ddb69 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -987,33 +987,6 @@ Terminal::erase_characters(long count,
m_text_deleted_flag = TRUE;
}
-void
-Terminal::erase_image_rect(vte::grid::row_t rows,
- vte::grid::column_t columns)
-{
- auto const top = m_screen->cursor.row;
-
- /* FIXMEchpe: simplify! */
- for (auto i = 0; i < rows; ++i) {
- auto const row = top + i;
-
- erase_characters(columns, true);
-
- if (row > m_screen->insert_delta - 1 &&
- row < m_screen->insert_delta + m_row_count)
- set_hard_wrapped(row);
-
- if (i == rows - 1) {
- if (m_modes_private.MINTTY_SIXEL_SCROLL_CURSOR_RIGHT())
- move_cursor_forward(columns);
- else
- cursor_down(true);
- } else {
- cursor_down(true);
- }
- }
-}
-
/* Insert a blank character. */
void
Terminal::insert_blank_character()
@@ -2408,9 +2381,6 @@ Terminal::DA1(vte::parser::Sequence const& seq)
return;
reply(seq, VTE_REPLY_DECDA1R, {65, 1,
-#ifdef WITH_SIXEL
- m_sixel_enabled ? 4 : -2 /* skip */,
-#endif
9});
}
@@ -4139,8 +4109,6 @@ Terminal::DECSCL(vte::parser::Sequence const& seq)
break;
}
#endif
-
- reset_graphics_color_registers();
}
void
@@ -4385,7 +4353,7 @@ Terminal::DECSGR(vte::parser::Sequence const& seq)
/* TODO: consider implementing sub/superscript? */
}
-bool
+void
Terminal::DECSIXEL(vte::parser::Sequence const& seq)
{
/*
@@ -4413,116 +4381,6 @@ Terminal::DECSIXEL(vte::parser::Sequence const& seq)
* References: VT330
* DEC PPLV2 § 5.4
*/
-
-#ifdef WITH_SIXEL
- auto process_sixel = false;
- auto mode = vte::sixel::Parser::Mode{};
- if (m_sixel_enabled) {
- switch (primary_data_syntax()) {
- case DataSyntax::ECMA48_UTF8:
- process_sixel = true;
- mode = vte::sixel::Parser::Mode::UTF8;
- break;
-
-#ifdef WITH_ICU
- case DataSyntax::ECMA48_PCTERM:
- /* It's not really clear how DECSIXEL should be processed in PCTERM mode.
- * The DEC documentation available isn't very detailed on PCTERM mode,
- * and doesn't appear to mention its interaction with DECSIXEL at all.
- *
- * Since (afaik) a "real" DEC PCTERM mode only (?) translates the graphic
- * characters, not the whole data stream, as we do, let's assume that
- * DECSIXEL content should be processed as raw bytes, i.e. without any
- * translation.
- * Also, since C1 controls don't exist in PCTERM mode, let's process
- * DECSIXEL in 7-bit mode.
- *
- * As an added complication, we can only switch data syntaxes if
- * the data stream is exact, that is the charset converter has
- * not consumed more data than we have currently read output bytes
- * from it. So we need to check that the converter has no pending
- * characters.
- *
- * Alternatively, we could just refuse to process DECSIXEL in
- * PCTERM mode.
- */
- process_sixel = !m_converter->decoder().pending();
- mode = vte::sixel::Parser::Mode::SEVENBIT;
- break;
-#endif /* WITH_ICU */
-
- default:
- __builtin_unreachable();
- process_sixel = false;
- }
- }
-
- /* How to interpret args[1] is not entirely clear from the DEC
- * documentation and other terminal emulators.
- * We choose to make args[1]==1 mean to use transparent background.
- * and treat all other values (default, 0, 2) as using the current
- * SGR background colour. See the discussion in issue #253.
- *
- * Also use the current SGR foreground colour to initialise
- * the special colour register so that SIXEL images which set
- * no colours get a sensible default.
- */
- auto transparent_bg = bool{};
- switch (seq.collect1(1, 2)) {
- case -1: /* default */
- case 0:
- case 2:
- transparent_bg = false;
- break;
-
- case 1:
- transparent_bg = true;
- break;
-
- case 5: /* OR mode (a nonstandard NetBSD/x68k extension; not supported */
- process_sixel = false;
- break;
-
- default:
- transparent_bg = false;
- break;
- }
-
- /* Ignore the whole sequence */
- if (!process_sixel || seq.is_ripe() /* that shouldn't happen */) {
- m_parser.ignore_until_st();
- return false;
- }
-
- auto fore = unsigned{}, back = unsigned{};
- auto fg = vte::color::rgb{}, bg = vte::color::rgb{};
- resolve_normal_colors(&m_defaults, &fore, &back, fg, bg);
-
- try {
- if (!m_sixel_context)
- m_sixel_context = std::make_unique<vte::sixel::Context>();
-
- m_sixel_context->prepare(seq.introducer(),
- fg.red >> 8, fg.green >> 8, fg.blue >> 8,
- bg.red >> 8, bg.green >> 8, bg.blue >> 8,
- back == VTE_DEFAULT_BG || transparent_bg,
- m_modes_private.XTERM_SIXEL_PRIVATE_COLOR_REGISTERS());
-
- m_sixel_context->set_mode(mode);
-
- /* We need to reset the main parser, so that when it is in the ground state
- * when processing returns to the primary data syntax from DECSIXEL
- */
- m_parser.reset();
- push_data_syntax(DataSyntax::DECSIXEL);
-
- return true; /* switching data syntax */
- } catch (...) {
- }
-#endif /* WITH_SIXEL */
-
- m_parser.ignore_until_st();
- return false;
}
void
@@ -8937,84 +8795,7 @@ Terminal::XTERM_SMGRAPHICS(vte::parser::Sequence const& seq)
*/
auto const attr = seq.collect1(0);
- auto status = 3, rv0 = -2, rv1 = -2;
-
- switch (attr) {
-#ifdef WITH_SIXEL
- case 0: /* Colour registers.
- *
- * VTE doesn't support changing the number of colour registers, so always
- * return the fixed number, and set() returns success iff the passed number
- * was less or equal that number.
- */
- switch (seq.collect1(1)) {
- case 1: /* read */
- case 2: /* reset */
- case 4: /* read maximum */
- status = 0;
- rv0 = VTE_SIXEL_NUM_COLOR_REGISTERS;
- break;
- case 3: /* set */
- status = (seq.collect1(2) <= VTE_SIXEL_NUM_COLOR_REGISTERS) ? 0 : 2;
- rv0 = VTE_SIXEL_NUM_COLOR_REGISTERS;
- break;
- case -1: /* no default */
- default:
- status = 2;
- break;
- }
- break;
-
- case 1: /* SIXEL graphics geometry.
- *
- * VTE doesn't support variable geometries; always report
- * the maximum size of a SIXEL graphic, and set() returns success iff the
- * passed numbers are less or equal to that number.
- */
- switch (seq.collect1(1)) {
- case 1: /* read */
- case 2: /* reset */
- case 4: /* read maximum */
- status = 0;
- rv0 = VTE_SIXEL_MAX_WIDTH;
- rv1 = VTE_SIXEL_MAX_HEIGHT;
- break;
-
- case 3: /* set */ {
- auto w = int{}, h = int{};
- if (seq.collect(2, {&w, &h}) &&
- w > 0 && w <= VTE_SIXEL_MAX_WIDTH &&
- h > 0 && h <= VTE_SIXEL_MAX_HEIGHT) {
- rv0 = VTE_SIXEL_MAX_WIDTH;
- rv1 = VTE_SIXEL_MAX_HEIGHT;
- status = 0;
- } else {
- status = 3;
- }
-
- break;
- }
-
- case -1: /* no default */
- default:
- status = 2;
- break;
- }
- break;
-
-#endif /* WITH_SIXEL */
-
-#if 0 /* ifdef WITH_REGIS */
- case 2:
- status = 1;
- break;
-#endif
-
- case -1: /* no default value */
- default:
- status = 1;
- break;
- }
+ auto status = 1, rv0 = -2, rv1 = -2;
reply(seq, VTE_REPLY_XTERM_SMGRAPHICS_REPORT, {attr, status, rv0, rv1});
}
diff --git a/src/widget.hh b/src/widget.hh
index 2acb0e07..2dac3cb9 100644
--- a/src/widget.hh
+++ b/src/widget.hh
@@ -473,9 +473,6 @@ public:
bool should_emit_signal(int id) noexcept;
- bool set_sixel_enabled(bool enabled) noexcept { return m_terminal->set_sixel_enabled(enabled); }
- bool sixel_enabled() const noexcept { return m_terminal->sixel_enabled(); }
-
constexpr auto xalign() const noexcept { return m_xalign; }
constexpr auto yalign() const noexcept { return m_yalign; }
constexpr auto xfill() const noexcept { return m_xfill; }