[vte/wip/sixels] sixel: Assign sixel background and default foreground from m_defaults



commit 8131733d025d1848593f1a8b2577c69279d3df75
Author: Hans Petter Jansson <hpj hpjansson org>
Date:   Sat Nov 7 16:38:59 2020 +0100

    sixel: Assign sixel background and default foreground from m_defaults
    
    This allows sixel images to be composited on any chosen background color
    including the default (resulting in transparency). It also allows
    monochrome images to be printed in the default foreground color.
    Reverse video is respected as per determine_colors().
    
    Fixes issue where palette index 0 (black) would be overwritten by the
    default foreground color.

 src/sixel-context.cc | 72 +++++++++++++++++++++++++++-------------------------
 src/sixel-context.hh | 32 +++++++++++++++--------
 src/sixel-test.cc    |  7 +++--
 src/vteinternal.hh   | 28 ++++++++++----------
 src/vteseq.cc        | 23 +++++++++++------
 5 files changed, 91 insertions(+), 71 deletions(-)
---
diff --git a/src/sixel-context.cc b/src/sixel-context.cc
index cb25fb56..10766eef 100644
--- a/src/sixel-context.cc
+++ b/src/sixel-context.cc
@@ -129,7 +129,7 @@ Context::make_color_hls(int h,
         auto const g = ((g1p + mp) * 255 + 10000) / 20000;
         auto const b = ((b1p + mp) * 255 + 10000) / 20000;
 
-        return make_color(r, g, b);
+        return make_color_opaque(r, g, b);
 }
 
 /* END */
@@ -245,22 +245,22 @@ Context::reset_colors() noexcept
          * Colours 9..14 (name marked with '*') are less saturated
          * versions of colours 1..6.
          */
-        m_colors[0 + 1]  = make_color_rgb( 0,  0,  0); /* HLS(  0,  0,  0) */ /* Black    */
-        m_colors[1 + 1]  = make_color_rgb(20, 20, 80); /* HLS(  0, 50, 60) */ /* Blue     */
-        m_colors[2 + 1]  = make_color_rgb(80, 13, 13); /* HLS(120, 46, 72) */ /* Red      */
-        m_colors[3 + 1]  = make_color_rgb(20, 80, 20); /* HLS(240, 50, 60) */ /* Green    */
-        m_colors[4 + 1]  = make_color_rgb(80, 20, 80); /* HLS( 60, 50, 60) */ /* Magenta  */
-        m_colors[5 + 1]  = make_color_rgb(20, 80, 80); /* HLS(300, 50, 60) */ /* Cyan     */
-        m_colors[6 + 1]  = make_color_rgb(80, 80, 20); /* HLS(180, 50, 60) */ /* Yellow   */
-        m_colors[7 + 1]  = make_color_rgb(53, 53, 53); /* HLS(  0, 53,  0) */ /* Grey 50% */
-        m_colors[8 + 1]  = make_color_rgb(26, 26, 26); /* HLS(  0, 26,  0) */ /* Grey 25% */
-        m_colors[9 + 1]  = make_color_rgb(33, 33, 60); /* HLS(  0, 46, 29) */ /* Blue*    */
-        m_colors[10 + 1] = make_color_rgb(60, 26, 26); /* HLS(120, 43, 39) */ /* Red*     */
-        m_colors[11 + 1] = make_color_rgb(33, 60, 33); /* HLS(240, 46, 29) */ /* Green*   */
-        m_colors[12 + 1] = make_color_rgb(60, 33, 60); /* HLS( 60, 46, 29) */ /* Magenta* */
-        m_colors[13 + 1] = make_color_rgb(33, 60, 60); /* HLS(300, 46, 29) */ /* Cyan*    */
-        m_colors[14 + 1] = make_color_rgb(60, 60, 33); /* HLS(180, 46, 29) */ /* Yellow*  */
-        m_colors[15 + 1] = make_color_rgb(80, 80, 80); /* HLS(  0, 80,  0) */ /* Grey 75% */
+        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
@@ -279,21 +279,21 @@ Context::reset_colors() noexcept
                                    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);
+                return make_color_opaque(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 + 1] = make_cube_color(n / 36, (n / 6) % 6, n % 6);
+                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 + 1] = make_color(8 + n * 10, 8 + n * 10, 8 + n * 10);
+                m_colors[n + 16 + 216 + 2] = make_color_opaque(8 + n * 10, 8 + n * 10, 8 + n * 10);
 
         /* Set all other colours to black */
