From 43eec85adca41352f2bbfe43ead5627d4fc27a89 Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Sun, 31 Jul 2022 23:14:16 +0300 Subject: [PATCH] add a way to pre-render svgs to fix duplication of surfaces --- meson.build | 4 +++- src/SvgUtil.cpp | 35 +++++++++++++++++++++++++++++++++++ src/SvgUtil.hpp | 10 ++++++++++ src/SvgWidget.cpp | 19 +++++++++++++++---- src/SvgWidget.hpp | 14 ++++++++++---- src/Widget.cpp | 1 + src/main.cpp | 20 +++++++++----------- 7 files changed, 83 insertions(+), 20 deletions(-) create mode 100644 src/SvgUtil.cpp create mode 100644 src/SvgUtil.hpp diff --git a/meson.build b/meson.build index 8737629..44cecaa 100644 --- a/meson.build +++ b/meson.build @@ -5,7 +5,7 @@ project( ) project_description = 'The Raven user interface library' -add_project_arguments('-g3', language : 'cpp') +add_project_arguments('-O3', language : 'cpp') cairomm_dep = dependency('cairomm-1.0') pangocairo_dep = dependency('pangocairo') @@ -22,6 +22,7 @@ raven_dependencies = [ headers = include_directories('src') raven_source_files = [ + './src/SvgUtil.cpp', './src/Box.cpp', './src/Styles.cpp', './src/Painter.cpp', @@ -38,6 +39,7 @@ raven_source_files = [ ] raven_header_files = [ + './src/SvgUtil.hpp', './src/Logging.hpp', './src/Box.hpp', './src/BoxLayout.hpp', diff --git a/src/SvgUtil.cpp b/src/SvgUtil.cpp new file mode 100644 index 0000000..c6642bd --- /dev/null +++ b/src/SvgUtil.cpp @@ -0,0 +1,35 @@ +#include "SvgUtil.hpp" +#include "librsvg/rsvg.h" +#include +#include "cairomm/context.h" + +namespace Raven { + +Cairo::RefPtr render_svg(std::string path, double x, double y, double width, double height) { + auto file = g_file_new_for_path(path.c_str()); + auto handle = rsvg_handle_new_from_gfile_sync(file, RSVG_HANDLE_FLAGS_NONE, NULL, NULL); + + if (!handle) { + std::cerr << "could not load svg file: " << path << std::endl; + exit(EXIT_FAILURE); + } + + RsvgRectangle viewport = { + .x = x, + .y = y, + .width = width, + .height = height, + }; + + auto surface = Cairo::ImageSurface::create(Cairo::Format::FORMAT_ARGB32, width, height); + auto context = Cairo::Context::create(surface); + + rsvg_handle_render_document(handle, context->cobj(), &viewport, NULL); + + g_object_unref(file); + g_object_unref(handle); + + return surface; +} + +} diff --git a/src/SvgUtil.hpp b/src/SvgUtil.hpp new file mode 100644 index 0000000..acbdf65 --- /dev/null +++ b/src/SvgUtil.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "cairomm/refptr.h" +#include "cairomm/surface.h" + +namespace Raven { + +Cairo::RefPtr render_svg(std::string path, double x, double y, double width, double height); + +} diff --git a/src/SvgWidget.cpp b/src/SvgWidget.cpp index 982fcc0..59aee97 100644 --- a/src/SvgWidget.cpp +++ b/src/SvgWidget.cpp @@ -6,11 +6,16 @@ namespace Raven { void SvgWidget::on_init() { + set_style(&clear_widget_style); + + if (m_user_defined_surface) { + set_did_init(true); + return; + } + m_file = g_file_new_for_path(m_path.c_str()); m_handle = rsvg_handle_new_from_gfile_sync(m_file, RSVG_HANDLE_FLAGS_NONE, NULL, NULL); - set_style(&clear_widget_style); - if (!m_handle) { std::cerr << "could not load svg file: " << m_path << std::endl; exit(EXIT_FAILURE); @@ -20,6 +25,10 @@ void SvgWidget::on_init() { } void SvgWidget::on_after_layout() { + if (m_user_defined_surface) { + return; + } + auto width = rect().width(); auto height = rect().height(); @@ -52,8 +61,10 @@ void SvgWidget::on_paint() { } SvgWidget::~SvgWidget() { - g_object_unref(m_file); - g_object_unref(m_handle); + if (m_file) + g_object_unref(m_file); + if (m_handle) + g_object_unref(m_handle); } } diff --git a/src/SvgWidget.hpp b/src/SvgWidget.hpp index 7675fd3..38a8a3d 100644 --- a/src/SvgWidget.hpp +++ b/src/SvgWidget.hpp @@ -16,6 +16,11 @@ public: : Raven::Widget() , m_path(path) {} + SvgWidget(Cairo::RefPtr image_surface) + : Raven::Widget() + , m_image_surface(image_surface) + , m_user_defined_surface(true) {} + ~SvgWidget(); std::string &path() { return m_path; } @@ -26,12 +31,13 @@ protected: void on_paint(); private: std::string m_path; - RsvgHandle *m_handle; - GFile *m_file; - Cairo::RefPtr m_image_context; - Cairo::RefPtr m_image_surface; + RsvgHandle *m_handle { nullptr }; + GFile *m_file { nullptr }; + Cairo::RefPtr m_image_context { nullptr }; + Cairo::RefPtr m_image_surface { nullptr }; double m_known_width { 0.0 }; double m_known_height { 0.0 }; + bool m_user_defined_surface { false }; }; } diff --git a/src/Widget.cpp b/src/Widget.cpp index da97e8c..d0fdc35 100644 --- a/src/Widget.cpp +++ b/src/Widget.cpp @@ -115,6 +115,7 @@ void Widget::remove_child(std::shared_ptr child) { void Widget::clear_children() { m_children.clear(); + m_children.shrink_to_fit(); reflow(); } diff --git a/src/main.cpp b/src/main.cpp index 273e3de..ecc3c46 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,24 +29,22 @@ int main() { top_bar->set_layout(Raven::Direction::Horizontal); auto container_widget = main_widget->add(); - auto container_layout = container_widget->set_layout(Raven::Direction::Vertical); - container_layout->set_spacing(5); - container_layout->set_margin(18); - container_widget->resize(400, 400); + container_widget->set_layout(); auto new_button = top_bar->add("add"); new_button->rect().set_max_width(50); - new_button->on_click = [container_widget]() { - container_widget->add("hello"); + new_button->on_click = [&window, container_widget]() { + window.queue_microtask([container_widget]() { + for (int i = 0; i < 5000; i++) { + container_widget->add("hello"); + } + }); }; + auto remove_button = top_bar->add("remove"); remove_button->on_click = [container_widget]() { - if (container_widget->children().size() > 0) { - container_widget->remove_child(container_widget->children()[0]); - } + container_widget->clear_children(); }; - auto dummy_button = top_bar->add("dummy"); - dummy_button->rect().set_max_width(60); window.run(true); return 0;