[vte/wip/sixels: 61/82] ring: Implement rewrapping for images



commit 3bbefb9538ce58d724cc2776def83290d9726e72
Author: Hans Petter Jansson <hpj cl no>
Date:   Tue Jun 16 21:13:49 2020 +0200

    ring: Implement rewrapping for images

 src/image.hh |  1 +
 src/ring.cc  | 96 +++++++++++++++++++++++++++++++++++++++++++++++-------------
 src/ring.hh  |  7 ++++-
 3 files changed, 83 insertions(+), 21 deletions(-)
---
diff --git a/src/image.hh b/src/image.hh
index 02914985..9056274e 100644
--- a/src/image.hh
+++ b/src/image.hh
@@ -65,6 +65,7 @@ public:
         inline constexpr auto get_priority() const noexcept { return m_priority; }
         inline constexpr auto get_left() const noexcept { return m_left_cells; }
         inline constexpr 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 constexpr auto get_bottom() const noexcept { return m_top_cells + get_height() - 1; }
diff --git a/src/ring.cc b/src/ring.cc
index 70534db2..55388fc4 100644
--- a/src/ring.cc
+++ b/src/ring.cc
@@ -96,7 +96,7 @@ Ring::Ring(row_t max_rows,
         g_ptr_array_add(m_hyperlinks, empty_str);
 
         m_next_image_priority = 0;
-        m_image_map = new (std::nothrow) std::map<gint, vte::image::Image *>();
+        m_image_by_top_map = new (std::nothrow) std::map<gint, vte::image::Image *>();
         m_image_priority_map = new (std::nothrow) std::map<int, vte::image::Image *>();
         m_image_fast_memory_used = 0;
 
@@ -105,7 +105,7 @@ Ring::Ring(row_t max_rows,
 
 Ring::~Ring()
 {
-       auto image_map = m_image_map;
+       auto image_map = m_image_by_top_map;
 
        for (size_t i = 0; i <= m_mask; i++)
                _vte_row_data_fini (&m_array[i]);
@@ -116,7 +116,7 @@ Ring::~Ring()
        for (auto it = image_map->begin (); it != image_map->end (); ++it)
                delete it->second;
        image_map->clear();
-       delete m_image_map;
+       delete m_image_by_top_map;
         delete m_image_priority_map;
 
        if (m_has_streams) {
@@ -236,8 +236,7 @@ Ring::image_gc_region()
 
                         /* Apparently this is the cleanest way to erase() with a reverse iterator... */
                         it = decltype(it){m_image_priority_map->erase(std::next(it).base())};
-
-                        m_image_map->erase(image->get_bottom());
+                        unlink_image_from_top_map(image);
                         delete image;
                         continue;
                 }
@@ -261,12 +260,58 @@ Ring::image_gc()
 
                 vte::image::Image *image = m_image_priority_map->begin()->second;
                 m_image_fast_memory_used -= image->resource_size();
-                m_image_map->erase(image->get_bottom());
                 m_image_priority_map->erase(m_image_priority_map->begin());
+                unlink_image_from_top_map(image);
                 delete image;
         }
 }
 
+void
+Ring::unlink_image_from_top_map(vte::image::Image *image)
+{
+        for (auto it = m_image_by_top_map->find(image->get_top()); it != m_image_by_top_map->end(); it++) {
+                vte::image::Image *cur_image = it->second;
+
+                if (cur_image->get_priority() == image->get_priority()) {
+                        m_image_by_top_map->erase(it);
+                        break;
+                }
+        }
+}
+
+void
+Ring::rebuild_image_top_map()
+{
+        m_image_by_top_map->clear();
+
+        for (auto it = m_image_priority_map->begin(); it != m_image_priority_map->end(); it++) {
+                vte::image::Image *image = it->second;
+                m_image_by_top_map->insert(std::make_pair(image->get_top(), image));
+        }
+}
+
+bool
+Ring::rewrap_images_in_range(std::map<int,vte::image::Image*>::iterator &it,
+                             size_t text_start_ofs, size_t text_end_ofs, row_t new_row_index)
+{
+        for ( ; it != m_image_by_top_map->end(); it++) {
+                vte::image::Image *image = it->second;
+                CellTextOffset ofs;
+
+                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;
+}
+
 /*
  * Find existing idx for the hyperlink or allocate a new one.
  *
@@ -661,7 +706,7 @@ Ring::reset_streams(row_t position)
 Ring::row_t
 Ring::reset()
 {
-       auto image_map = m_image_map;
+       auto image_map = m_image_by_top_map;
 
         _vte_debug_print (VTE_DEBUG_RING, "Reseting the ring at %lu.\n", m_end);
 
@@ -1106,7 +1151,16 @@ Ring::frozen_row_column_to_text_offset(row_t position,
        } else
                records[1].text_start_offset = _vte_stream_head(m_text_stream);
 
-       g_string_set_size (buffer, records[1].text_start_offset - records[0].text_start_offset);
+       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);
        if (!_vte_stream_read(m_text_stream, records[0].text_start_offset, buffer->str, buffer->len))
                return false;
 
@@ -1118,8 +1172,6 @@ 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())) {
@@ -1140,7 +1192,7 @@ Ring::frozen_row_column_to_text_offset(row_t position,
                off++;
                if ((buffer->str[off] & 0xC0) != 0x80) num_chars--;
        }
-       offset->text_offset = records[0].text_start_offset + off;
+       offset->text_offset += off;
        return true;
 }
 
@@ -1252,6 +1304,7 @@ Ring::rewrap(column_t columns,
        gsize paragraph_len;  /* excluding trailing '\n' */
        gsize attr_offset;
        gsize old_ring_end;
+        auto image_it = m_image_by_top_map->begin();
 
        if (G_UNLIKELY(length() == 0))
                return;
@@ -1386,10 +1439,15 @@ Ring::rewrap(column_t columns,
                                                                                "      Marker #%d will be 
here in row %lu\n", i, new_row_index);
                                                        }
                                                }
+
+                                                if (!rewrap_images_in_range(image_it, 
new_record.text_start_offset, text_offset, new_row_index))
+                                                        goto err;
+
                                                new_row_index++;
                                                new_record.text_start_offset = text_offset;
                                                new_record.attr_start_offset = attr_offset;
                                                col = 0;
+
                                        }
                                        if (paragraph_is_ascii) {
                                                /* Shortcut for quickly wrapping ASCII (excluding TAB) text.
@@ -1433,6 +1491,10 @@ Ring::rewrap(column_t columns,
                                                "      Marker #%d will be here in row %lu\n", i, 
new_row_index);
                        }
                }
+
+                if (!rewrap_images_in_range(image_it, new_record.text_start_offset, 
paragraph_end_text_offset, new_row_index))
+                        goto err;
+
                new_row_index++;
                paragraph_start_text_offset = paragraph_end_text_offset;
        }
@@ -1465,6 +1527,8 @@ Ring::rewrap(column_t columns,
        g_free(marker_text_offsets);
        g_free(new_markers);
 
+        rebuild_image_top_map();
+
        _vte_debug_print(VTE_DEBUG_RING, "Ring after rewrapping:\n");
         validate();
        return;
@@ -1594,15 +1658,7 @@ Ring::append_image (cairo_surface_t *surface, gint pixelwidth, gint pixelheight,
                                           cell_width, cell_height);
        g_assert (image != NULL);
 
-       /*
-        * Now register new image to the m_image_map container.
-        * the key is bottom positon.
-        *  +----------+
-        *  |   new    |
-        *  |          |
-        *  +----------+ <- bottom position (key)
-        */
-       m_image_map->insert (std::make_pair (image->get_bottom (), image));
+       m_image_by_top_map->insert (std::make_pair (image->get_top (), image));
         m_image_priority_map->insert (std::make_pair (image->get_priority (), image));
        m_image_fast_memory_used += image->resource_size ();
 
diff --git a/src/ring.hh b/src/ring.hh
index ff384f3b..53e34dd4 100644
--- a/src/ring.hh
+++ b/src/ring.hh
@@ -116,7 +116,7 @@ public:
 
         int m_next_image_priority;
 
-        std::map<gint, vte::image::Image *> *m_image_map;
+        std::map<gint, vte::image::Image *> *m_image_by_top_map;
         std::map<int, vte::image::Image *> *m_image_priority_map;
         unsigned int m_image_fast_memory_used;
 
@@ -137,6 +137,11 @@ private:
         void image_gc_region();
         hyperlink_idx_t get_hyperlink_idx_no_update_current(char const* hyperlink);
 
+        void unlink_image_from_top_map(vte::image::Image *image);
+        void rebuild_image_top_map();
+        bool rewrap_images_in_range(std::map<int,vte::image::Image*>::iterator &it,
+                                    size_t text_start_ofs, size_t text_end_ofs, row_t new_row_index);
+
         typedef struct _CellAttrChange {
                 gsize text_end_offset;  /* offset of first character no longer using this attr */
                 VteStreamCellAttr attr;


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