-        for (auto n = 256 + 1; n < k_num_colors + 1; ++n)
-                m_colors[n] = make_color(0, 0, 0);
+        for (auto n = 256 + 2; n < k_num_colors + 2; ++n)
+                m_colors[n] = make_color_opaque(0, 0, 0);
 }
 
 void
@@ -301,11 +301,12 @@ Context::prepare(uint32_t introducer,
                  unsigned fg_red,
                  unsigned fg_green,
                  unsigned fg_blue,
+                 unsigned fg_alpha,
                  unsigned bg_red,
                  unsigned bg_green,
                  unsigned bg_blue,
+                 unsigned bg_alpha,
                  bool private_color_registers,
-                 bool opaque_bg,
                  double pixel_aspect) noexcept
 {
         m_introducer = introducer;
@@ -316,20 +317,23 @@ Context::prepare(uint32_t introducer,
         if (private_color_registers)
                 reset_colors();
 
-        if (opaque_bg)
-                set_color(0, make_color(bg_red, bg_green, bg_blue));
+        /* Premultiply alpha for Cairo */
+        fg_red = (fg_red * fg_alpha) / 255;
+        fg_green = (fg_green * fg_alpha) / 255;
+        fg_blue = (fg_blue * fg_alpha) / 255;
+        bg_red = (bg_red * bg_alpha) / 255;
+        bg_green = (bg_green * bg_alpha) / 255;
+        bg_blue = (bg_blue * bg_alpha) / 255;
 
-        /* FIXMEchpe: this all seems bogus. */
-        if (private_color_registers)
-                set_color(param_to_color_register(0),
-                          make_color(fg_red, fg_green, fg_blue));
+        set_color(0, make_color(bg_red, bg_green, bg_blue, bg_alpha));
+        set_color(1, make_color(fg_red, fg_green, fg_blue, fg_alpha));
 
         /*
          * DEC PPLV2 says that on entering DECSIXEL mode, the active colour
-         * is set to colour to colour register 0.
-         * Xterm defaults to register 3.
+         * is set to colour register 0. Xterm defaults to register 3.
+         * We use the foreground color currently set by SGR.
          */
-        set_current_color(param_to_color_register(0));
+        set_current_color(1);
 
         /* Clear buffer and scanline offsets */
         std::memset(m_scanlines_offsets, 0, sizeof(m_scanlines_offsets));
diff --git a/src/sixel-context.hh b/src/sixel-context.hh
index 32ea942c..e9544e26 100644
--- a/src/sixel-context.hh
+++ b/src/sixel-context.hh
@@ -106,7 +106,7 @@ public:
 
 private:
 
-        color_t m_colors[1 + k_num_colors];
+        color_t m_colors[2 + k_num_colors];
         bool m_palette_modified{false};
 
         color_index_t m_current_color{0};
@@ -272,28 +272,37 @@ private:
         {
                 /* Colour registers are wrapped, as per DEC documentation.
                  *
-                 * We internally reserve a register for fully transparent
-                 * colour, and use register 0 for it since that makes it easier
-                 * to initialise the buffer. Therefore the user-provided
-                 * registers are stored at + 1 their public number.
+                 * 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)) + 1;
+                return (param & (k_num_colors - 1)) + 2;
         }
 
         inline constexpr color_t
         make_color(unsigned r,
                    unsigned g,
-                   unsigned b) noexcept
+                   unsigned b,
+                   unsigned a) noexcept
         {
                 if constexpr (std::endian::native == std::endian::little) {
-                        return b | g << 8 | r << 16 | 0xffu << 24 /* opaque */;
+                        return b | g << 8 | r << 16 | a << 24;
                 } else if constexpr (std::endian::native == std::endian::big) {
-                        return 0xffu /* opaque */ | r << 8 | g << 16 | b << 24;
+                        return a | r << 8 | g << 16 | b << 24;
                 } else {
                         __builtin_unreachable();
                 }
         }
 
+        inline constexpr color_t
+        make_color_opaque(unsigned r,
+                          unsigned g,
+                          unsigned b) noexcept
+        {
+                return make_color(r, g, b, 0xff);
+        }
+
         color_t
         make_color_hls(int h,
                        int l,
@@ -309,7 +318,7 @@ private:
                         return (value * 255u + 50u) / 100u;
                 };
 
-                return make_color(scale(r), scale(g), scale(b));
+                return make_color_opaque(scale(r), scale(g), scale(b));
         }
 
         void
@@ -624,11 +633,12 @@ public:
                      unsigned fg_red,
                      unsigned fg_green,
                      unsigned fg_blue,
