diff --git a/src/vte.cc b/src/vte.cc
index 6fe836dc..fbb831b1 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -6174,6 +6174,7 @@ vte_terminal_cellattr_equal(VteCellAttr const *attr1,
 	        attr1->italic        == attr2->italic    &&
 	        attr1->fore          == attr2->fore      &&
 	        attr1->back          == attr2->back      &&
+                attr1->deco          == attr2->deco      &&
 	        attr1->underline     == attr2->underline &&
 	        attr1->strikethrough == attr2->strikethrough &&
 	        attr1->reverse       == attr2->reverse   &&
@@ -6192,11 +6193,11 @@ VteTerminalPrivate::cellattr_to_html(VteCellAttr const* attr,
                                      char const* text) const
 {
 	GString *string;
-	guint fore, back;
+        guint fore, back, deco;
 
 	string = g_string_new(text);
 
-	determine_colors(attr, false, false, &fore, &back);
+        determine_colors(attr, false, false, &fore, &back, &deco);
 
 	if (attr->bold) {
 		g_string_prepend(string, "<b>");
@@ -6209,12 +6210,26 @@ VteTerminalPrivate::cellattr_to_html(VteCellAttr const* attr,
         /* <u> should be inside <font> so that it inherits its color by default */
         if (attr->underline) {
                 const char *styles[] = {"", "single", "double", "wavy"};
-                char *tag;
+                char *tag, *colorattr;
+
+                if (attr->deco != VTE_DEFAULT_FG) {
+                        vte::color::rgb color;
+
+                        rgb_from_index(attr->deco, color);
+                        colorattr = g_strdup_printf(";text-decoration-color:#%02X%02X%02X",
+                                                    color.red >> 8,
+                                                    color.green >> 8,
+                                                    color.blue >> 8);
+                } else {
+                        colorattr = g_strdup("");
+                }
 
-                tag = g_strdup_printf("<u style=\"text-decoration-style:%s\">",
-                                      styles[attr->underline]);
+                tag = g_strdup_printf("<u style=\"text-decoration-style:%s%s\">",
+                                      styles[attr->underline],
+                                      colorattr);
                 g_string_prepend(string, tag);
                 g_free(tag);
+                g_free(colorattr);
                 g_string_append(string, "</u>");
         }
 	if (attr->fore != VTE_DEFAULT_FG || attr->reverse) {
@@ -8796,15 +8811,17 @@ VteTerminalPrivate::determine_colors(VteCellAttr const* attr,
                                      bool is_selected,
                                      bool is_cursor,
                                      guint *pfore,
-                                     guint *pback) const
+                                     guint *pback,
+                                     guint *pdeco) const
 {
-	guint fore, back;
+        guint fore, back, deco;
 
         g_assert(attr);
 
 	/* Start with cell colors */
 	fore = attr->fore;
 	back = attr->back;
+        deco = attr->deco;
 
 	/* Reverse-mode switches default fore and back colors */
         if (G_UNLIKELY (m_reverse_mode)) {
@@ -8869,33 +8886,36 @@ VteTerminalPrivate::determine_colors(VteCellAttr const* attr,
 
 	/* Invisible? */
 	if (attr->invisible) {
-		fore = back;
+                fore = deco = back;
 	}
 
 	*pfore = fore;
 	*pback = back;
+        *pdeco = deco;
 }
 
 void
 VteTerminalPrivate::determine_colors(VteCell const* cell,
                                      bool highlight,
                                      guint *fore,
-                                     guint *back) const
+                                     guint *back,
+                                     guint *deco) const
 {
 	determine_colors(cell ? &cell->attr : &basic_cell.attr,
                          highlight, false /* not cursor */,
-                         fore, back);
+                         fore, back, deco);
 }
 
 void
 VteTerminalPrivate::determine_cursor_colors(VteCell const* cell,
                                             bool highlight,
                                             guint *fore,
-                                            guint *back) const
+                                            guint *back,
+                                            guint *deco) const
 {
 	determine_colors(cell ? &cell->attr : &basic_cell.attr,
                          highlight, true /* cursor */,
-                         fore, back);
+                         fore, back, deco);
 }
 
 /* Draw a string of characters with similar attributes. */
@@ -8904,6 +8924,7 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
                                gssize n,
                                guint fore,
                                guint back,
+                               guint deco,
                                bool clear,
                                bool draw_default_bg,
                                bool bold,
@@ -8918,7 +8939,7 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
 {
 	int i, x, y;
 	gint columns = 0;
-	vte::color::rgb fg, bg;
+        vte::color::rgb fg, bg, dc;
 
 	g_assert(n > 0);
 	_VTE_DEBUG_IF(VTE_DEBUG_CELLS) {
@@ -8928,10 +8949,10 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
 			g_string_append_unichar (str, items[i].c);
 		}
 		tmp = g_string_free (str, FALSE);
-		g_printerr ("draw_cells('%s', fore=%d, back=%d, bold=%d,"
+                g_printerr ("draw_cells('%s', fore=%d, back=%d, deco=%d, bold=%d,"
                                 " ul=%d, strike=%d,"
                                 " hyperlink=%d, hilite=%d, boxed=%d)\n",
-				tmp, fore, back, bold,
+                                tmp, fore, back, deco, bold,
                                 underline, strikethrough,
                                 hyperlink, hilite, boxed);
 		g_free (tmp);
@@ -8940,6 +8961,7 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
 	bold = bold && m_allow_bold;
 	rgb_from_index(fore, fg);
 	rgb_from_index(back, bg);
+        rgb_from_index(deco == VTE_DEFAULT_FG ? fore : deco, dc);
 
 	i = 0;
 	do {
@@ -8960,12 +8982,9 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
 		}
 	} while (i < n);
 
-	_vte_draw_text(m_draw,
-			items, n,
-			&fg, VTE_DRAW_OPAQUE,
-			_vte_draw_get_style(bold, italic));
-
-	/* Draw whatever SFX are required. */
+        /* Draw whatever SFX are required. Do this before drawing the letters,
+         * so that if the descent of a letter crosses an underline of a different color,
+         * it's the letter's color that wins. */
         if (underline | strikethrough | hyperlink | hilite | boxed) {
 		i = 0;
 		do {
@@ -8984,7 +9003,7 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
                                                             x + (columns * column_width) - 1,
                                                             y + position + thickness - 1,
                                                             VTE_LINE_WIDTH,
-                                                            &fg, VTE_DRAW_OPAQUE);
+                                                            &dc, VTE_DRAW_OPAQUE);
                                 }
                         } else if (underline == 3) {
                                 for (int j = 0; j < columns; j++) {
@@ -8993,7 +9012,7 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
                                                                  y + m_undercurl_position,
                                                                  column_width,
                                                                  m_undercurl_thickness,
-                                                                 &fg, VTE_DRAW_OPAQUE);
+                                                                 &dc, VTE_DRAW_OPAQUE);
                                 }
 			}
 			if (strikethrough) {
@@ -9030,8 +9049,13 @@ VteTerminalPrivate::draw_cells(struct _vte_draw_text_request *items,
                                                          MAX(0, row_height),
                                                          &fg, VTE_DRAW_OPAQUE);
 			}
