From bd0f56f6baa170ff5b66acbba2110d186b868960 Mon Sep 17 00:00:00 2001 From: Yuri Kobets Date: Tue, 3 Jun 2025 03:14:41 +0300 Subject: [PATCH 1/6] Fix: url fragment is not processed correctly Issue appears in these cases: 1. fragment contains spesial characters (quotes for example) 2. fragment starts with number --- support/webpage/web_page.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/support/webpage/web_page.cpp b/support/webpage/web_page.cpp index 2f90600b..923235d0 100644 --- a/support/webpage/web_page.cpp +++ b/support/webpage/web_page.cpp @@ -118,13 +118,9 @@ void litebrowser::web_page::show_hash(const litehtml::string& hash) m_html_host->scroll_to(0, 0); } else { - std::string selector = "#" + hash; + auto escaped_hash = litehtml::get_escaped_string(hash); + std::string selector = ":is([id=\"" + escaped_hash + "\"],[name=\"" + escaped_hash + "\"])"; litehtml::element::ptr el = m_html->root()->select_one(selector); - if (!el) - { - selector = "[name=" + hash + "]"; - el = m_html->root()->select_one(selector); - } if (el) { litehtml::position pos = el->get_placement(); From 131b44b0076826d14e4f25b0ecf424bed3500d03 Mon Sep 17 00:00:00 2001 From: Yuri Kobets Date: Wed, 4 Jun 2025 00:07:43 +0300 Subject: [PATCH 2/6] refactor: hash renamed to the fragment --- support/gtkmm4/html_widget.cpp | 28 ++++++++++++++-------------- support/gtkmm4/html_widget.h | 4 ++-- support/webpage/web_page.cpp | 10 +++++----- support/webpage/web_page.h | 14 +++++++------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/support/gtkmm4/html_widget.cpp b/support/gtkmm4/html_widget.cpp index 9d6365ea..852e6d4c 100644 --- a/support/gtkmm4/html_widget.cpp +++ b/support/gtkmm4/html_widget.cpp @@ -180,7 +180,7 @@ cairo_surface_t *html_widget::load_image(const std::string &path) } -void html_widget::open_page(const litehtml::string& url, const litehtml::string& hash) +void html_widget::open_page(const litehtml::string& url, const litehtml::string& fragment) { { std::lock_guard lock(m_page_mutex); @@ -189,7 +189,7 @@ void html_widget::open_page(const litehtml::string& url, const litehtml::string& m_current_page->stop_loading(); } m_next_page = std::make_shared(this, m_notifier, 10); - m_next_page->open(url, hash); + m_next_page->open(url, fragment); } m_sig_set_address.emit(url); m_sig_update_state.emit(get_state()); @@ -619,37 +619,37 @@ void html_widget::on_page_loaded(uint64_t web_page_id) m_sig_update_state.emit(get_state()); } -void html_widget::show_hash(const std::string &hash) +void html_widget::show_fragment(const std::string &fragment) { std::shared_ptr page = current_page(); if(page) { - page->show_hash(hash); + page->show_fragment(fragment); } } void html_widget::open_url(const std::string &url) { - std::string hash; + std::string fragment; std::string s_url = url; m_sig_set_address.emit(url); - std::string::size_type hash_pos = s_url.find_first_of(L'#'); - if(hash_pos != std::wstring::npos) + std::string::size_type fragment_pos = s_url.find_first_of(L'#'); + if(fragment_pos != std::wstring::npos) { - hash = s_url.substr(hash_pos + 1); - s_url.erase(hash_pos); + fragment = s_url.substr(fragment_pos + 1); + s_url.erase(fragment_pos); } bool open_hash_only = false; bool reload = false; auto current_url = m_history.current(); - hash_pos = current_url.find_first_of(L'#'); - if(hash_pos != std::wstring::npos) + fragment_pos = current_url.find_first_of(L'#'); + if(fragment_pos != std::wstring::npos) { - current_url.erase(hash_pos); + current_url.erase(fragment_pos); } if(!current_url.empty()) @@ -667,10 +667,10 @@ void html_widget::open_url(const std::string &url) } if(!open_hash_only) { - open_page(url, hash); + open_page(url, fragment); } else { - show_hash(hash); + show_fragment(fragment); } if(!reload) { diff --git a/support/gtkmm4/html_widget.h b/support/gtkmm4/html_widget.h index ef5f15d0..042834e4 100644 --- a/support/gtkmm4/html_widget.h +++ b/support/gtkmm4/html_widget.h @@ -235,7 +235,7 @@ class html_widget : public Gtk::Widget, std::string get_html_source(); long render_measure(int number); long draw_measure(int number); - void show_hash(const std::string& hash); + void show_fragment(const std::string& fragment); bool on_close(); void dump(litehtml::dumper& cout); @@ -246,7 +246,7 @@ class html_widget : public Gtk::Widget, double get_dpi() override; int get_screen_width() override; int get_screen_height() override; - void open_page(const litehtml::string& url, const litehtml::string& hash); + void open_page(const litehtml::string& url, const litehtml::string& fragment); void update_cursor() override; void redraw_boxes(const litehtml::position::vector& boxes) override; int get_render_width() override; diff --git a/support/webpage/web_page.cpp b/support/webpage/web_page.cpp index 923235d0..19e80741 100644 --- a/support/webpage/web_page.cpp +++ b/support/webpage/web_page.cpp @@ -21,7 +21,7 @@ void litebrowser::text_file::on_page_downloaded(u_int32_t http_status, wait_mutex.unlock(); } -void litebrowser::web_page::open(const std::string &url, const std::string &hash) +void litebrowser::web_page::open(const std::string &url, const std::string &fragment) { litehtml::url l_url(url); @@ -39,7 +39,7 @@ void litebrowser::web_page::open(const std::string &url, const std::string &hash m_url = url; } m_base_url = m_url; - m_hash = hash; + m_fragment = fragment; auto data = std::make_shared(); auto cb_on_data = [data](auto && PH1, auto && PH2, auto && PH3, auto && PH4) mutable { data->on_data(std::forward(PH1), std::forward(PH2), std::forward(PH3), std::forward(PH4)); }; @@ -110,15 +110,15 @@ cairo_surface_t* litebrowser::web_page::get_image(const std::string& url) return m_images.get_image(url); } -void litebrowser::web_page::show_hash(const litehtml::string& hash) +void litebrowser::web_page::show_fragment(const litehtml::string& fragment) { std::lock_guard html_lock(m_html_mutex); - if(hash.empty() || !m_html) + if(fragment.empty() || !m_html) { m_html_host->scroll_to(0, 0); } else { - auto escaped_hash = litehtml::get_escaped_string(hash); + auto escaped_hash = litehtml::get_escaped_string(fragment); std::string selector = ":is([id=\"" + escaped_hash + "\"],[name=\"" + escaped_hash + "\"])"; litehtml::element::ptr el = m_html->root()->select_one(selector); if (el) diff --git a/support/webpage/web_page.h b/support/webpage/web_page.h index 9a3dca5f..6080b416 100644 --- a/support/webpage/web_page.h +++ b/support/webpage/web_page.h @@ -68,7 +68,7 @@ namespace litebrowser std::recursive_mutex m_html_mutex; litehtml::string m_cursor; litehtml::string m_clicked_url; - std::string m_hash; + std::string m_fragment; html_host_interface* m_html_host; cairo_images_cache m_images; litebrowser::http_requests_pool m_requests_pool; @@ -89,7 +89,7 @@ namespace litebrowser [[nodiscard]] const std::string& get_html_source() const { return m_html_source; } - void open(const litehtml::string& url, const litehtml::string& hash); + void open(const litehtml::string& url, const litehtml::string& fragment); void get_viewport(litehtml::position& viewport) const override; void on_anchor_click(const char* url, const litehtml::element::ptr& el) override; @@ -105,13 +105,13 @@ namespace litebrowser int get_screen_width() const override; int get_screen_height() const override; - void show_hash(const litehtml::string& hash); - void show_hash_and_reset() + void show_fragment(const litehtml::string& fragment); + void show_fragment_and_reset() { - if(!m_hash.empty() && m_html) + if(!m_fragment.empty() && m_html) { - show_hash(m_hash); - m_hash = ""; + show_fragment(m_fragment); + m_fragment = ""; } } From 4409f2687dcd56364f891c40a5f6e5ee0fbad579 Mon Sep 17 00:00:00 2001 From: Yuri Kobets Date: Wed, 4 Jun 2025 01:11:40 +0300 Subject: [PATCH 3/6] refactor: replace std::bind with lambda in litebrowser::web_page --- support/webpage/web_page.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/support/webpage/web_page.cpp b/support/webpage/web_page.cpp index 19e80741..fdbb7806 100644 --- a/support/webpage/web_page.cpp +++ b/support/webpage/web_page.cpp @@ -42,8 +42,12 @@ void litebrowser::web_page::open(const std::string &url, const std::string &frag m_fragment = fragment; auto data = std::make_shared(); - auto cb_on_data = [data](auto && PH1, auto && PH2, auto && PH3, auto && PH4) mutable { data->on_data(std::forward(PH1), std::forward(PH2), std::forward(PH3), std::forward(PH4)); }; - auto cb_on_finish = std::bind(&web_page::on_page_downloaded, shared_from_this(), data, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); + auto cb_on_data = [data](void* in_data, size_t len, size_t /*downloaded*/, size_t /*total*/) { data->on_data(in_data, len, 0, 0); }; + auto shared_this = shared_from_this(); + auto cb_on_finish = [shared_this, data](u_int32_t http_status, u_int32_t err_code, const std::string &err_text, const std::string& url) + { + shared_this->on_page_downloaded(data, http_status, err_code, err_text, url); + }; http_request(m_url, cb_on_data, cb_on_finish); } @@ -78,8 +82,11 @@ void litebrowser::web_page::import_css(litehtml::string& text, const litehtml::s make_url(url.c_str(), baseurl.c_str(), css_url); auto data = std::make_shared(); - auto cb_on_data = std::bind(&text_file::on_data, data, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); - auto cb_on_finish = std::bind(&text_file::on_page_downloaded, data, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + auto cb_on_data = [data](void* in_data, size_t len, size_t /*downloaded*/, size_t /*total*/) { data->on_data(in_data, len, 0, 0); }; + auto cb_on_finish = [data](u_int32_t http_status, u_int32_t err_code, const std::string &err_text, const std::string& /*url*/) + { + data->on_page_downloaded(http_status, err_code, err_text); + }; http_request(css_url, cb_on_data, cb_on_finish); data->wait(); text = data->str(); @@ -256,8 +263,13 @@ void litebrowser::web_page::load_image(const char *src, const char *baseurl, boo if(m_images.reserve(url)) { auto data = std::make_shared(url, redraw_on_ready); - auto cb_on_data = std::bind(&image_file::on_data, data, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); - auto cb_on_finish = std::bind(&web_page::on_image_downloaded, this, data, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); + auto cb_on_data = [data](void* in_data, size_t len, size_t /*downloaded*/, size_t /*total*/) { data->on_data(in_data, len, 0, 0); }; + auto shared_this = shared_from_this(); + auto cb_on_finish = [shared_this, data](u_int32_t http_status, u_int32_t err_code, const std::string &err_text, const std::string& url) + { + shared_this->on_image_downloaded(data, http_status, err_code, err_text, url); + }; + http_request(url, cb_on_data, cb_on_finish); } } From 6795b43e8f24b6a697b0c642c0698e4b30800037 Mon Sep 17 00:00:00 2001 From: Yuri Kobets Date: Wed, 4 Jun 2025 02:25:48 +0300 Subject: [PATCH 4/6] refactor: removed web_page dependency from draw_buffer class --- support/gtkmm4/html_widget.cpp | 43 ++++++++++++++--------------- support/gtkmm4/html_widget.h | 10 +++++++ support/webpage/draw_buffer.cpp | 35 +++++++++++------------- support/webpage/draw_buffer.h | 48 ++++++++++++++++++--------------- 4 files changed, 74 insertions(+), 62 deletions(-) diff --git a/support/gtkmm4/html_widget.cpp b/support/gtkmm4/html_widget.cpp index 852e6d4c..d31d4fb8 100644 --- a/support/gtkmm4/html_widget.cpp +++ b/support/gtkmm4/html_widget.cpp @@ -203,7 +203,7 @@ void html_widget::scroll_to(int x, int y) void html_widget::on_redraw() { - m_draw_buffer.redraw(current_page()); + m_draw_buffer.redraw(get_draw_function(current_page())); queue_draw(); } @@ -416,16 +416,16 @@ void html_widget::size_allocate_vfunc(int width, int height, int /* baseline */) { m_rendered_width = width; m_rendered_height = height; - m_draw_buffer.on_size_allocate(page, width, height); + m_draw_buffer.on_size_allocate(get_draw_function(page), width, height); page->media_changed(); page->render(m_rendered_width); update_view_port(page); - m_draw_buffer.redraw(page); + m_draw_buffer.redraw(get_draw_function(page)); queue_draw(); } } else { - m_draw_buffer.on_size_allocate(page, width, height); + m_draw_buffer.on_size_allocate(get_draw_function(page), width, height); } } @@ -459,9 +459,11 @@ void html_widget::allocate_scrollbars(int width, int height) void html_widget::on_vadjustment_changed() { - m_draw_buffer.on_scroll( current_page(), - (int) m_hadjustment->get_value(), - (int) m_vadjustment->get_value()); + auto page = current_page(); + m_draw_buffer.on_scroll(get_draw_function(page), + (int) m_hadjustment->get_value(), + (int) m_vadjustment->get_value(), + page ? page->get_fixed_boxes() : litehtml::position::vector{}); if(m_do_force_redraw_on_adjustment) { @@ -474,9 +476,12 @@ void html_widget::on_vadjustment_changed() void html_widget::on_hadjustment_changed() { - m_draw_buffer.on_scroll( current_page(), - (int) m_hadjustment->get_value(), - (int) m_vadjustment->get_value()); + auto page = current_page(); + m_draw_buffer.on_scroll(get_draw_function(page), + (int) m_hadjustment->get_value(), + (int) m_vadjustment->get_value(), + page ? page->get_fixed_boxes() : litehtml::position::vector{}); + if(m_do_force_redraw_on_adjustment) { force_redraw(); @@ -512,21 +517,17 @@ void html_widget::on_realize() { Gtk::Widget::on_realize(); - auto native = get_native(); - if(native) + if(auto native = get_native()) { - auto surface = native->get_surface(); - if(surface) + if(auto surface = native->get_surface()) { surface->property_scale().signal_changed().connect([this]() { - auto native = get_native(); - if(native) + if(auto native = get_native()) { - auto surface = native->get_surface(); - if(surface) + if(auto surface = native->get_surface()) { - m_draw_buffer.set_scale_factor(current_page(), surface->get_scale()); + m_draw_buffer.set_scale_factor(get_draw_function(current_page()), surface->get_scale()); queue_draw(); } } @@ -592,7 +593,7 @@ void html_widget::redraw_boxes(const litehtml::position::vector& boxes) if(!rect.has_zero_area()) { - m_draw_buffer.redraw_area(current_page(), rect.get_x(), rect.get_y(), rect.get_width(), rect.get_height()); + m_draw_buffer.redraw_area(get_draw_function(current_page()), rect.get_x(), rect.get_y(), rect.get_width(), rect.get_height()); queue_draw(); } } @@ -686,7 +687,7 @@ void html_widget::render() { page->render(m_draw_buffer.get_width()); update_view_port(page); - m_draw_buffer.redraw(page); + m_draw_buffer.redraw(get_draw_function(page)); queue_draw(); } } diff --git a/support/gtkmm4/html_widget.h b/support/gtkmm4/html_widget.h index 042834e4..0fe1b14a 100644 --- a/support/gtkmm4/html_widget.h +++ b/support/gtkmm4/html_widget.h @@ -287,6 +287,16 @@ class html_widget : public Gtk::Widget, queue_draw(); while (g_main_context_iteration(nullptr, false)) {} } + litebrowser::draw_buffer::draw_page_function_t get_draw_function(const std::shared_ptr& page) + { + return [this, page](cairo_t* cr, int x, int y, const litehtml::position* clip) + { + if (page) + { + page->draw((litehtml::uint_ptr) cr, x, y, clip); + } + }; + } public: // Signals types diff --git a/support/webpage/draw_buffer.cpp b/support/webpage/draw_buffer.cpp index fd09828e..bb9266f4 100644 --- a/support/webpage/draw_buffer.cpp +++ b/support/webpage/draw_buffer.cpp @@ -6,10 +6,11 @@ /// Note, the actual position of the draw buffer can be rounded according to the scale factor. /// Use get_left() and get_top() to know the actual position. /// -/// @param page webpage to be redraw if the position was changed +/// @param cb_draw the callback for drawing the page /// @param left new horizontal position /// @param top new vertical position -void litebrowser::draw_buffer::on_scroll(std::shared_ptr page, int left, int top) +/// @param fixed_boxes fixed boxes to be redrawn +void litebrowser::draw_buffer::on_scroll(const draw_page_function_t& cb_draw, int left, int top, const litehtml::position::vector& fixed_boxes) { if(m_width <= 0 || m_height <= 0 || !m_draw_buffer) return; @@ -26,7 +27,7 @@ void litebrowser::draw_buffer::on_scroll(std::shared_ptr { m_left = left; m_top = top; - redraw(page); + redraw(cb_draw); } else { int shift_x = m_left - left; @@ -58,43 +59,42 @@ void litebrowser::draw_buffer::on_scroll(std::shared_ptr if(rec_clean.x > m_left) { - redraw_area(page, m_left, rec_clean.y, rec_clean.x - m_left, rec_clean.height); + redraw_area(cb_draw, m_left, rec_clean.y, rec_clean.x - m_left, rec_clean.height); } if(clean_right < right) { - redraw_area(page, clean_right, rec_clean.y, right - clean_right, rec_clean.height); + redraw_area(cb_draw, clean_right, rec_clean.y, right - clean_right, rec_clean.height); } if(rec_clean.y > m_top) { - redraw_area(page, m_left, m_top, m_width, rec_clean.y - m_top); + redraw_area(cb_draw, m_left, m_top, m_width, rec_clean.y - m_top); } if(clean_bottom < bottom) { - redraw_area(page, m_left, clean_bottom, m_width, bottom - clean_bottom); + redraw_area(cb_draw, m_left, clean_bottom, m_width, bottom - clean_bottom); } - litehtml::position::vector fixed_boxes = page->get_fixed_boxes(); + for(const auto& box : fixed_boxes) { - redraw_area(page, m_left + box.left(), m_top + box.top(), box.width, box.height); - redraw_area(page, m_left + box.left() + shift_x, m_top + box.top() + shift_y, box.width, box.height); + redraw_area(cb_draw, m_left + box.left(), m_top + box.top(), box.width, box.height); + redraw_area(cb_draw, m_left + box.left() + shift_x, m_top + box.top() + shift_y, box.width, box.height); } } } } -/// @brief Reraw the defined area of the buffer +/// @brief Redraw the defined area of the buffer /// -/// All coordinated are not scaled. Actual rectangle could be different according to the scale factor, +/// All coordinated are not scaled. The actual rectangle could be different, according to the scale factor, /// but it must always cover the requested. /// -/// @param page webpage to be redraw +/// @param cb_draw the callback for drawing the page /// @param x left position of the area /// @param y top position of the area /// @param width width of the area /// @param height height of the area -void litebrowser::draw_buffer::redraw_area(std::shared_ptr page, int x, int y, int width, - int height) +void litebrowser::draw_buffer::redraw_area(const draw_page_function_t& cb_draw, int x, int y, int width, int height) { if(m_draw_buffer) { @@ -134,10 +134,7 @@ void litebrowser::draw_buffer::redraw_area(std::shared_ptrdraw((litehtml::uint_ptr) cr, -m_left, -m_top, &pos); - } + cb_draw(cr, -m_left, -m_top, &pos); cairo_destroy(cr); } diff --git a/support/webpage/draw_buffer.h b/support/webpage/draw_buffer.h index be3b72a5..dbd5d35f 100644 --- a/support/webpage/draw_buffer.h +++ b/support/webpage/draw_buffer.h @@ -2,16 +2,18 @@ #define LITEBROWSER_DRAW_BUFFER_H #include +#include +#include #include -#include "web_page.h" +#include "litehtml/types.h" namespace litebrowser { /// @brief Draw Buffer Class /// /// This class performs the draw operations into the cairo surface. - /// The application draws everything to the buffer, then buffer are - /// drawn on widged or window. + /// The application draws everything to the buffer, then buffer is + /// drawn on widget or window. class draw_buffer { cairo_surface_t* m_draw_buffer = nullptr; @@ -23,6 +25,8 @@ namespace litebrowser int m_min_int_position = 1; public: + using draw_page_function_t = std::function; + ~draw_buffer() { if(m_draw_buffer) @@ -50,9 +54,9 @@ namespace litebrowser double get_scale_factor() const { return m_scale_factor; } /// @brief Set scale factor for draw buffer - /// @param page the webpage to be redraw if required + /// @param cb_draw the callback for drawing the page /// @param scale the scale factor to be applied - void set_scale_factor(std::shared_ptr page, double scale) + void set_scale_factor(const draw_page_function_t& cb_draw, double scale) { if(m_scale_factor != scale) { @@ -68,7 +72,7 @@ namespace litebrowser } m_draw_buffer = nullptr; create_draw_buffer(m_width, m_height); - redraw(page); + redraw(cb_draw); } } @@ -76,8 +80,8 @@ namespace litebrowser /// @param width surface width (not scaled) /// @param height surface height (not scaled) /// @param scale_factor scale factor - /// @return poiter to the cairo surface - cairo_surface_t* make_surface(int width, int height, double scale_factor) + /// @return pointer to the cairo surface + static cairo_surface_t* make_surface(int width, int height, double scale_factor) { return cairo_image_surface_create(CAIRO_FORMAT_RGB24, std::ceil((double) width * scale_factor), @@ -109,14 +113,14 @@ namespace litebrowser } /// @brief Call this function when widget size changed - /// @param page webpage to be redraw if buffer size changed + /// @param cb_draw the callback for drawing the page /// @param width new draw buffer width /// @param height new draw buffer height - void on_size_allocate(std::shared_ptr page, int width, int height) + void on_size_allocate(const draw_page_function_t& cb_draw, int width, int height) { if(create_draw_buffer(width, height)) { - redraw(page); + redraw(cb_draw); } } @@ -125,32 +129,33 @@ namespace litebrowser /// Note, the actual position of the draw buffer can be rounded according to the scale factor. /// Use get_left() and get_top() to know the actual position. /// - /// @param page webpage to be redraw if the position was changed + /// @param cb_draw the callback for drawing the page /// @param left new horizontal position /// @param top new vertical position - void on_scroll(std::shared_ptr page, int left, int top); + /// @param fixed_boxes fixed boxes to be redrawn + void on_scroll(const draw_page_function_t& cb_draw, int left, int top, const litehtml::position::vector& fixed_boxes); - /// @brief Reraw the defined area of the buffer + /// @brief Redraw the defined area of the buffer /// - /// All coordinated are not scaled. Actual rectangle could be different according to the scale factor, + /// All coordinated are not scaled. The actual rectangle could be different, according to the scale factor, /// but it must always cover the requested. /// - /// @param page webpage to be redraw + /// @param cb_draw the callback for drawing the page /// @param x left position of the area /// @param y top position of the area /// @param width width of the area /// @param height height of the area - void redraw_area(std::shared_ptr page, int x, int y, int width, int height); + void redraw_area(const draw_page_function_t& cb_draw, int x, int y, int width, int height); /// @brief Redraw entire buffer - /// @param page webpage to be redraw - void redraw(std::shared_ptr page) + /// @param cb_draw the callback for drawing the page + void redraw(const draw_page_function_t& cb_draw) { - redraw_area(page, m_left, m_top, m_width, m_height); + redraw_area(cb_draw, m_left, m_top, m_width, m_height); } private: - inline int fix_position(int pos) + [[nodiscard]] int fix_position(int pos) const { return (pos / m_min_int_position) * m_min_int_position; } @@ -172,7 +177,6 @@ namespace litebrowser int denominator = 100; int common_divisor = get_common_divisor(numerator, denominator); - numerator /= common_divisor; return denominator / common_divisor; } }; From ccf1ca825eb23f15b30260028ecb26a41cfe8d08 Mon Sep 17 00:00:00 2001 From: Yuri Kobets Date: Wed, 4 Jun 2025 03:24:29 +0300 Subject: [PATCH 5/6] refactor: move draw_buffer sources into own directory --- support/{webpage => draw_buffer}/draw_buffer.cpp | 0 support/{webpage => draw_buffer}/draw_buffer.h | 0 support/gtkmm4/html_widget.h | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename support/{webpage => draw_buffer}/draw_buffer.cpp (100%) rename support/{webpage => draw_buffer}/draw_buffer.h (100%) diff --git a/support/webpage/draw_buffer.cpp b/support/draw_buffer/draw_buffer.cpp similarity index 100% rename from support/webpage/draw_buffer.cpp rename to support/draw_buffer/draw_buffer.cpp diff --git a/support/webpage/draw_buffer.h b/support/draw_buffer/draw_buffer.h similarity index 100% rename from support/webpage/draw_buffer.h rename to support/draw_buffer/draw_buffer.h diff --git a/support/gtkmm4/html_widget.h b/support/gtkmm4/html_widget.h index 0fe1b14a..f98064c8 100644 --- a/support/gtkmm4/html_widget.h +++ b/support/gtkmm4/html_widget.h @@ -4,7 +4,7 @@ #include "html_host.h" #include "web_page.h" #include "web_history.h" -#include "draw_buffer.h" +#include "../draw_buffer/draw_buffer.h" #include enum page_state From bd87c65ecf1a01dd67e05d3b427655a6a7853089 Mon Sep 17 00:00:00 2001 From: Yuri Kobets Date: Sat, 7 Jun 2025 00:57:38 +0300 Subject: [PATCH 6/6] added url::encode an url::decode functions --- include/litehtml/url.h | 3 ++ src/url.cpp | 108 ++++++++++++++++++++++++++++++----------- 2 files changed, 83 insertions(+), 28 deletions(-) diff --git a/include/litehtml/url.h b/include/litehtml/url.h index fae3db0a..d651b7c3 100644 --- a/include/litehtml/url.h +++ b/include/litehtml/url.h @@ -103,6 +103,9 @@ class url { return !fragment_.empty(); } + static string encode(const string& str); + static string decode(const string& str); + protected: string str_; diff --git a/src/url.cpp b/src/url.cpp index dbae382a..b1b0fba2 100644 --- a/src/url.cpp +++ b/src/url.cpp @@ -31,9 +31,9 @@ #include #include - #include "codepoint.h" #include "url_path.h" +#include namespace litehtml { @@ -94,35 +94,87 @@ url::url(const string& str) path_ = tmp; } -url::url(const string& scheme, - const string& authority, - const string& path, - const string& query, - const string& fragment) -: scheme_(scheme) -, authority_(authority) -, path_(path) -, query_(query) -, fragment_(fragment) +url::url(const string& scheme, const string& authority, const string& path, const string& query, + const string& fragment) : + scheme_(scheme), + authority_(authority), + path_(path), + query_(query), + fragment_(fragment) { - std::stringstream tss; + std::stringstream tss; + + if(!scheme_.empty()) + { + tss << scheme_ << ":"; + } + if(!authority_.empty()) + { + tss << "//" << authority_; + } + if(!path_.empty()) + { + tss << path_; + } + if(!query_.empty()) + { + tss << "?" << query_; + } + if(!fragment_.empty()) + { + tss << "#" << fragment_; + } + str_ = tss.str(); +} - if (!scheme_.empty()) { - tss << scheme_ << ":"; - } - if (!authority_.empty()) { - tss << "//" << authority_; - } - if (!path_.empty()) { - tss << path_; - } - if (!query_.empty()) { - tss << "?" << query_; - } - if (!fragment_.empty()) { - tss << "#" << fragment_; - } - str_ = tss.str(); +string url::encode(const string& str) +{ + std::ostringstream encoded; + encoded << std::hex << std::uppercase; + + for(unsigned char c : str) + { + if(isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') + { + encoded << c; + } else + { + encoded << '%' << std::setw(2) << int((unsigned char) c); + } + } + + return encoded.str(); +} + +string url::decode(const string& str) +{ + string decoded; + size_t i = 0; + + while(i < str.size()) + { + char c = str[i]; + if(c == '%') + { + if(i + 2 >= str.size()) + { + break; + } + + // Decode the percent-encoded character + char hex[3] = {str[i + 1], str[i + 2], '\0'}; + c = static_cast(std::strtol(hex, nullptr, 16)); + i += 2; // Skip the next two characters + } else if(c == '+') + { + // Replace '+' with space + c = ' '; + } + decoded += c; + i++; + } + + return decoded; } url resolve(const url& b, const url& r)