+                     unsigned fg_alpha,
                      unsigned bg_red,
                      unsigned bg_green,
                      unsigned bg_blue,
+                     unsigned bg_alpha,
                      bool private_color_registers,
-                     bool opaque_bg,
                      double pixel_aspect = 1.0) noexcept;
 
         void reset_colors() noexcept;
diff --git a/src/sixel-test.cc b/src/sixel-test.cc
index db0f2d43..163c410a 100644
--- a/src/sixel-test.cc
+++ b/src/sixel-test.cc
@@ -1025,10 +1025,9 @@ parse_image(C& context,
 {
         context.reset();
         context.prepare(0x50 /* C0 DCS */,
-                        fg_red, fg_green, fg_blue,
-                        bg_red, bg_green, bg_blue,
-                        private_color_registers,
-                        opaque_bg);
+                        fg_red, fg_green, fg_blue, 0xff,
+                        bg_red, bg_green, bg_blue, 0x00,
+                        private_color_registers);
 
         auto str_st = std::string{str};
         str_st.append(ST(StType::C0));
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 57895de3..ed57e9e1 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -987,24 +987,24 @@ public:
         GString* get_selected_text(GArray* attributes = nullptr);
 
         template<unsigned int redbits, unsigned int greenbits, unsigned int bluebits>
-        inline void rgb_from_index(guint index,
-                                   vte::color::rgb& color) const;
-        inline void determine_colors(VteCellAttr const* attr,
+        void rgb_from_index(guint index,
+                            vte::color::rgb& color) const;
+        void determine_colors(VteCellAttr const* attr,
+                              bool selected,
+                              bool cursor,
+                              guint *pfore,
+                              guint *pback,
+                              guint *pdeco) const;
+        void determine_colors(VteCell const* cell,
+                              bool selected,
+                              guint *pfore,
+                              guint *pback,
+                              guint *pdeco) const;
+        void determine_cursor_colors(VteCell const* cell,
                                      bool selected,
-                                     bool cursor,
                                      guint *pfore,
                                      guint *pback,
                                      guint *pdeco) const;
-        inline void determine_colors(VteCell const* cell,
-                                     bool selected,
-                                     guint *pfore,
-                                     guint *pback,
-                                     guint *pdeco) const;
-        inline void determine_cursor_colors(VteCell const* cell,
-                                            bool selected,
-                                            guint *pfore,
-                                            guint *pback,
-                                            guint *pdeco) const;
 
         char *cellattr_to_html(VteCellAttr const* attr,
                                char const* text) const;
diff --git a/src/vteseq.cc b/src/vteseq.cc
index aa5d91a3..e2c17852 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -4438,18 +4438,25 @@ Terminal::DECSIXEL(vte::parser::Sequence const& seq)
         }
 
         try {
+                bool force_transparent_bg = seq.collect1(1) == 1 ? true : false;
+                guint fore, back, deco;
+                vte::color::rgb fg, bg;
+
+                determine_colors(&m_defaults, false, &fore, &back, &deco);
+                rgb_from_index<8, 8, 8>(fore, fg);
+                rgb_from_index<8, 8, 8>(back, bg);
+
                 if (!m_sixel_context)
                         m_sixel_context = std::make_unique<vte::sixel::Context>();
 
-                auto const fg = get_color(VTE_DEFAULT_FG);
-                auto const bg = get_color(VTE_DEFAULT_BG);
-                auto const opaque_bg = seq.collect1(1) == 1 ? false : true;
-
+                /* If colors were swapped, foreground can be set to the default background
+                 * color, resulting in transparency in inked pixels. This is expected. */
                 m_sixel_context->prepare(seq.st(),
-                                         fg->red >> 8, fg->green >> 8, fg->blue >> 8,
-                                         bg->red >> 8, bg->green >> 8, bg->blue >> 8,
-                                         m_modes_private.XTERM_SIXEL_PRIVATE_COLOR_REGISTERS(),
-                                         opaque_bg);
+                                         fg.red >> 8, fg.green >> 8, fg.blue >> 8,
+                                         fore == VTE_DEFAULT_BG ? 0 : 255,
+                                         bg.red >> 8, bg.green >> 8, bg.blue >> 8,
+                                         (back == VTE_DEFAULT_BG || force_transparent_bg) ? 0 : 255,
+                                         m_modes_private.XTERM_SIXEL_PRIVATE_COLOR_REGISTERS());
 
                 m_sixel_context->set_mode(mode);
 


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