-		}while (i < n);
+                } while (i < n);
 	}
+
+        _vte_draw_text(m_draw,
+                       items, n,
+                       &fg, VTE_DRAW_OPAQUE,
+                       _vte_draw_get_style(bold, italic));
 }
 
 /* FIXME: we don't have a way to tell GTK+ what the default text attributes
@@ -9232,7 +9256,7 @@ VteTerminalPrivate::draw_cells_with_attributes(struct _vte_draw_text_request *it
         int i, j, cell_count;
 	VteCell *cells;
 	char scratch_buf[VTE_UTF8_BPC];
-	guint fore, back;
+        guint fore, back, deco;
 
 	/* Note: since this function is only called with the pre-edit text,
 	 * all the items contain gunichar only, not vteunistr. */
@@ -9244,10 +9268,11 @@ VteTerminalPrivate::draw_cells_with_attributes(struct _vte_draw_text_request *it
 	cells = g_new(VteCell, cell_count);
 	translate_pango_cells(attrs, cells, cell_count);
 	for (i = 0, j = 0; i < n; i++) {
-		determine_colors(&cells[j], false, &fore, &back);
+                determine_colors(&cells[j], false, &fore, &back, &deco);
 		draw_cells(items + i, 1,
 					fore,
 					back,
+                                        deco,
 					TRUE, draw_default_bg,
 					cells[j].attr.bold,
 					cells[j].attr.italic,
@@ -9279,7 +9304,7 @@ VteTerminalPrivate::draw_rows(VteScreen *screen_,
         vte::grid::row_t row, rows;
         vte::grid::column_t i, j;
         long x, y;
-        guint fore, nfore, back, nback, underline, nunderline;
+        guint fore, nfore, back, nback, deco, ndeco, underline, nunderline;
         gboolean bold, nbold, italic, nitalic,
                  hyperlink, nhyperlink, hilite, nhilite,
 		 selected, nselected, strikethrough, nstrikethrough;
@@ -9313,7 +9338,7 @@ VteTerminalPrivate::draw_rows(VteScreen *screen_,
 				cell = _vte_row_data_get (row_data, i);
 				/* Find the colors for this cell. */
 				selected = cell_is_selected(i, row);
-				determine_colors(cell, selected, &fore, &back);
+                                determine_colors(cell, selected, &fore, &back, &deco);
 
 				bold = cell && cell->attr.bold;
 				j = i + (cell ? cell->attr.columns : 1);
@@ -9332,7 +9357,7 @@ VteTerminalPrivate::draw_rows(VteScreen *screen_,
 					 * compare visual attributes to the first character
 					 * in this chunk. */
 					selected = cell_is_selected(j, row);
-					determine_colors(cell, selected, &nfore, &nback);
+                                        determine_colors(cell, selected, &nfore, &nback, &ndeco);
 					if (nback != back) {
 						break;
 					}
@@ -9367,7 +9392,7 @@ VteTerminalPrivate::draw_rows(VteScreen *screen_,
 					}
 					j++;
 				}
-				determine_colors(nullptr, selected, &fore, &back);
+                                determine_colors(nullptr, selected, &fore, &back, &deco);
 				if (back != VTE_DEFAULT_BG) {
 					vte::color::rgb bg;
 					rgb_from_index(back, bg);
@@ -9429,7 +9454,7 @@ VteTerminalPrivate::draw_rows(VteScreen *screen_,
 			}
 			/* Find the colors for this cell. */
 			selected = cell_is_selected(i, row);
-			determine_colors(cell, selected, &fore, &back);
+                        determine_colors(cell, selected, &fore, &back, &deco);
 			underline = cell->attr.underline;
 			strikethrough = cell->attr.strikethrough;
                         hyperlink = (m_allow_hyperlink && cell->attr.hyperlink_idx != 0);
@@ -9480,10 +9505,13 @@ VteTerminalPrivate::draw_rows(VteScreen *screen_,
 					 * compare visual attributes to the first character
 					 * in this chunk. */
 					selected = cell_is_selected(j, row);
-					determine_colors(cell, selected, &nfore, &nback);
+                                        determine_colors(cell, selected, &nfore, &nback, &ndeco);
 					if (nfore != fore) {
 						break;
 					}
+                                        if (ndeco != deco) {
+                                                break;
+                                        }
 					nbold = cell->attr.bold;
 					if (nbold != bold) {
 						break;
@@ -9556,7 +9584,7 @@ fg_draw:
 			draw_cells(
 					items,
 					item_count,
-					fore, back, FALSE, FALSE,
+                                        fore, back, deco, FALSE, FALSE,
 					bold, italic, underline,
                                         strikethrough, hyperlink, hilite, FALSE,
 					column_width, row_height);
@@ -9662,7 +9690,7 @@ VteTerminalPrivate::paint_cursor()
         vte::grid::column_t col;
         int width, height, cursor_width;
         guint style = 0;
-	guint fore, back;
+        guint fore, back, deco;
 	vte::color::rgb bg;
 	int x, y;
 	gboolean blink, selected, focus;
@@ -9706,7 +9734,7 @@ VteTerminalPrivate::paint_cursor()
 	}
 
 	selected = cell_is_selected(col, drow);
-	determine_cursor_colors(cell, selected, &fore, &back);
+        determine_cursor_colors(cell, selected, &fore, &back, &deco);
 	rgb_from_index(back, bg);
 
 	x = item.x;
@@ -9785,7 +9813,7 @@ VteTerminalPrivate::paint_cursor()
                                 if (cell && cell->c != 0 && cell->c != ' ' && cell->c != '\t') {
                                         draw_cells(
                                                         &item, 1,
-                                                        fore, back, TRUE, FALSE,
+                                                        fore, back, deco, TRUE, FALSE,
                                                         cell->attr.bold,
                                                         cell->attr.italic,
                                                         cell->attr.underline,
@@ -9817,7 +9845,7 @@ VteTerminalPrivate::paint_im_preedit_string()
 	int col, columns;
 	long width, height;
 	int i, len;
-	guint fore, back;
+        guint fore, back, deco;
 
 	if (!m_im_preedit)
 		return;
@@ -9862,6 +9890,7 @@ VteTerminalPrivate::paint_im_preedit_string()
                                 get_color(VTE_DEFAULT_BG), m_background_alpha);
                 fore = m_color_defaults.attr.fore;
                 back = m_color_defaults.attr.back;
+                deco = m_color_defaults.attr.deco;
 		draw_cells_with_attributes(
 							items, len,
 							m_im_preedit_attrs,
@@ -9872,7 +9901,7 @@ VteTerminalPrivate::paint_im_preedit_string()
 			/* Cursored letter in reverse. */
 			draw_cells(
 						&items[preedit_cursor], 1,
-                                                back, fore,
+                                                back, fore, deco,
                                                 TRUE,  /* clear */
                                                 TRUE,  /* draw_default_bg */
                                                 FALSE, /* bold */
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index e3733b29..e284447e 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -835,6 +835,7 @@ public:
                         gssize n,
                         guint fore,
                         guint back,
+                        guint deco,
                         bool clear,
                         bool draw_default_bg,
                         bool bold,
@@ -986,15 +987,18 @@ public:
                                      bool selected,
                                      bool cursor,
                                      guint *pfore,
-                                     guint *pback) const;
+                                     guint *pback,
+                                     guint *pdeco) const;
         inline void determine_colors(VteCell const* cell,
                                      bool selected,
                                      guint *pfore,
-                                     guint *pback) const;
+                                     guint *pback,
+                                     guint *pdeco) const;
         inline void determine_cursor_colors(VteCell const* cell,
                                             bool selected,
                                             guint *pfore,
-                                            guint *pback) const;
+                                            guint *pback,
+                                            guint *pdeco) const;
 
         char *cellattr_to_html(VteCellAttr const* attr,
                                char const* text) const;
diff --git a/src/vterowdata.h b/src/vterowdata.h
index 630cd1ad..f441952a 100644
--- a/src/vterowdata.h
+++ b/src/vterowdata.h
@@ -32,7 +32,7 @@ G_BEGIN_DECLS
 #define VTE_TAB_WIDTH_BITS		4  /* Has to be able to store the value of 8. */
 #define VTE_TAB_WIDTH_MAX		((1 << VTE_TAB_WIDTH_BITS) - 1)
 
-#define VTE_CELL_ATTR_COMMON_BYTES      8  /* The number of common bytes in VteCellAttr and VteStreamCellAttr */
+#define VTE_CELL_ATTR_COMMON_BYTES      12  /* The number of common bytes in VteCellAttr and VteStreamCellAttr */
 
 /*
  * VteCellAttr: A single cell style attributes
@@ -63,6 +63,9 @@ typedef struct _VteCellAttr {
 
 	guint64 invisible: 1;
         /* 8-byte boundary */
+        guint32 deco: 25;       /* decoration color (currently for underline) */
+        guint32 padding_unused: 7;
+        /* 12-byte boundary */
         guint32 hyperlink_idx;  /* a unique hyperlink index at a time for the ring's cells,
                                    0 means not a hyperlink, VTE_HYPERLINK_IDX_TARGET_IN_STREAM
                                    means the target is irrelevant/unknown at the moment.
@@ -70,7 +73,6 @@ typedef struct _VteCellAttr {
                                    for every cell in the ring but not yet in the stream
                                    (currently the height rounded up to the next power of two, times width)
                                    for supported VTE sizes, and update VTE_HYPERLINK_IDX_TARGET_IN_STREAM. */
-        guint32 padding_unused;
 } VteCellAttr;
 G_STATIC_ASSERT (sizeof (VteCellAttr) == 16);
 G_STATIC_ASSERT (offsetof (VteCellAttr, hyperlink_idx) == VTE_CELL_ATTR_COMMON_BYTES);
@@ -85,13 +87,15 @@ G_STATIC_ASSERT (offsetof (VteCellAttr, hyperlink_idx) == VTE_CELL_ATTR_COMMON_B
 typedef struct _VTE_GNUC_PACKED _VteStreamCellAttr {
         guint64 fragment: 1;
         guint64 columns: VTE_TAB_WIDTH_BITS;
-        guint64 remaining_main_attributes: 59;  /* All the non-hyperlink related attributes from VteCellAttr.
-                                                   We don't individually access them in the stream, so there's
-                                                   no point in repeating each field separately. */
+        guint64 remaining_main_attributes_1: 59;  /* All the non-hyperlink related attributes from VteCellAttr, part 1.
+                                                     We don't individually access them in the stream, so there's
+                                                     no point in repeating each field separately. */
         /* 8-byte boundary */
+        guint32 remaining_main_attributes_2;      /* Non-hyperlink related attributes, part 2. */
+        /* 12-byte boundary */
         guint16 hyperlink_length;       /* make sure it fits VTE_HYPERLINK_TOTAL_LENGTH_MAX */
 } VteStreamCellAttr;
-G_STATIC_ASSERT (sizeof (VteStreamCellAttr) == 10);
+G_STATIC_ASSERT (sizeof (VteStreamCellAttr) == 14);
 G_STATIC_ASSERT (offsetof (VteStreamCellAttr, hyperlink_length) == VTE_CELL_ATTR_COMMON_BYTES);
 
 /*
@@ -122,8 +126,9 @@ static const VteCell basic_cell = {
 		0, /* half */
 
                 0, /* invisible */
-                0, /* hyperlink_idx */
+                VTE_DEFAULT_FG, /* deco */
                 0, /* padding_unused */
+                0, /* hyperlink_idx */
 	}
 };
 
diff --git a/src/vteseq.cc b/src/vteseq.cc
index e0de1382..a8a8ddc7 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -1801,7 +1801,7 @@ VteTerminalPrivate::seq_vertical_tab(vte::parser::Params const& params)
         line_feed();
 }
 
-/* Parse parameters of SGR 38 or 48, starting at @index within @params.
+/* Parse parameters of SGR 38, 48 or 58, starting at @index within @params.
  * Returns the color index, or -1 on error.
  * Increments @index to point to the last consumed parameter (not beyond). */
 int32_t
@@ -1871,6 +1871,7 @@ VteTerminalPrivate::seq_character_attributes(vte::parser::Params const& params)
                                 break;
                         case 38:
                         case 48:
+                        case 58:
                         {
                                 unsigned int index = 1;
                                 auto color = parse_sgr_38_48_parameters(subparams, &index);
@@ -1880,8 +1881,10 @@ VteTerminalPrivate::seq_character_attributes(vte::parser::Params const& params)
                                 if (G_LIKELY (color != -1)) {
                                         if (param0 == 38) {
                                                 m_defaults.attr.fore = color;
-                                        } else {
+                                        } else if (param0 == 48) {
                                                 m_defaults.attr.back = color;
+                                        } else {
+                                                m_defaults.attr.deco = color;
                                         }
                                 }
                                 break;
@@ -1960,6 +1963,7 @@ VteTerminalPrivate::seq_character_attributes(vte::parser::Params const& params)
 			break;
 		case 38:
 		case 48:
+                case 58:
 		{
 			/* The format looks like:
 			 * - 256 color indexed palette:
@@ -1995,8 +1999,10 @@ VteTerminalPrivate::seq_character_attributes(vte::parser::Params const& params)
 				if (G_LIKELY (color != -1)) {
 					if (param == 38) {
                                                 m_defaults.attr.fore = color;
-					} else {
+                                        } else if (param == 48) {
                                                 m_defaults.attr.back = color;
+                                        } else {
+                                                m_defaults.attr.deco = color;
 					}
 				}
 			}
@@ -2021,6 +2027,11 @@ VteTerminalPrivate::seq_character_attributes(vte::parser::Params const& params)
 			/* default background */
                         m_defaults.attr.back = VTE_DEFAULT_BG;
 			break;
+             /* case 58: was handled above at 38 to avoid code duplication */
+                case 59:
+                        /* default decoration color, that is, same as the cell's foreground */
+                        m_defaults.attr.deco = VTE_DEFAULT_FG;
+                        break;
 		case 90:
 		case 91:
 		case 92:
